Packages
new_relic_agent
1.18.2
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/transaction/reporter.ex
defmodule NewRelic.Transaction.Reporter do
use GenServer
alias NewRelic.Util.AttrStore
alias NewRelic.Transaction
# This GenServer collects and reports Transaction related data
# - Transaction Events
# - Transaction Metrics
# - Span Events
# - Transaction Errors
# - Transaction Traces
# - Custom Attributes
@moduledoc false
# Customer Exposed API
def add_attributes(attrs) when is_list(attrs) do
if tracking?(self()) do
AttrStore.add(
__MODULE__,
self(),
attrs
|> NewRelic.Util.deep_flatten()
|> NewRelic.Util.coerce_attributes()
)
end
end
def incr_attributes(attrs) do
if tracking?(self()) do
AttrStore.incr(__MODULE__, self(), attrs)
end
end
def set_transaction_name(custom_name) when is_binary(custom_name) do
if tracking?(self()) do
AttrStore.add(__MODULE__, self(), custom_name: custom_name)
end
end
# Internal Agent API
def start() do
Transaction.Monitor.add(self())
AttrStore.track(__MODULE__, self())
AttrStore.add(__MODULE__, self(),
pid: inspect(self()),
start_time: System.system_time(),
start_time_mono: System.monotonic_time()
)
end
def start_other_transaction(category, name) do
unless tracking?(self()) do
start()
AttrStore.add(__MODULE__, self(), other_transaction_name: "#{category}/#{name}")
end
end
def ignore_transaction() do
if tracking?(self()) do
ensure_purge(self())
AttrStore.untrack(__MODULE__, self())
AttrStore.purge(__MODULE__, self())
end
end
def fail(%{kind: kind, reason: reason, stack: stack} = error) do
if tracking?(self()) do
if NewRelic.Config.feature?(:error_collector) do
AttrStore.add(__MODULE__, self(),
error: true,
transaction_error: {:error, error},
error_kind: kind,
error_reason: inspect(reason),
error_stack: inspect(stack)
)
else
AttrStore.add(__MODULE__, self(), error: true)
end
end
end
def add_trace_segment(segment) do
if tracking?(self()) do
AttrStore.add(__MODULE__, self(), trace_function_segments: {:list, segment})
end
end
def track_metric(metric) do
if tracking?(self()) do
AttrStore.add(__MODULE__, self(), transaction_metrics: {:list, metric})
end
end
def complete(pid, mode) do
if tracking?(pid) do
AttrStore.add(__MODULE__, pid, end_time_mono: System.monotonic_time())
AttrStore.untrack(__MODULE__, pid)
case mode do
:sync ->
complete_and_purge(pid)
:async ->
Task.Supervisor.start_child(Transaction.TaskSupervisor, fn ->
complete_and_purge(pid)
end)
end
end
end
defp complete_and_purge(pid) do
AttrStore.collect(__MODULE__, pid)
|> Transaction.Complete.run(pid)
AttrStore.purge(__MODULE__, pid)
end
# Internal Transaction.Monitor API
#
def track_spawn(original, pid, timestamp) do
if tracking?(original) do
AttrStore.link(__MODULE__, original, pid)
AttrStore.add(__MODULE__, pid,
trace_process_spawns: {:list, {pid, timestamp, original}},
trace_process_names: {:list, {pid, NewRelic.Util.process_name(pid)}}
)
end
end
def track_exit(pid, timestamp) do
if tracking?(pid) do
AttrStore.add(__MODULE__, pid, trace_process_exits: {:list, {pid, timestamp}})
end
end
# Try really hard not to leak memory if any async reporting trickles in late
def ensure_purge(pid) do
Process.send_after(
__MODULE__,
{:ensure_purge, AttrStore.root(__MODULE__, pid)},
Application.get_env(:new_relic_agent, :ensure_purge_after, 2_000)
)
end
# GenServer
#
def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
NewRelic.sample_process()
AttrStore.new(__MODULE__)
{:ok, %{timers: %{}}}
end
def handle_info({:ensure_purge, pid}, state) do
AttrStore.purge(__MODULE__, pid)
{:noreply, %{state | timers: Map.drop(state.timers, [pid])}}
end
# Helpers
#
def tracking?(pid), do: AttrStore.tracking?(__MODULE__, pid)
def root(pid), do: AttrStore.root(__MODULE__, pid)
end