Current section

Files

Jump to
new_relic_agent lib new_relic distributed_trace context.ex
Raw

lib/new_relic/distributed_trace/context.ex

defmodule NewRelic.DistributedTrace.Context do
# Struct containing the DT payload context
@moduledoc false
@payload_version [0, 1]
defstruct type: "App",
version: @payload_version,
account_id: nil,
app_id: nil,
parent_id: nil,
guid: nil,
span_guid: nil,
trace_id: nil,
trust_key: nil,
priority: nil,
sampled: false,
timestamp: nil
def decode(raw_payload) when is_binary(raw_payload) do
with {:ok, json} <- Base.decode64(raw_payload),
{:ok, map} <- Jason.decode(json),
context <- validate(map) do
NewRelic.report_metric(:supportability, [:dt, :accept, :success])
context
else
error ->
NewRelic.report_metric(:supportability, [:dt, :accept, :parse_error])
NewRelic.log(:debug, "Bad DT Payload: #{inspect(error)} #{inspect(raw_payload)}")
nil
end
end
def validate(%{
"v" => @payload_version,
"d" =>
%{
"ty" => type,
"ac" => account_id,
"ap" => app_id,
"tr" => trace_id,
"ti" => timestamp
} = data
}) do
%__MODULE__{
version: @payload_version,
type: type,
account_id: account_id,
app_id: app_id,
parent_id: data["tx"],
span_guid: data["id"],
trace_id: trace_id,
trust_key: data["tk"],
priority: data["pr"],
sampled: data["sa"] || false,
timestamp: timestamp
}
end
def validate(_invalid), do: :invalid
def encode(context, current_span_guid) do
%{
"v" => @payload_version,
"d" =>
%{
"ty" => context.type,
"ac" => context.account_id,
"ap" => context.app_id,
"tx" => context.guid,
"tr" => context.trace_id,
"pr" => context.priority,
"sa" => context.sampled,
"ti" => System.system_time(:millisecond)
}
|> maybe_put(:span_guid, "id", context.sampled, current_span_guid)
|> maybe_put(:trust_key, "tk", context.account_id, context.trust_key)
}
|> Jason.encode!()
|> Base.encode64()
end
def maybe_put(data, :span_guid, key, true = _sampled, guid), do: Map.put(data, key, guid)
def maybe_put(data, :span_guid, _key, false = _sampled, _guid), do: data
def maybe_put(data, :trust_key, _key, account_id, account_id), do: data
def maybe_put(data, :trust_key, _key, _account_id, nil), do: data
def maybe_put(data, :trust_key, key, _account_id, trust_key), do: Map.put(data, key, trust_key)
def parse_int(nil), do: :error
def parse_int(field), do: Integer.parse(field)
end