Current section

Files

Jump to
ex_datadog_plug lib ex_datadog_plug.ex
Raw

lib/ex_datadog_plug.ex

defmodule ExDatadog.Plug do
@moduledoc """
A plug for logging response time in datadog. To use it, just plug it into the desired module.
plug ExDatadog.Plug, prefix: "your-service", method: true, query: []
## Options
* `:prefix` - the prefix you want to put for this stat.
Default is `plug`.
* `:method` - a boolean value to include the method in the tag list.
Default is `false`.
* `:path` - a boolean value to include the path in the tag list.
Default is `false`.
* `:query` - a list of strings to include specific query string in the tag list. `[]` will generate all query
params as tags.
Default is `nil` (do not generate tag for query string)
"""
alias Plug.Conn
@behaviour Plug
def init(opts) do
opts
end
def call(conn, opts) do
prefix = Keyword.get(opts, :prefix, "plug")
start = System.monotonic_time()
Conn.register_before_send(conn, fn conn ->
stop = System.monotonic_time()
diff = System.convert_time_unit(stop - start, :native, :milli_seconds)
ExStatsD.histogram(diff, prefix <> ".response_time", tags: gen_tags(conn, opts))
conn
end)
end
defp gen_tags(conn, opts) do
include_method? = Keyword.get(opts, :method, false)
include_path? = Keyword.get(opts, :path, false)
query_list = Keyword.get(opts, :query, nil)
conn.path_info
|> gen_route_tags(conn.path_params)
|> Enum.concat(gen_path_tags(conn.path_info, include_path?))
|> Enum.concat(gen_method_tags(conn.method, include_method?))
|> Enum.concat(gen_query_tags(conn.query_string, query_list))
end
defp gen_route_tags(path_info, %{}), do: [join_path(path_info, "route")]
defp gen_route_tags(path_info, path_params) do
reversed_params = Enum.reduce(path_params, %{}, fn {k, v}, acc -> Map.put(acc, v, k) end)
path_info
|> Enum.map(fn v -> Map.get(reversed_params, v) || v end)
|> gen_route_tags(%{})
end
defp gen_path_tags(_path_info, false), do: []
defp gen_path_tags(path_info, true), do: [join_path(path_info, "path")]
defp gen_method_tags(_method, false), do: []
defp gen_method_tags(method, true), do: [method]
defp gen_query_tags(_query_string, nil), do: []
defp gen_query_tags(query_string, query_list) do
query = query_string
|> Plug.Conn.Query.decode
|> Enum.map(fn {k, v} -> {k, "#{k}:#{v}"} end)
|> Enum.into(%{})
case query_list do
[] -> Map.values(query)
_ -> Enum.filter_map(query, fn {k, _} -> k in query_list end, fn {_, v} -> v end)
end
end
defp join_path(path_info, prefix), do: "#{prefix}:/#{Enum.join(path_info, "/")}"
end