CodeNameRaven.Probe behaviour (raven_observer_sdk v0.5.4)

Copy Markdown

Behaviour for probe monitors — monitors that observe other monitors via Raven's event bus rather than collecting from an external target directly.

A probe subscribes to events on startup (handled by Raven itself, not the probe) and reacts to them as they arrive. Unlike a standard integration, a probe never polls anything — its "collection" is just reading its own accumulated state, updated as events arrive.

This module is deliberately implementation-free: it defines only the callback contract. The actual event subscription and dispatch live in Raven itself (mirroring how CodeNameRaven.Display's on_metric/3/ on_status/3 work — the display module never subscribes to anything itself either). A probe module built against this behaviour has zero dependency on any Raven-internal module and compiles standalone.

Using this behaviour

Replace use CodeNameRaven.Monitor with use CodeNameRaven.Probe. Then implement the callbacks your probe needs:

  • probe_init/1 — set up initial state from params (replaces init/1)
  • on_metric/3 — react to an arriving metric event
  • on_status/3 — react to an arriving status event (optional)
  • healthy?/1 — evaluate current state → health signal (required, inherited from CodeNameRaven.Monitor — not redefined here)

All callbacks except healthy?/1 have no-op defaults. A minimal probe only needs probe_init/1, on_metric/3, and healthy?/1.

Lifecycle

  1. Raven starts the probe's process, sees it's probe-shaped, and subscribes it to metric and status events on its behalf.
  2. Raven calls init/1 → delegates to probe_init/1 for state setup.
  3. As metric/status events arrive, Raven calls on_metric/3 or on_status/3 directly with the event and the probe's current state.
  4. on_metric/3 / on_status/3 return {:ok, new_state} to update state and wait, or {:ok, new_state, :check_now} to also trigger an immediate check cycle.
  5. On each check cycle, collect/2 returns {:ok, state, state} — the current state is the collect result.
  6. healthy?/1 receives the state and returns :up, :degraded, :down, or :unknown.

Event shapes

on_metric/3's first argument and on_status/3's first argument are loosely typed (term()) rather than a concrete struct — the concrete shape is documented here rather than enforced at compile time, matching CodeNameRaven.Display's on_metric/3/on_status/3 precedent, since the real message module lives in Raven itself, not this SDK.

A metric event has (at least) these fields: monitor_id (the id of the monitor that produced it), metric_name (string), value (number), checked_at (DateTime.t()), target_id (string or nil).

A status event has (at least): monitor_id, status (:up | :degraded | :down | :unknown), checked_at, target_id.

Both are plain structs with a stable, additive-only field contract: Raven may add fields to these events across releases, but will not remove or repurpose a field a probe already relies on.

Example

defmodule Integrations.MyProbe do
  use CodeNameRaven.Probe
  use CodeNameRaven.Display, category: :custom, size_hint: :small

  @impl true
  def probe_init(%{"monitor_id" => mid} = _params) do
    {:ok, %{monitor_id: mid, last_value: nil}}
  end

  @impl true
  def on_metric(%{monitor_id: mid, metric_name: "my_metric", value: v},
                _params, %{monitor_id: mid} = state) do
    {:ok, %{state | last_value: v}, :check_now}
  end
  def on_metric(_, _, state), do: {:ok, state}

  @impl true
  def healthy?(%{last_value: nil}), do: :unknown
  def healthy?(%{last_value: v}) when v > 100, do: :down
  def healthy?(_), do: :up
end

Relationship to Monitor

use CodeNameRaven.Probe sets up the full CodeNameRaven.Monitor behaviour and overrides two callbacks with probe-specific defaults:

  • init/1 → delegates to probe_init/1
  • collect/2 → returns {:ok, state, state} (state is the result)

All other Monitor callbacks (after_check/3, metrics/1, etc.) are available with their standard defaults and can be overridden normally.

Summary

Callbacks

Handles an arriving metric event.

Handles an arriving status event.

Initialises the probe's state from params.

Functions

Returns true if the given module implements the Probe behaviour.

Callbacks

on_metric(metric, params, state)

@callback on_metric(metric :: term(), params :: map(), state :: term()) ::
  {:ok, term()} | {:ok, term(), :check_now}

Handles an arriving metric event.

Called directly by Raven when a metric event matching this probe's subscription arrives — not routed through handle_info/3. Return {:ok, new_state} to update state, or {:ok, new_state, :check_now} to also trigger an immediate check cycle.

The default ignores all metrics and returns the state unchanged.

on_status(status, params, state)

@callback on_status(status :: term(), params :: map(), state :: term()) ::
  {:ok, term()} | {:ok, term(), :check_now}

Handles an arriving status event.

Called directly by Raven, same delivery mechanism as on_metric/3. Return {:ok, new_state} to update state, or {:ok, new_state, :check_now} to also trigger an immediate check cycle.

The default ignores all status events and returns the state unchanged.

probe_init(params)

@callback probe_init(params :: map()) :: {:ok, term()} | {:error, String.t()}

Initialises the probe's state from params.

Called by the Probe-managed init/1. Return {:ok, initial_state} or {:error, reason}.

The default returns {:ok, %{}}.

Functions

probe_module?(module)

@spec probe_module?(module()) :: boolean()

Returns true if the given module implements the Probe behaviour.

Checks for probe_init/1, the one callback every real probe defines (directly or via inheriting use CodeNameRaven.Probe's default).