Spec-Zone.ru › Elixir 1.17

Исходный код Отладка

Существует множество способов отладки кода в Elixir. В этой главе мы рассмотрим некоторые из наиболее распространённых методов.

IO.inspect/2

То, что делает IO.inspect(item, opts \\ []) действительно полезным при отладке, заключается в том, что он возвращает item аргумент, переданный ему, не влияя на поведение исходного кода. Давайте посмотрим пример.

(1..10)
|> IO.inspect()
|> Enum.map(fn x -> x * 2 end)
|> IO.inspect()
|> Enum.sum()
|> IO.inspect()

Выводит:

1..10
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
110

Как вы видите, IO.inspect/2 позволяет «просматривать» значения практически в любом месте вашего кода без изменения результата, что очень полезно внутри конвейера, как в приведенном выше случае.

IO.inspect/2 также предоставляет возможность форматировать вывод с помощью label опции. Метка будет напечатана перед просматриваемым item:

[1, 2, 3]
|> IO.inspect(label: "before")
|> Enum.map(&(&1 * 2))
|> IO.inspect(label: "after")
|> Enum.sum

Выводит:

before: [1, 2, 3]
after: [2, 4, 6]

Также очень часто используется IO.inspect/2 с binding/0, который возвращает все имена переменных и их значения:

def some_fun(a, b, c) do
  IO.inspect binding()
  ...
end

Когда some_fun/3 вызывается с :foo, "bar", :baz, он выводит:

[a: :foo, b: "bar", c: :baz]

См. IO.inspect/2 и Inspect.Opts соответственно, чтобы узнать больше о функции и ознакомиться со всеми поддерживаемыми опциями.

dbg/2

Elixir v1.14 представил dbg/2. dbg похож на IO.inspect/2, но специально разработан для отладки. Он выводит значение, переданное ему, и возвращает его (как и IO.inspect/2), но также выводит код и местоположение.

# In my_file.exs
feature = %{name: :dbg, inspiration: "Rust"}
dbg(feature)
dbg(Map.put(feature, :in_version, "1.14.0"))

Приведенный выше код выводит это:

[my_file.exs:2: (file)]
feature #=> %{inspiration: "Rust", name: :dbg}
[my_file.exs:3: (file)]
Map.put(feature, :in_version, "1.14.0") #=> %{in_version: "1.14.0", inspiration: "Rust", name: :dbg}

Говоря о IO.inspect/2, мы упомянули его полезность, когда он расположен между шагами |> конвейеров. dbg делает это лучше: он понимает код Elixir, поэтому он будет выводить значения на каждом шаге конвейера.

# In dbg_pipes.exs
__ENV__.file
|> String.split("/", trim: true)
|> List.last()
|> File.exists?()
|> dbg()

Этот код выводит:

[dbg_pipes.exs:5: (file)]
__ENV__.file #=> "/home/myuser/dbg_pipes.exs"
|> String.split("/", trim: true) #=> ["home", "myuser", "dbg_pipes.exs"]
|> List.last() #=> "dbg_pipes.exs"
|> File.exists?() #=> true

Хотя dbg предоставляет удобства для работы со структурами Elixir, вам понадобится IEx, если вы хотите выполнить код и установить точки останова во время отладки.

Pry

При использовании IEx, вы можете передать --dbg pry в качестве опции, чтобы «остановить» выполнение кода там, где находится вызов dbg:

$ iex --dbg pry

Или для отладки внутри проекта:

$ iex --dbg pry -S mix

Теперь любой вызов dbg спросит, хотите ли вы запустить pry для существующего кода. Если вы согласитесь, вы сможете получить доступ ко всем переменным, а также импортам и псевдонимам из кода непосредственно из IEx. Это называется «prying». Пока сессия pry активна, выполнение кода останавливается, пока не будут вызваны continue (или c) или next (или n). Помните, что вы всегда можете запустить iex в контексте проекта с iex -S mix TASK.

Точки останова

dbg вызовы требуют изменения кода, который мы намерены отлаживать, и имеют ограниченную функциональность по шагам. К счастью, IEx также предоставляет функцию IEx.break!/2, которая позволяет устанавливать и управлять точками останова в любом коде Elixir без изменения его исходного кода:

Аналогично dbg, когда достигается точка останова, выполнение кода останавливается, пока не будут вызваны continue (или c) или next (или n). Точки останова могут перемещаться по строкам по умолчанию, однако у них нет доступа к псевдонимам и импортам, когда точки останова установлены на скомпилированных модулях.

Задача mix test имеет прямую интеграцию с точками останова через флаг -b/--breakpoints. При использовании флага устанавливается точка останова в начале каждого теста, который будет запущен:

Вот некоторые команды, которые вы можете использовать на практике:

# Debug all failed tests
$ iex -S mix test --breakpoints --failed
# Debug the test at the given file:line
$ iex -S mix test -b path/to/file:line

Наблюдатель

Для отладки сложных систем перепрыгивание по коду недостаточно. Необходимо понимать всю виртуальную машину, процессы, приложения, а также устанавливать механизмы отслеживания. К счастью, это можно сделать в Erlang с помощью :observer. В вашем приложении:

$ iex
iex> :observer.start()

Не хватает зависимостей

При запуске iex внутри проекта с iex -S mix, observer не будет доступен как зависимость. Для этого вам нужно вызвать следующие функции перед этим:

iex> Mix.ensure_application!(:wx)             # Not necessary on Erlang/OTP 27+
iex> Mix.ensure_application!(:runtime_tools)  # Not necessary on Erlang/OTP 27+
iex> Mix.ensure_application!(:observer)
iex> :observer.start()

Если любой из вышеуказанных вызовов завершится неудачно, вот что могло произойти: некоторые менеджеры пакетов по умолчанию устанавливают минимизированный Erlang без привязок WX для поддержки графического интерфейса. В некоторых менеджерах пакетов вы можете заменить беспиковый Erlang более полным пакетом (ищите пакеты под названием erlang против erlang-nox в Debian/Ubuntu/Arch). В других менеджерах вам может потребоваться установить отдельный пакет erlang-wx (или с аналогичным названием).

Это откроет другой графический интерфейс, который предоставляет множество панелей для полного понимания и навигации по времени выполнения и вашему проекту.

Мы изучаем Наблюдателя в контексте реального проекта в главе «Динамический супервайзор» руководства Mix & OTP. Это один из методов отладки, который использовал фреймворк Phoenix для достижения 2 миллионов подключений на одном компьютере на одном компьютере.

Если вы используете веб-фреймворк Phoenix, он поставляется с Phoenix LiveDashboard, веб-панель управления для узлов в производстве, который предоставляет функции, похожие на Наблюдатель.

Наконец, помните, что вы также можете получить краткий обзор информации о времени выполнения, вызвав runtime_info/0 непосредственно в IEx.

Другие инструменты и сообщество

Мы только коснулись того, что может предложить виртуальная машина Erlang, например:

  • Наряду с приложением наблюдателя, Erlang также включает :crashdump_viewer для просмотра дампов аварий

  • Интеграция с трассировщиками уровня ОС, такими как Linux Trace Toolkit, DTRACE, и SystemTap

  • Подсчёт микросостояний измеряет, сколько времени среда выполнения тратит на несколько задач низкого уровня в короткий промежуток времени

  • Mix поставляется со многими задачами в пространстве имён profile, таких как mix profile.cprof и mix profile.fprof

  • Для более сложных случаев использования мы рекомендуем отличный Erlang in Anger, который доступен в виде бесплатной электронной книги

Удачной отладки!

← Предыдущая страница Библиотеки Erlang
Следующая страница → Справочник по Enum

Скачать версию ePub

Разработано с использованием ExDoc (v0.34.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/debugging.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API