-module(pharos@probe). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pharos/probe.gleam"). -export([new/5, id/1, event_name/1, interval_ms/1, source/1, decode/2, threshold_id/1]). -export_type([source/0, probe/0, comparison/0, probe_threshold/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Custom monitoring probes - the pluggable lane of pharos.\n" "\n" " The built-in `Statistic` / `Measurement` / `Threshold` enums cover BEAM\n" " and host signals. A `Probe` opens the same poll → decode → threshold →\n" " alert pipeline to *any* signal a caller can express, without modifying\n" " pharos: it bundles how to poll (a `Source`), the telemetry event it\n" " emits, and how to decode that event into named numeric readings\n" " (`MetricSample`). `ProbeThreshold`s compare a single sample field against\n" " a limit and feed the same soak/cool alert machinery the BEAM lane uses.\n" "\n" " This is what lets a consumer such as `logothetes` monitor MicroVMs:\n" " register a probe whose `Source` points at an emitter that reads\n" " `/proc/` and `telemetry:execute`s the readings, plus thresholds over\n" " the decoded fields.\n" ). -type source() :: {custom_mfa, gleam@erlang@atom:atom_(), gleam@erlang@atom:atom_(), list(gleam@dynamic:dynamic_())}. -opaque probe() :: {probe, binary(), list(gleam@erlang@atom:atom_()), integer(), source(), fun((pharos@measurement:telemetry_event()) -> {ok, gleam@dict:dict(binary(), float())} | {error, binary()})}. -type comparison() :: {above, float()} | {below, float()}. -type probe_threshold() :: {probe_threshold, binary(), binary(), comparison(), pharos@alert:alert_level()}. -file("src/pharos/probe.gleam", 55). ?DOC( " Define a probe.\n" "\n" " - `id` - stable identifier, referenced by `ProbeThreshold.probe_id`.\n" " - `event_name` - the telemetry event the `source` emits (e.g.\n" " `[atom.create(\"logothetes\"), atom.create(\"vm\"), atom.create(\"metrics\")]`).\n" " - `interval_ms` - how often to poll.\n" " - `source` - how the reading is produced.\n" " - `decode` - lift the raw telemetry event into a `MetricSample`.\n" ). -spec new( binary(), list(gleam@erlang@atom:atom_()), integer(), source(), fun((pharos@measurement:telemetry_event()) -> {ok, gleam@dict:dict(binary(), float())} | {error, binary()}) ) -> probe(). new(Id, Event_name, Interval_ms, Source, Decode) -> {probe, Id, Event_name, Interval_ms, Source, Decode}. -file("src/pharos/probe.gleam", 72). ?DOC(" The probe's stable identifier.\n"). -spec id(probe()) -> binary(). id(Probe) -> erlang:element(2, Probe). -file("src/pharos/probe.gleam", 77). ?DOC(" The telemetry event name the probe emits.\n"). -spec event_name(probe()) -> list(gleam@erlang@atom:atom_()). event_name(Probe) -> erlang:element(3, Probe). -file("src/pharos/probe.gleam", 82). ?DOC(" The probe's polling interval in milliseconds.\n"). -spec interval_ms(probe()) -> integer(). interval_ms(Probe) -> erlang:element(4, Probe). -file("src/pharos/probe.gleam", 87). ?DOC(" How the probe is polled.\n"). -spec source(probe()) -> source(). source(Probe) -> erlang:element(5, Probe). -file("src/pharos/probe.gleam", 93). ?DOC( " Decode a raw telemetry event into a `MetricSample` using the probe's\n" " decoder.\n" ). -spec decode(probe(), pharos@measurement:telemetry_event()) -> {ok, gleam@dict:dict(binary(), float())} | {error, binary()}. decode(Probe, Event) -> (erlang:element(6, Probe))(Event). -file("src/pharos/probe.gleam", 123). ?DOC( " Stable string id derived from a probe threshold. Used to register the\n" " per-threshold alert manager under a deterministic name (mirrors\n" " `config.threshold_id` for the BEAM lane).\n" ). -spec threshold_id(probe_threshold()) -> binary(). threshold_id(Threshold) -> Comparison = case erlang:element(4, Threshold) of {above, _} -> <<"above"/utf8>>; {below, _} -> <<"below"/utf8>> end, <<<<<<<<(erlang:element(2, Threshold))/binary, "_"/utf8>>/binary, (erlang:element(3, Threshold))/binary>>/binary, "_"/utf8>>/binary, Comparison/binary>>.