Packages
new_relic_agent
1.31.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_sample_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
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: kb(info[:memory]),
message_queue_length: info[:message_queue_len],
name: parse(:name, info[:registered_name]) || inspect(pid),
reductions: info[:reductions]
}
end
@kb 1024
defp kb(nil), do: nil
defp kb(bytes), do: bytes / @kb
defp delta(%{reductions: nil}, _), do: nil
defp delta(_, %{reductions: nil}), do: nil
defp delta(%{reductions: prev}, %{reductions: curr}), do: %{reductions: curr - prev}
defp parse(:name, []), do: nil
defp parse(:name, name), do: inspect(name)
end