ExDebugToolbar v0.3.5 ExDebugToolbar View Source

A toolbar for Phoenix projects to display all sorts of information about current and previous requests: logs, timelines, database queries etc.

Project is in its early stages and under active development. Contributions to code, feedback and suggestions will be much appreciated!

Features

Toolbar is built with development environment in mind. It’s up to you to enable or disable it in configuration. Calls to toolbar functions such as Toolbar.pry are no-op when it is disabled.

After enabling the toolbar, it automatically injects itself at the bottom of html pages. Some panels on the toolbar are optional and only appear when relevant data is available (ecto queries, for example).

Let’s take a look at available panels:

Timings

It shows overall time spent rendering current controller as reported by Phoenix instrumentation. In addition, it provides aggregated stats for each template.

Connection details

Surfaces information from conn struct of current request.

Logs

Log entries relevant to current request only

Ecto queries

A list of executed ecto queries including parallel preloads when possible.

Breakpoints

Think of having multiply IEx.pry breakpoints available on demand right from the toolbar. Note, unlike IEx.pry, this does not interfere with execution flow of phoenix server.

Usage is similar to IEx. Drop require ExDebugToolbar; ExDebugToolbar.pry in a file you’d like to debug and breakpoint will appear in this panel. Breakpoints are not limited to current request, but are capped at configurable number (100 by default).

A click on any breakpoint will take you to familiar iex session with context as it was at execution time.

Installation

  1. Add ex_debug_toolbar to your list of dependencies in mix.exs:

    def deps do
      [{:ex_debug_toolbar, "~> 0.2.0"}]
    end
  2. Ensure :ex_debug_toolbar is started before your application:

   def application do
     [applications: [:ex_debug_toolbar, :logger]]
   end
  1. Add ExDebugToolbar.Phoenix to your endpoint in lib/my_app/endpoint.ex
    defmodule MyApp.Endpoint do
      use Phoenix.Endpoint, otp_app: :my_app
      use ExDebugToolbar.Phoenix
      ...
    end
  1. Enable toolbar in config config/dev.exs and setup collectors. Replace :my_app and MyApp with your application name
    # ExDebugToolbar config
    config :ex_debug_toolbar,
      enable: true

    config :my_app, MyApp.Endpoint,
      instrumenters: [ExDebugToolbar.Collector.InstrumentationCollector]

    config :my_app, MyApp.Repo,
      loggers: [ExDebugToolbar.Collector.EctoCollector, Ecto.LogEntry]

    config :phoenix, :template_engines,
      eex: ExDebugToolbar.Template.EExEngine,
      exs: ExDebugToolbar.Template.ExsEngine
  1. To display parallel Ecto preloads you have to use master branch
    defp deps do
      [
       {:ecto, github: "elixir-ecto/ecto", branch: "master", override: true}
      ]
    end

Configuration

To change configuration, update :ex_debug_toolbar config key in your config/dev.exs. For example:

    config :ex_debug_toolbar,
      enable: true

Available options:

OptionValuesDefaultDescription
enablebooleanfalseEnable/disable toolbar. When disabled, toolbar code is not injected in page and toolbar functions are mostly no-op.
iex_shellstring“/bin/sh”Shell executable to be used for breakpoint session
iex_shell_cmdstring“”” stty echo; clear; iex —sname %{node_name} -S mix breakpoint.client %{breakpoint_id} “””Shell command to launch breakpoint iex session
breakpoints_limitinteger100Maximum number of available breakpoints. After reaching this cap, new breakpoints will push out oldest ones.
remove_glob_paramsbooleantruePlug.Router adds glob params to conn.params and conn.path_params on forward. This option removes them

Contributors

Special thanks goes to Juan Peri!

Contribution

Contributions in the form of bug reports, pull requests, or thoughtful discussions in the GitHub issue tracker are welcome!

TODO

  • [ ] Toolbar panels

    • [ ] Messages output panel (Toolbar.inspect and Toolbar.puts)
    • [ ] System info panel (versions, vm info, etc)
    • [ ] Help/Docs Panel (links to dev resources)
    • [ ] Request time panel

      • [ ] Request history (historical graphs?)
      • [ ] Visualize timeline
    • [ ] Ajax requests panel
    • [ ] Channels info panel
    • [ ] Visualize gettext
  • [ ] Toolbar API

    • [ ] Decorator for functions to time them
    • [ ] Add metadata to events and use groupable names (template.render, controller.render etc)
  • [ ] Documentation

    • [ ] Add function specs
    • [ ] Document top level API, hide internal modules from docs
  • [ ] Support multiple breakpoint servers on one host
  • [ ] Tests

    • [ ] breakpoints

      • [ ] client test
      • [ ] server test
      • [ ] terminal test
  • [ ] Hide debug logs/output behind debug: true config
  • [ ] Simple installer mix task
  • [ ] Upgrade to Phoenix 1.3
  • [ ] Elm/React instead of jquery?

Demo App

Use demo app to simplify development process.

Link to this section Summary

Functions

Adds data to request with id id

Adds timeline event name with provided duration without explicitly starting it

Deletes breakpoint by id

Deletes request from repository

Finishes event name in request with pid self()

Finishes event name for request with id id

Returns all available breakpoints

Returns all requests from repository

Returns breakpoint by its id

Returns request matching provided id, which defaults to self()

Adds a breakpoint that can be interacted with using Breakpoints Panel on toolbar

Creates a timeline event for provided function func execution

Starts a timeline event name in request identified by id, which defaults to self()

Creates a new request record with to provided uuid and current process pid

Stops request. Toolbar waits for request to stop before rendering

Link to this section Types

Link to this section Functions

Link to this function add_data(id \\ self(), key, data) View Source
add_data(id, atom, any) :: ok

Adds data to request with id id

Link to this function add_finished_event(id \\ self(), name, duration) View Source
add_finished_event(id, String.t, Integer.t) :: ok

Adds timeline event name with provided duration without explicitly starting it.

Link to this function delete_breakpoint(id) View Source
delete_breakpoint(breakpoint_id) :: ok

Deletes breakpoint by id

Link to this function delete_request(uuid) View Source
delete_request(uuid) :: ok

Deletes request from repository

Link to this function finish_event(name) View Source
finish_event(String.t) :: ok

Finishes event name in request with pid self()

See finish_event/3 for more details.

Link to this function finish_event(name, opts) View Source
Link to this function finish_event(id, name, opts) View Source
finish_event(id, String.t, options) :: ok

Finishes event name for request with id id

Event duration is calculated as a difference between call to start_event/2 and finish_event/3 with matching name and request id.

Available options:

  • :duration - overrides event duration, should be in :native time units
Link to this function get_all_breakpoints() View Source
get_all_breakpoints() :: [ExDebugToolbar.Breakpoint.t]

Returns all available breakpoints

Link to this function get_all_requests() View Source
get_all_requests() :: [ExDebugToolbar.Request.t]

Returns all requests from repository

Link to this function get_breakpoint(id) View Source
get_breakpoint(breakpoint_id) :: ExDebugToolbar.Breakpoint.t

Returns breakpoint by its id

Link to this function get_request(id \\ self()) View Source
get_request(id) :: ExDebugToolbar.Request.t

Returns request matching provided id, which defaults to self()

Link to this macro pry() View Source (macro)
pry(term) :: nil

Adds a breakpoint that can be interacted with using Breakpoints Panel on toolbar.

Link to this function record_event(id \\ self(), name, func) View Source
record_event(id, String.t, function) :: any

Creates a timeline event for provided function func execution.

Returns func return value.

Link to this function start_event(id \\ self(), name) View Source
start_event(id, String.t) :: ok

Starts a timeline event name in request identified by id, which defaults to self()

Link to this function start_request(uuid) View Source
start_request(uuid) :: ok

Creates a new request record with to provided uuid and current process pid.

Request is required to be present before adding new timeline events. By default request is started on :ex_debug_toolbar :start intrumentation event.

Link to this function stop_request(id) View Source
stop_request(id) :: ok

Stops request. Toolbar waits for request to stop before rendering.

By default request is stopped on :ex_debug_toolbar :stop instrumentation event.