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](https://w3c.github.io/server-timing/)) via the `plug_server_timing` package. Production Safe™.

Metrics are collected from the [scout_apm](https://github.com/scoutapp/scout_apm_elixir) package. A [Scout](https://scoutapp.com) account is not required.

![image](https://s3-us-west-1.amazonaws.com/scout-blog/elixir_server_timing.png)

## Browser Support

- Chrome 65+ (Chrome 64 uses an [old format](https://github.com/scoutapp/ruby_server_timing/issues/5#issuecomment-370504687) 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:

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

Add `PlugServerTiming.Plug` to your Plug pipeline: 

```diff
# 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, which requires a couple of steps to instrument your app.

__Instrument controllers:__

```diff
# 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:__

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

__Instrument templates:__

```diff
# 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](http://help.apm.scoutapp.com/#instrumenting-common-libraries).

### Custom instrumentation

Collect performance data on additional function calls by adding custom instrumentation via `scout_apm`. [See the docs for instructions](http://help.apm.scoutapp.com/#elixir-custom-instrumentation).

## 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`.

```elixir

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](https://github.com/OleMchls) for writing up https://blog.dnsimple.com/2018/02/server-timing-with-phoenix/ and inspiring this package 💖

[Documentation on HexDocs](https://hexdocs.pm/plug_server_timing).