Bring Elixir/Phoenix server-side performance metrics 📈 to Chrome's Developer Tools via the Server Timing API. Production Safe™.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
config
lib
test
.formatter.exs
.gitignore
CHANGELOG.md
LICENSE
README.md
mix.exs
mix.lock

README.md

Server Timing Response Headers for Elixir / Phoenix

Bring Phoenix server-side performance metrics 📈 to Chrome's Developer Tools (and other browsers that support the Server Timing API) via the plug_server_timing package. Production Safe™.

Metrics are collected from the scout_apm package. A Scout account is not required.

image

Browser Support

  • Chrome 65+ (Chrome 64 uses an old format of the server timing headers. This isn't supported by the gem).
  • Firefox 59+
  • Opera 52+

Installation

To install and use PlugServerTiming, add it as a dependency in your Mixfile:

# mix.exs
  def deps do
    [
      # ...
+     {:plug_server_timing, "~> 0.0.2"}
    ]
  end

Add PlugServerTiming.Plug to your Plug pipeline:

# lib/my_app_web/router.ex
defmodule MyAppWeb.Router do
  pipeline :browser do
    # ...
+   plug PlugServerTiming.Plug
  end
end

Whoa! We're not done yet ... we need to instrument our app's function calls.

Instrumentation

Performance metrics are collected via the scout_apm gem. There's just a couple of steps to instrument your app.

Instrument controllers:

# lib/my_app_web.ex
defmodule MyAppWeb do
  # ...
  def controller do
    quote do
      use Phoenix.Controller, namespace: MyAppWeb
+     use ScoutApm.Instrumentation
      # ...
    end
  end
end

Instrument Ecto queries:

# config/dev.exs
+config :my_app, MyApp.Repo,
+ loggers: [{Ecto.LogEntry, :log, []}, {ScoutApm.Instruments.EctoLogger, :log, []}]

Instrument templates:

# config/dev.exs
+config :phoenix, :template_engines,
+ eex: ScoutApm.Instruments.EExEngine,
+ exs: ScoutApm.Instruments.ExsEngine

Additional instrumentation

To instrument HTTPoison, MongoDB Ecto, and more see the Scout docs.

Custom instrumentation

Collect performance data on additional function calls by adding custom instrumentation via scout_apm. See the docs for instructions.

Security

If you'd like to conditionally include Server-Timing headers depending on authorization, the Plug can be included in a Plug.Builder pipeline or you can directly use PlugServerTiming.Plug.register_before_send_headers/1 in an existing Plug.

defmodule MyExistingAuthPlug do
  @behaviour Plug
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    case AuthModule.verify_auth(conn) do
      {:ok, :admin} ->
        PlugServerTiming.Plug.register_before_send_headers(conn)
      {:ok, :user} ->
        conn
      {:error, _} ->
        conn
        |> put_status(:unauthorized)
        |> halt()
    end
  end
end

Overhead

The scout_apm package, a dependency of plug_server_timing, applies low overhead instrumentation designed for production use.

Thanks!

Special thank you goes to @OleMchls for writing up https://blog.dnsimple.com/2018/02/server-timing-with-phoenix/ and inspiring this package 💖

Documentation on HexDocs.