Packages
new_relic_agent
1.9.8
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