this repo has no description
at main 2.4 kB view raw
1defmodule PlugOpenTracing do 2 @moduledoc """ 3 A plug for adding OpenTracing instrumentation to requests. 4 5 If a request already has a trace-id, the parts will be split 6 out and added as trace-id and parent-id in the new span. Otherwise, 7 a new span will be created. 8 9 The default header is "uber-trace-id" but this can be set at compile time. 10 11 At any point in the request you can access the span using conn.assigns[:trace]. 12 This can then be used to either add tags onto it or use the span as a parent span 13 for other requests. 14 15 To use it, just plug it into your module: 16 17 plug PlugOpenTracing 18 19 ## Options 20 21 * `:trace_id` - An incoming trace-id. This should be hex and in the 22 form `trace-id:span-id` plus any optional bits that will be removed. 23 24 plug PlugOpenTracing, trace_id: "my-trace-header" 25 """ 26 27 alias Plug.Conn 28 alias :otter, as: Otter 29 @behaviour Plug 30 31 def init(opts) do 32 Keyword.get(opts, :trace_header, "uber-trace-id") 33 end 34 35 def call(conn, trace_id_header) do 36 conn 37 |> get_trace_id(trace_id_header) 38 |> start_span() 39 |> tag_span() 40 |> register_span() 41 end 42 43 defp get_trace_id(conn, header) do 44 case Conn.get_req_header(conn, header) do 45 [] -> {conn, nil} 46 [val|_] -> {conn, extract_id(String.split(val, ":"))} 47 end 48 end 49 50 defp start_span({conn, [nil, _]}), do: start_span({conn, nil}) 51 defp start_span({conn, [_, nil]}), do: start_span({conn, nil}) 52 defp start_span({conn, [trace_id, span_id]}) do 53 {conn, Otter.start(conn.method, trace_id, span_id)} 54 end 55 defp start_span({conn, _}), do: {conn, Otter.start(conn.method)} 56 57 defp tag_span({conn, span}) do 58 span = span 59 |> Otter.tag("path", Enum.join(Enum.map(conn.path_info, &URI.decode/1), "/")) 60 |> Otter.tag("method", conn.method) 61 conn |> Conn.assign(:trace_span, span) 62 end 63 64 defp register_span(conn) do 65 Conn.register_before_send(conn, fn c -> 66 c.assigns[:trace_span] 67 |> Otter.finish() 68 c 69 end) 70 end 71 72 defp extract_id(vals) when length(vals) >= 2 do 73 vals 74 |> Enum.take(2) 75 |> Enum.map(fn(s) -> s 76 |> Integer.parse(16) 77 |> case do 78 :error -> nil 79 i -> elem(i,0) 80 end 81 end) 82 end 83 defp extract_id(_), do: nil 84end