A single compiled watch declaration.
This is the runtime shape of what you wrote in a Kepler module. You do not
build one by hand; the DSL produces them and Kepler.__kepler_watches__/0
returns them, in dependency order.
Reading one is the fastest way to see what a declaration actually cost:
:tier says which signal tier it uses, and the sampling and hot-path notes
in Kepler explain what each tier is charged.
Summary
Types
How raw observations are folded into a single number per tick.
Delivery semantics. Only :best_effort is implemented.
How loudly a consumer should react. Always present on an event.
Where a watch's occurrences come from.
Functions
Human-readable name for an aggregate, for the event payload.
Named aggregates a telemetry measurement can use, excluding percentiles.
How many :counters slots this watch's aggregate needs, or nil if it does
not use counters.
Whether a source produces discrete occurrences rather than a number per tick.
Delivery guarantees a watch may ask a sink for.
The measurement keys a source accepts.
Builds a watch from already-validated fields.
Fields a report source can be asked to enrich with.
Severities a watch may declare, quietest first.
System monitor conditions the VM can enforce on Kepler's behalf.
The signal tier a source belongs to.
Types
@type aggregate() :: :count | :rate | :sum | :average | :gauge | {:percentile, number()}
How raw observations are folded into a single number per tick.
@type guarantee() :: :best_effort | :at_least_once
Delivery semantics. Only :best_effort is implemented.
@type severity() :: :info | :warning | :error | :critical
How loudly a consumer should react. Always present on an event.
@type source() :: {:telemetry, [atom()]} | {:process, atom() | pid()} | {:vm, :memory | :system | :scheduler} | {:system_monitor, atom() | {atom(), pos_integer()}} | {:supervisor_report, :child_terminated} | {:crash_report, :any}
Where a watch's occurrences come from.
@type t() :: %Kepler.Watch{ condition: {module(), atom()} | nil, condition_source: String.t() | nil, cooldown: non_neg_integer(), deps: [atom()], enrich: [atom()], filter: {module(), atom()} | nil, guarantees: %{required(atom()) => guarantee()}, immediate: boolean(), measure: %{key: atom() | nil, aggregate: aggregate()} | nil, meta: map(), name: atom(), notify_resolved: boolean(), reads: [atom()], recent: %{size: pos_integer(), keys: :all | [atom()]} | nil, requires: [atom()], severity: severity(), sinks: :all | [atom()], source: source(), sustained: non_neg_integer(), tier: 0..2, unit: {System.time_unit(), System.time_unit()} | nil }
Functions
Human-readable name for an aggregate, for the event payload.
@spec aggregates() :: [atom()]
Named aggregates a telemetry measurement can use, excluding percentiles.
@spec counter_slots(t()) :: pos_integer() | nil
How many :counters slots this watch's aggregate needs, or nil if it does
not use counters.
Percentiles need the full histogram; everything else needs one or two words.
Whether a source produces discrete occurrences rather than a number per tick.
@spec guarantees() :: [guarantee()]
Delivery guarantees a watch may ask a sink for.
The measurement keys a source accepts.
Used by the DSL to reject measure :vibes at compile time rather than
letting it sample nil forever.
Builds a watch from already-validated fields.
@spec report_fields() :: [atom()]
Fields a report source can be asked to enrich with.
These come out of the report OTP already assembled — by the time it arrives the process is gone, so there is nothing to introspect and everything worth having was captured at crash time.
@spec severities() :: [severity()]
Severities a watch may declare, quietest first.
@spec system_monitor_types() :: [atom()]
System monitor conditions the VM can enforce on Kepler's behalf.
@spec tier(source()) :: 0..2
The signal tier a source belongs to.
Tier 0 is enforced by the VM and costs nothing until it trips. Tier 1 is a telemetry handler doing an atomic increment. Tier 2 is work done on the tick.