Packages
new_relic_agent
1.10.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/sampler/process.ex
defmodule NewRelic.Sampler.Process do
use GenServer
# Takes samples of the state of requested processes at an interval
@moduledoc false
def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
NewRelic.sample_process()
if NewRelic.Config.enabled?(),
do: Process.send_after(self(), :report, NewRelic.Sampler.Reporter.random_offset())
{:ok, %{pids: %{}, previous: %{}}}
end
def sample_process, do: GenServer.cast(__MODULE__, {:sample_process, self()})
def handle_cast({:sample_process, pid}, state) do
state = store_pid(state.pids[pid], state, pid)
{:noreply, state}
end
def handle_info(:report, state) do
previous = record_samples(state)
Process.send_after(self(), :report, NewRelic.Sampler.Reporter.sample_cycle())
{:noreply, %{state | previous: previous}}
end
def handle_info({:DOWN, _ref, :process, pid, _reason}, state) do
state = %{
state
| pids: Map.delete(state.pids, pid),
previous: Map.delete(state.previous, pid)
}
{:noreply, state}
end
def handle_call(:report, _from, state) do
previous = record_samples(state)
{:reply, :ok, %{state | previous: previous}}
end
def record_samples(state) do
Enum.reduce(state.pids, %{}, fn {pid, true}, acc ->
{current_sample, stats} = collect(pid, state.previous[pid])
NewRelic.report_sample(:ProcessSample, stats)
Map.put(acc, pid, current_sample)
end)
end
def store_pid(true, state, _existing_pid), do: state
def store_pid(nil, state, pid) do
Process.monitor(pid)
pids = Map.put(state.pids, pid, true)
previous = Map.put(state.previous, pid, take_sample(pid))
%{state | pids: pids, previous: previous}
end
def collect(pid, previous) do
current_sample = take_sample(pid)
stats = Map.merge(current_sample, delta(previous, current_sample))
{current_sample, stats}
end
@kb 1024
def take_sample(pid) do
# http://erlang.org/doc/man/erlang.html#process_info-2
info = Process.info(pid, [:message_queue_len, :memory, :reductions, :registered_name])
%{
pid: inspect(pid),
memory_kb: info[:memory] / @kb,
message_queue_length: info[:message_queue_len],
name: parse(:name, info[:registered_name]) || inspect(pid),
reductions: info[:reductions]
}
end
defp delta(previous, current), do: %{reductions: current.reductions - previous.reductions}
defp parse(:name, []), do: nil
defp parse(:name, name), do: inspect(name)
end