Current section

Files

Jump to
new_relic_agent lib new_relic distributed_trace.ex
Raw

lib/new_relic/distributed_trace.ex

defmodule NewRelic.DistributedTrace do
@dt_header "newrelic"
@moduledoc false
alias NewRelic.DistributedTrace.{Context, Tracker}
alias NewRelic.Transaction
def accept_distributed_trace_payload(:http, conn) do
case Plug.Conn.get_req_header(conn, @dt_header) do
[trace_payload | _] ->
trace_payload
|> Context.decode()
[] ->
:no_payload
end
end
def create_distributed_trace_payload(:http) do
case get_tracing_context() do
nil -> []
context -> [{@dt_header, Context.encode(context, get_current_span_guid())}]
end
end
def set_tracing_context(context) do
Tracker.store(self(), context: context)
end
def cleanup_context() do
Tracker.cleanup(self())
end
def get_tracing_context() do
if Transaction.Reporter.tracking?(self()) do
self()
|> Transaction.Reporter.root()
|> Tracker.fetch()
end
end
def set_span(:generic, attrs) do
Process.put(:nr_current_span_attrs, attrs)
end
def set_span(:http, url: url, method: method, component: component) do
Process.put(:nr_current_span_attrs, %{url: url, method: method, component: component})
end
def set_span(
:datastore,
statement: statement,
instance: instance,
address: address,
hostname: hostname,
component: component
) do
Process.put(:nr_current_span_attrs, %{
statement: statement,
instance: instance,
address: address,
hostname: hostname,
component: component
})
end
def get_span_attrs() do
Process.get(:nr_current_span_attrs) || %{}
end
def set_current_span(label: label, ref: ref) do
current = {label, ref}
previous = Process.get(:nr_current_span)
Process.put(:nr_current_span, current)
{current, previous}
end
def get_current_span_guid() do
case Process.get(:nr_current_span) do
nil -> generate_guid(pid: self())
{label, ref} -> generate_guid(pid: self(), label: label, ref: ref)
end
end
def reset_span(previous: previous) do
Process.put(:nr_current_span, previous)
end
def generate_guid(), do: :crypto.strong_rand_bytes(8) |> Base.encode16() |> String.downcase()
def generate_guid(pid: pid), do: encode_guid([pid, node()])
def generate_guid(pid: pid, label: label, ref: ref), do: encode_guid([label, ref, pid, node()])
def encode_guid(segments) when is_list(segments) do
segments
|> Enum.map(&encode_guid/1)
|> Enum.join("")
|> String.pad_trailing(16, "0")
end
def encode_guid(term) do
term
|> :erlang.phash2()
|> Integer.to_charlist(16)
|> to_string()
|> String.slice(0..4)
|> String.downcase()
end
end