Packages
new_relic_agent
1.3.1
1.40.3
1.40.2
1.40.1
1.40.0
1.39.0
1.38.0
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.1
1.31.0
1.30.0
1.29.0
1.28.0
1.27.8
1.27.7
1.27.6
1.27.5
1.27.4
1.27.3
1.27.2
1.27.1
1.27.0
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.5
1.24.4
1.24.3
1.24.2
1.24.1
1.24.0
1.24.0-rc.10
1.24.0-rc.9
1.24.0-rc.8
1.24.0-rc.7
1.23.6
1.23.5
1.23.4
1.23.3
1.23.2
1.23.1
1.23.0
1.23.0-rc.6
1.23.0-rc.5
1.23.0-rc.4
1.23.0-rc.3
1.23.0-rc.2
1.23.0-rc.1
1.22.6
1.22.5
1.22.4
1.22.3
1.22.2
1.22.1
1.22.0
1.21.2
1.21.1
1.21.0
1.21.0-rc.3
1.21.0-rc.1
1.20.0
1.20.0-rc.1
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.18.0-rc.5
1.18.0-rc.4
1.18.0-rc.2
1.18.0-rc.1
1.17.1
1.17.0
1.17.0-rc.4
1.17.0-rc.3
1.17.0-rc.2
1.17.0-rc.1
1.17.0-rc.0
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.16.0-rc.2
1.16.0-rc.1
1.16.0-rc.0
1.15.0
1.15.0-rc.3
1.15.0-rc.2
1.15.0-rc.1
1.14.0
1.13.1
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.12
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
New Relic's Open-Source Elixir Agent
Current section
Files
Jump to
Current section
Files
lib/new_relic/distributed_trace/plug.ex
defmodule NewRelic.DistributedTrace.Plug do
@behaviour Plug
import Plug.Conn
require Logger
# Plug that accepts an incoming DT payload and tracks the DT context
@moduledoc false
alias NewRelic.DistributedTrace
alias NewRelic.DistributedTrace.Context
alias NewRelic.Harvest.Collector.AgentRun
@impl Plug
def init(opts), do: opts
@impl Plug
def call(%{private: %{newrelic_dt_instrumented: true}} = conn, _opts) do
Logger.warn(
"You have instrumented twice in the same plug! Please `use NewRelic.Transaction` only once."
)
conn
end
def call(conn, _opts), do: trace(conn, NewRelic.Config.enabled?())
def trace(conn, false), do: conn
def trace(conn, true) do
determine_context(conn)
|> assign_transaction_guid
|> report_attributes
|> convert_to_outbound
|> DistributedTrace.set_tracing_context()
conn
|> put_private(:newrelic_dt_instrumented, true)
|> register_before_send(&before_send/1)
end
defp before_send(conn) do
DistributedTrace.cleanup_context()
conn
end
defp determine_context(conn) do
with %Context{} = context <- DistributedTrace.accept_distributed_trace_payload(:http, conn),
%Context{} = context <- restrict_access(context) do
context
else
_ -> generate_new_context()
end
end
defp assign_transaction_guid(context) do
Map.put(context, :guid, DistributedTrace.generate_guid())
end
defp report_attributes(%Context{parent_id: nil} = context) do
[
guid: context.guid,
traceId: context.guid,
priority: context.priority,
sampled: context.sampled
]
|> NewRelic.add_attributes()
context
end
defp report_attributes(context) do
[
"parent.type": context.type,
"parent.app": context.app_id,
"parent.account": context.account_id,
"parent.transportType": "HTTP",
"parent.transportDuration": transport_duration(context.timestamp),
parentId: context.parent_id,
parentSpanId: context.span_guid,
guid: context.guid,
traceId: context.trace_id,
priority: context.priority,
sampled: context.sampled
]
|> NewRelic.add_attributes()
context
end
defp convert_to_outbound(%Context{parent_id: nil} = context) do
%Context{
account_id: AgentRun.account_id(),
app_id: AgentRun.primary_application_id(),
parent_id: nil,
trust_key: context.trust_key,
guid: context.guid,
trace_id: context.guid,
priority: context.priority,
sampled: context.sampled
}
end
defp convert_to_outbound(%Context{} = context) do
%Context{
account_id: AgentRun.account_id(),
app_id: AgentRun.primary_application_id(),
parent_id: context.guid,
trust_key: context.trust_key,
guid: context.guid,
trace_id: context.trace_id,
priority: context.priority,
sampled: context.sampled
}
end
defp generate_new_context() do
{priority, sampled} = generate_sampling()
%Context{
account_id: AgentRun.account_id(),
app_id: AgentRun.primary_application_id(),
trust_key: AgentRun.trusted_account_key(),
priority: priority,
sampled: sampled
}
end
@doc false
def restrict_access(context) do
if (context.trust_key || context.account_id) == AgentRun.trusted_account_key() do
context
else
:restricted
end
end
defp generate_sampling() do
case {generate_sample?(), generate_priority()} do
{true, priority} -> {priority + 1, true}
{false, priority} -> {priority, false}
end
end
defp generate_sample?() do
NewRelic.DistributedTrace.BackoffSampler.sample?()
end
defp generate_priority, do: :rand.uniform() |> Float.round(6)
defp transport_duration(context_start_time) do
(System.system_time(:milliseconds) - context_start_time) / 1_000
end
end