defmodule Uplink.Monitors.VM do
use TelemetryRegistry
use Uplink.Monitor
telemetry_event(%{
event: [:vm, :stats],
description: "Emits BEAM system statistics",
measurements: """
%{
context_switches: non_neg_integer,
gc_count: non_neg_integer,
gc_bytes_reclaimed: non_neg_integer,
io_in: non_neg_integer,
io_out: non_neg_integer,
reductions: non_neg_integer
}
""",
metadata: "%{}"
})
telemetry_event(%{
event: [:vm, :system_limits],
description: "Emits BEAM system limits",
measurements: """
%{
atom_limit: non_neg_integer,
port_limit: non_neg_integer,
process_limit: non_neg_integer
}
""",
metadata: "%{}"
})
@moduledoc """
Provides telemetry events, pollers for emitting those events, and definitions for
BEAM VM statistics in addition to the builtins available `telemetry_poller` vm statistics.
## Telemetry
#{telemetry_docs()}
"""
import Telemetry.Metrics, only: [counter: 2, last_value: 2]
@impl true
def init(_opts \\ []), do: :ok
@impl true
def poller_specs(opts \\ []) do
args = Keyword.merge([poller_interval: :timer.seconds(5)], opts)
[
{args[:poller_interval],
[
:memory,
:total_run_queue_lengths,
:system_counts,
{__MODULE__, :emit_system_limits, []},
{__MODULE__, :emit_stats, []}
]}
]
end
def emit_system_limits do
measurements =
Enum.map(
[
:atom_limit,
:port_limit,
:process_limit
],
&{&1, :erlang.system_info(&1)}
)
|> Enum.into(%{})
:telemetry.execute([:vm, :system_limits], measurements)
end
def emit_stats do
{context_switches, _} = :erlang.statistics(:context_switches)
{reductions, _} = :erlang.statistics(:reductions)
{gc_count, words_reclaimed, _} = :erlang.statistics(:garbage_collection)
{{:input, input}, {:output, output}} = :erlang.statistics(:io)
:telemetry.execute([:vm, :stats], %{
context_switches: context_switches,
reductions: reductions,
gc_count: gc_count,
gc_bytes_reclaimed: words_reclaimed * 8,
io_in: input,
io_out: output
})
end
@impl true
def metric_definitions(_opts \\ []) do
[
counter("erlang.vm.context_switches.total",
event_name: [:vm, :stats],
measurement: :context_switches,
unit: :"1",
description: "Erlang VM - Total context switches"
),
counter("erlang.vm.reductions.total",
event_name: [:vm, :stats],
measurement: :reductions,
unit: :"1",
description: "Erlang VM - Total reductions"
),
counter("erlang.vm.gc.total",
event_name: [:vm, :stats],
measurement: :gc_count,
unit: :"1",
description: "Erlang VM - Total garbage collections"
),
counter("erlang.vm.gc.reclaimed.total.bytes",
event_name: [:vm, :stats],
measurement: :gc_bytes_reclaimed,
unit: :byte,
description: "Erlang VM - Total bytes reclaimed from gc"
),
counter("erlang.vm.io.in.total.bytes",
event_name: [:vm, :stats],
measurement: :io_in,
unit: :byte,
description: "Erlang VM - Total IO bytes in"
),
counter("erlang.vm.io.out.total.bytes",
event_name: [:vm, :stats],
measurement: :io_out,
unit: :byte,
description: "Erlang VM - Total IO bytes out"
),
last_value("erlang.vm.memory.usage.bytes",
event_name: [:vm, :memory],
measurement: :total,
unit: :byte,
description: "Erlang VM - Total memory usage"
),
last_value("erlang.vm.memory.processes.usage.bytes",
event_name: [:vm, :memory],
measurement: :processes_used,
unit: :byte,
description: "Erlang VM - Total memory used by all processes"
),
last_value("erlang.vm.memory.binaries.usage.bytes",
event_name: [:vm, :memory],
measurement: :binary,
unit: :byte,
description: "Erlang VM - Total memory used by binaries"
),
last_value("erlang.vm.memory.ets.usage.bytes",
event_name: [:vm, :memory],
measurement: :ets,
unit: :byte,
description: "Erlang VM - Total memory used by ets tables"
),
last_value("erlang.vm.run_queue_lengths",
event_name: [:vm, :total_run_queue_lengths],
measurement: :total,
unit: :"1",
description: "Erlang VM - Sum of all schedulers' run queue lengths"
),
last_value("erlang.vm.run_queue_lengths.cpu",
event_name: [:vm, :total_run_queue_lengths],
measurement: :cpu,
unit: :"1",
description:
"Erlang VM - Sum of CPU schedulers' run queue lengths, including dirty CPU run queue length"
),
last_value("erlang.vm.system.process.limit",
event_name: [:vm, :system_limits],
measurement: :process_limit,
unit: :"1",
description: "Erlang VM - Total process limit"
),
last_value("erlang.vm.system.process.usage",
event_name: [:vm, :system_counts],
measurement: :process_count,
unit: :"1",
description: "Erlang VM - Total process count"
),
last_value("erlang.vm.system.atom.limit",
event_name: [:vm, :system_limits],
measurement: :atom_limit,
unit: :"1",
description: "Erlang VM - Total atom limit"
),
last_value("erlang.vm.system.atom.usage",
event_name: [:vm, :system_counts],
measurement: :atom_count,
unit: :"1",
description: "Erlang VM - Total atom count"
),
last_value("erlang.vm.system.port.limit",
event_name: [:vm, :system_limits],
measurement: :port_limit,
unit: :"1",
description: "Erlang VM - Total port limit"
),
last_value("erlang.vm.system.port.usage",
event_name: [:vm, :system_counts],
measurement: :port_count,
unit: :"1",
description: "Erlang VM - Total port count"
)
]
end
end