Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Debugging techniques in Elixir - ElixirConf 2016

Erich Kist
September 01, 2016

Debugging techniques in Elixir - ElixirConf 2016

Show some results in the standard output is the first experience in how to debug your code. What is the next step? Probably, the first answer that you found was: start the observer. After some minutes with an awesome feeling, you asked yourself: What I should look here?
In this talk, you will meet some tools, learn how to debug and profile your system, check crash dump and how to find and deal with the most common cause of failure. More than that, you will understand the concepts behind the reports and the observer tool.

Erich Kist

September 01, 2016

More Decks by Erich Kist

Other Decks in Programming


  1. What I learned in my journey… • Tools used to

    debug applications. • When I can use each tool. • How I can analyze the system information. • How I connect to different nodes.
  2. iex(1)> IO.puts {:a, :b} ** (Protocol.UndefinedError) protocol String.Chars not implemented

    for {:a, :b} (elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1 (elixir) lib/string/chars.ex:17: String.Chars.to_string/ 1 (elixir) lib/io.ex:500: IO.puts/2
  3. 1..10 |> Enum.take_random(3) |> IO.inspect |> Enum.map(&(&1 * 2)) |>

    IO.inspect |> … |> IO.inspect |> … Awesome!!!
  4. 1..10 |> Enum.take_random(3) |> IO.inspect(label: “list") |> Enum.map(&(&1 * 2))

    |> IO.inspect(label: “after multiply") |> … |> IO.inspect(label: “after foo") |> … Label
  5. %Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<0.7834419/1 in Plug.CSRFProtection.call/2>, #Function<4.100417920/1

    in Phoenix.Controller.fetch_flash/2>, #Function<0.82590416/1 in Plug.Session.before_send/2>, #Function<1.75806487/1 in Plug.Logger.call/2>, #Function<0.96656268/1 in Phoenix.LiveReloader.before_send_inject_reloader/1>], body_params: %{}, cookies: %{}, halted: false, host: "localhost", method: "GET", owner: #PID<0.381.0>, params: %{}, path_info: [], peer: {{127, 0, 0, 1}, 63732}, port: 4000, private: %{Chat.Router => {[], %{}}, :phoenix_action => :index, :phoenix_controller => Chat.PageController, :phoenix_endpoint => Chat.Endpoint, :phoenix_flash => %{}, :phoenix_format => "html", :phoenix_layout => {Chat.LayoutView, :app}, :phoenix_pipelines => [:browser], :phoenix_route => #Function<1.12450572/1 in Chat.Router.match_route/4>, :phoenix_router => Chat.Router, :phoenix_view => Chat.PageView, :plug_session => %{}, :plug_session_fetch => :done}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{}, req_headers: [{"host", "localhost:4000"}, {"connection", "keep-alive"}, {"cache-control", "max-age=0"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"}, {"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate, sdch"}, Limit
  6. IO.inspect conn, limit: 5 %Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{}, before_send:

    [#Function<0.7834419/1 in Plug.CSRFProtection.call/2>, #Function<4.100417920/1 in Phoenix.Controller.fetch_flash/ 2>, ...], body_params: %{}, cookies: %{}, ...} Limit
  7. Things to keep in mind: 1) lexical scope (its bindings

    and process info) 2) after allowed the pry, shell will be reset 3) a new shell will be started after respawn
  8. defmodule Chat.RoomChannel do ... require IEx def handle_in("new:msg", msg, socket)

    do IEx.pry broadcast! socket, "new:msg", %{user: msg["user"], body: msg["body"]} {:reply, {:ok, %{msg: msg["body"]}}, assign(socket, :user, msg["user"])} end end web/channels/room_channel.ex
  9. Scheduler will run the process Process reduction count: 0 Scheduler

    reduction limit: 500 Scheduler fake values
  10. To avoid going to sleep when work is low, the

    threads that control the Erlang schedulers will do busy looping
  11. module :observer can be not available Releases are self contained

    packages without unnecessary applications
  12. ## Name of the node -sname my_app ## Cookie for

    distributed erlang -setcookie my_cookie running-config/vm.args
  13. Erlang Port Mapper Daemon daemon acts as a name server

    on all hosts involved in distributed Erlang computations
  14. $ epmd -names epmd: up and running on port 4369

    with data: name my_app at port 64722
  15. $ epmd -names epmd: up and running on port 4369

    with data: name observer at port 64749 name my_app at port 64722
  16. 09:27:51.872 [info] Child Logger.ErrorHandler of Supervisor Logger.Supervisor started Pid: #PID<0.78.0>

    Start Call: Logger.Watcher.watcher(:error_logger, Logger.ErrorHandler, {true, true, 500}, :link) Restart: :permanent Shutdown: 5000 Type: :worker 09:27:51.884 [info] Application logger started at :nonode@nohost 09:27:52.174 [info] Child Mix.State of Supervisor Mix.Supervisor started Pid: #PID<0.86.0> Start Call: Mix.State.start_link() Restart: :permanent Shutdown: 5000 Type: :worker