Packages
new_relic_agent
1.18.0-rc.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/sampler/top_process.ex
defmodule NewRelic.Sampler.TopProcess do
use GenServer
# Track and sample the top processes by:
# * memory usage
# * message queue length
@moduledoc false
alias NewRelic.Util.PriorityQueue, as: PQ
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(), :sample, NewRelic.Sampler.Reporter.random_offset())
{:ok, :reset}
end
def handle_info(:sample, :reset) do
top_procs = detect_top_processes()
Process.send_after(self(), :report, NewRelic.Sampler.Reporter.sample_cycle())
{:noreply, top_procs}
end
@kb 1024
def handle_info(:report, top_procs) do
Enum.each(top_procs, &report_sample/1)
send(self(), :sample)
{:noreply, :reset}
end
def detect_top_processes() do
{mem_pq, msg_pq} =
Process.list()
|> Enum.reduce({PQ.new(), PQ.new()}, &measure_and_insert/2)
(PQ.values(mem_pq) ++ PQ.values(msg_pq))
|> Enum.uniq_by(&elem(&1, 0))
end
@size 5
def measure_and_insert(pid, {mem_pq, msg_pq}) do
case Process.info(pid, [:memory, :message_queue_len, :registered_name, :reductions]) do
[memory: mem, message_queue_len: msg, registered_name: _, reductions: _] = info ->
mem_pq = PQ.insert(mem_pq, @size, mem, {pid, info})
msg_pq = if msg > 0, do: PQ.insert(msg_pq, @size, msg, {pid, info}), else: msg_pq
{mem_pq, msg_pq}
nil ->
{mem_pq, msg_pq}
end
end
def report_sample({pid, info}) do
case Process.info(pid, :reductions) do
{:reductions, current_reductions} ->
NewRelic.report_sample(:ProcessSample, %{
pid: inspect(pid),
memory_kb: info[:memory] / @kb,
message_queue_length: info[:message_queue_len],
name: parse(:name, pid, info[:registered_name]),
reductions: current_reductions - info[:reductions]
})
nil ->
:ignore
end
end
defp parse(:name, pid, []) do
with {:dictionary, dictionary} <- Process.info(pid, :dictionary),
{m, f, a} <- Keyword.get(dictionary, :"$initial_call") do
"#{inspect(m)}.#{f}/#{a}"
else
_ -> inspect(pid)
end
end
defp parse(:name, _pid, name), do: inspect(name)
end