Current section

Files

Jump to
perf_agent lib perf_agent plug phoenix.ex
Raw

lib/perf_agent/plug/phoenix.ex

defmodule PerfAgent.Plug.Phoenix do
@moduledoc """
A plug that instruments Phoenix controllers and records their status and response times in Perf.
```
defmodule MyApp.UsersController do
use Phoenix.Controller
plug PerfAgent.Plug.Phoenix
def index(conn, _params) do
# `conn` is setup for instrumentation
end
end
```
"""
@behaviour Elixir.Plug
import Elixir.Plug.Conn
import Elixir.Phoenix.Controller
import Phoenix.Router.Helpers
def init(opts) do
opts
end
def call(conn, _config) do
if PerfAgent.configured? do
router = conn |> router_module
url = path(router, conn, conn.request_path)
transaction_name = url(router, conn) <> conn.request_path
normalized_path = project_param_keys_on_url(conn.request_path, conn.params)
conn
|> put_private(:perf_agent_transaction, PerfAgent.Transaction.start(transaction_name, conn.method, normalized_path))
|> register_before_send(fn conn ->
PerfAgent.Transaction.finish(Map.get(conn.private, :perf_agent_transaction), get_status(conn))
conn
end)
else
conn
end
end
# TODO: Find path from matching route path instead of projecting param keys back on url
defp project_param_keys_on_url(request_url, %Plug.Conn.Unfetched{}), do: request_url
defp project_param_keys_on_url(request_url, params) when map_size(params) > 0 do
request_url |> String.split("/") |> Enum.map(fn(component) ->
# If the params value exists in the url then project they key onto the url
case Enum.find(params, fn({_, value}) -> component == value end) do
nil -> component
{key, _} -> ":#{key}"
end
end)
|> Enum.join("/")
end
defp project_param_keys_on_url(request_url, _), do: request_url
defp get_status(conn) do
case conn.status do
nil -> 200
status -> status
end
end
end