Current section

Files

Jump to
new_relic_agent lib new_relic tracer direct.ex
Raw

lib/new_relic/tracer/direct.ex

defmodule NewRelic.Tracer.Direct do
@moduledoc false
@max_open_span_count Application.compile_env(:new_relic, :max_open_span_count, 20)
def start_span(id, name, options \\ []) do
case Process.get(:nr_open_span_count, 0) do
over when over >= @max_open_span_count ->
Process.put(:nr_open_span_count, over + 1)
NewRelic.incr_attributes(skipped_span_count: 1)
under ->
Process.put(:nr_open_span_count, under + 1)
system_time = Keyword.get(options, :system_time, System.system_time())
monotonic_time = Keyword.get(options, :monotonic_time, System.monotonic_time())
attributes = Keyword.get(options, :attributes, []) |> Map.new()
{span, previous_span, previous_span_attrs} =
NewRelic.DistributedTrace.set_current_span(
label: id,
ref: make_ref()
)
Process.put(
{:nr_span, id},
{name, system_time, monotonic_time, attributes, {span, previous_span, previous_span_attrs}}
)
end
:ok
end
def stop_span(id, options \\ []) do
case Process.delete({:nr_span, id}) do
nil ->
:no_such_span
{name, system_time, monotonic_start_time, start_attributes, {span, previous_span, previous_span_attrs}} ->
Process.put(:nr_open_span_count, Process.get(:nr_open_span_count) - 1)
{duration, duration_s} =
case Keyword.get(options, :duration) do
nil ->
duration = System.monotonic_time() - monotonic_start_time
{duration, System.convert_time_unit(duration, :native, :millisecond) / 1_000}
duration ->
{duration, System.convert_time_unit(duration, :native, :millisecond) / 1_000}
end
name = Keyword.get(options, :name, name)
stop_attributes = Keyword.get(options, :attributes, []) |> Map.new()
attributes = Map.merge(start_attributes, stop_attributes)
timestamp_ms = System.convert_time_unit(system_time, :native, :millisecond)
{primary_name, secondary_name} =
case name do
{primary_name, secondary_name} -> {primary_name, secondary_name}
name -> {name, ""}
end
NewRelic.Transaction.Reporter.add_trace_segment(%{
primary_name: primary_name,
secondary_name: secondary_name,
attributes: attributes,
pid: self(),
id: span,
parent_id: previous_span || :root,
start_time: system_time,
duration: duration
})
NewRelic.report_span(
timestamp_ms: timestamp_ms,
duration_s: duration_s,
name: primary_name,
edge: [span: span, parent: previous_span || :root],
category: "generic",
attributes: attributes
)
NewRelic.report_metric({:function, primary_name}, duration_s: duration_s)
NewRelic.DistributedTrace.reset_span(
previous_span: previous_span,
previous_span_attrs: previous_span_attrs
)
end
:ok
end
end