Packages
new_relic_agent
1.9.11
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/monitor.ex
defmodule NewRelic.Transaction.Monitor do
use GenServer
alias NewRelic.Transaction
alias NewRelic.DistributedTrace
# This GenServer watches transaction processes for
# - :trace messages
# - :DOWN messages
#
# :trace messages signal that a transaction process has
# spwaned another process. We want to track that process
# so we can track attributes on the original transaction
#
# :DOWN signals that the transaction process is complete, so
# we tell the reporter to purge its data
@moduledoc false
def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
NewRelic.sample_process()
enable_trace_patterns()
{:ok, %{pids: %{}}}
end
# API
def add(pid), do: GenServer.call(__MODULE__, {:add, pid})
# Server
def handle_call({:add, pid}, _from, %{pids: pids} = state) do
pids =
pids
|> Map.has_key?(pid)
|> setup_monitor(pids, pid)
{:reply, :ok, %{state | pids: pids}}
end
# Trace messages
def handle_info({:trace_ts, source, :spawn, pid, _mfa, timestamp}, state) do
Transaction.Reporter.track_spawn(source, pid, NewRelic.Util.time_to_ms(timestamp))
{:noreply, state}
end
def handle_info({:trace_ts, pid, :exit, _reason, timestamp}, state) do
Transaction.Reporter.track_exit(pid, NewRelic.Util.time_to_ms(timestamp))
{:noreply, state}
end
def handle_info(
{:trace_ts, source, :return_from, {Task.Supervisor, :async_nolink, _}, %Task{pid: pid},
timestamp},
state
) do
enable_trace_flags(pid)
Transaction.Reporter.track_spawn(source, pid, NewRelic.Util.time_to_ms(timestamp))
{:noreply, state}
end
def handle_info(
{:trace_ts, source, :return_from, {:poolboy, :checkout, _}, pid, timestamp},
state
) do
Transaction.Reporter.track_spawn(source, pid, NewRelic.Util.time_to_ms(timestamp))
{:noreply, state}
end
def handle_info({:DOWN, _ref, :process, pid, _reason}, state) do
Transaction.Reporter.ensure_purge(pid)
Transaction.Reporter.complete(pid)
DistributedTrace.Tracker.cleanup(pid)
{:noreply, %{state | pids: Map.delete(state.pids, pid)}}
end
def handle_info(_msg, state) do
# Ignore other :trace messages
{:noreply, state}
end
# Helpers
defp setup_monitor(false, pids, pid) do
Process.monitor(pid)
enable_trace_flags(pid)
Map.put(pids, pid, true)
end
defp setup_monitor(true, pids, _) do
pids
end
def enable_trace_flags(pid) do
# Trace process events to notice when a process is spawned
# Trace function calls so we can install specific trace_patterns
# http://erlang.org/doc/man/erlang.html#trace-3
:erlang.trace(pid, true, [:procs, :call, :set_on_spawn, :timestamp])
rescue
# Process is already dead
ArgumentError ->
nil
end
def enable_trace_patterns do
# Use function tracers to notice when Async work has been kicked off
# http://erlang.org/doc/man/erlang.html#trace_3_trace_messages_return_from
# http://erlang.org/doc/apps/erts/match_spec.html
trace_task_async_nolink()
trace_poolboy_checkout()
end
defp trace_task_async_nolink do
:erlang.trace_pattern({Task.Supervisor, :async_nolink, :_}, [{:_, [], [{:return_trace}]}], [])
end
defp trace_poolboy_checkout do
:erlang.trace_pattern({:poolboy, :checkout, :_}, [{:_, [], [{:return_trace}]}], [])
end
end