Current section
Files
Jump to
Current section
Files
lib/plug_opentracing.ex
defmodule PlugOpenTracing do
@moduledoc """
A plug for adding OpenTracing instrumentation to requests.
If a request already has a trace-id, the parts will be split
out and added as trace-id and parent-id in the new span. Otherwise,
a new span will be created.
The default header is "uber-trace-id" but this can be set at compile time.
At any point in the request you can access the span using conn.assigns[:trace].
This can then be used to either add tags onto it or use the span as a parent span
for other requests.
To use it, just plug it into your module:
plug PlugOpenTracing
## Options
* `:trace_id` - An incoming trace-id. This should be hex and in the
form `trace-id:span-id` plus any optional bits that will be removed.
plug PlugOpenTracing, trace_id: "my-trace-header"
"""
alias Plug.Conn
alias :otter, as: Otter
@behaviour Plug
def init(opts) do
Keyword.get(opts, :trace_header, "uber-trace-id")
end
def call(conn, trace_id_header) do
conn
|> get_trace_id(trace_id_header)
|> start_span()
|> tag_span()
|> register_span()
end
defp get_trace_id(conn, header) do
case Conn.get_req_header(conn, header) do
[] -> {conn, nil}
[val|_] -> {conn, extract_id(String.split(val, ":"))}
end
end
defp start_span({conn, [nil, _]}), do: start_span({conn, nil})
defp start_span({conn, [_, nil]}), do: start_span({conn, nil})
defp start_span({conn, [trace_id, span_id]}) do
{conn, Otter.start(conn.method, trace_id, span_id)}
end
defp start_span({conn, _}), do: {conn, Otter.start(conn.method)}
defp tag_span({conn, span}) do
span = span
|> Otter.tag("path", Enum.join(Enum.map(conn.path_info, &URI.decode/1), "/"))
|> Otter.tag("method", conn.method)
conn |> Conn.assign(:trace_span, span)
end
defp register_span(conn) do
Conn.register_before_send(conn, fn c ->
c.assigns[:trace_span]
|> Otter.finish()
c
end)
end
defp extract_id(vals) when length(vals) >= 2 do
vals
|> Enum.take(2)
|> Enum.map(fn(s) -> s
|> Integer.parse(16)
|> case do
:error -> nil
i -> elem(i,0)
end
end)
end
defp extract_id(_), do: nil
end