Исходный код Отладка
Существует несколько способов отладки кода на 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, если вы хотите выполнить код и установить точки останова во время отладки.
Точки останова
При использовании IEx, вы можете передать --dbg pry в качестве опции, чтобы «остановить» выполнение кода там, где вызов dbg:
$ iex --dbg pry
Теперь вызов dbg спросит, хотите ли вы применить отладчик к существующему коду. Если вы согласитесь, вы сможете получить доступ ко всем переменным, а также импортам и псевдонимам из кода непосредственно из IEx. Это называется «применение отладчика». Пока сессия отладки активна, выполнение кода останавливается, пока не будут вызваны continue или next. Помните, что вы всегда можете запустить iex в контексте проекта с iex -S mix TASK.
dbg вызовы требуют от нас изменения кода, который мы намерены отлаживать, и имеют ограниченные возможности пошаговому выполнению. К счастью, IEx также предоставляет функцию IEx.break!/2, которая позволяет устанавливать и управлять точками останова в любом коде Elixir без изменения исходного кода:
Аналогично dbg, после достижения точки останова выполнение кода приостанавливается до тех пор, пока не будут вызваны continue или next. Однако, break!/2 не имеет доступа к псевдонимам и импортам из отлаживаемого кода, поскольку работает с скомпилированным артефактом, а не с исходным кодом.
Наблюдатель
Для отладки сложных систем простого «шаговового» выполнения кода недостаточно. Необходимо понимать всю виртуальную машину, процессы, приложения, а также настроить механизмы отслеживания. К счастью, это можно сделать в Erlang с помощью :observer. В вашем приложении:
$ iex iex> :observer.start()
Недостающие зависимости
При запуске
iexвнутри проекта сiex -S mix,observerне будет доступен как зависимость. Для этого вам нужно будет вызвать следующие функции перед запуском:iex> Mix.ensure_application!(:wx) iex> Mix.ensure_application!(:runtime_tools) iex> Mix.ensure_application!(:observer) iex> :observer.start()Если какой-либо из вышеуказанных вызовов завершится ошибкой, возможно, произошло следующее: некоторые менеджеры пакетов по умолчанию устанавливают миниатюрный Erlang без привязок WX для поддержки графического интерфейса. В некоторых менеджерах пакетов вы можете заменить Erlang без графического интерфейса более полной версией (ищите пакеты под названием
erlangвместоerlang-noxв Debian/Ubuntu/Arch). В других менеджерах вам может потребоваться установить отдельный пакетerlang-wx(или с похожим названием).В будущих выпусках ведутся дискуссии об улучшении этого опыта.
Вышеуказанное откроет другой графический интерфейс, который предоставляет множество панелей для полного понимания и навигации по среде выполнения и вашему проекту.
Мы исследуем Наблюдателя в контексте реального проекта в главе «Динамический Supervisor» руководства по Mix & OTP. Это одна из техник отладки, которую использовал фреймворк Phoenix для достижения 2 миллионов подключений по протоколу WebSocket на одном компьютере .
Если вы используете фреймворк Phoenix, он поставляется с Phoenix LiveDashboard — веб-панелью для узлов в производстве, предоставляющей функции, аналогичные Наблюдателю.
Наконец, помните, что вы также можете получить краткий обзор информации о среде выполнения, вызвав runtime_info/0 непосредственно в IEx.
Другие инструменты и сообщество
Мы лишь слегка коснулись того, что предлагает виртуальная машина Erlang, например:
Наряду с приложением наблюдателя, Erlang также включает
:crashdump_viewerдля просмотра дампов памяти.Интеграция с системными отслеживателями, такими как Linux Trace Toolkit, DTRACE, и SystemTap
Подсчёт микросостояний измеряет, сколько времени среда выполнения тратит на различные низкоуровневые задачи за короткий промежуток времени.
Mix поставляется со многими задачами в пространстве имён
profile, таких какcprofиfprof.Для более сложных случаев использования мы рекомендуем превосходную книгу Erlang in Anger, которая доступна в виде бесплатной электронной книги.
Удачной отладки!
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/debugging.html