Skip to content

Event log schema reference

This page is a systematic reference for the on-disk/on-wire shape of the event log: the envelope every codec wraps a fact in, and every payload type the log can carry. For the concepts behind event sourcing in jaque, see Event sourcing instead.

Every persisted event is a Payload plus the fields the log itself owns — Envelope in eventlog/envelope.go:

Field Type Meaning
Version int Envelope version, bumped only for envelope-shape changes. Currently 2.
Seq uint64 Assigned by the transport on append; 0 until then.
Epoch uint64 The membership epoch the appending engine held at append time.
Payload Payload The domain fact itself — one of the types below.

The default codec (codec/, eventlog/codec_json.go) frames the envelope, payload included, as one JSON object per line:

{"v":2,"type":"state_changed","seq":42,"epoch":1,"object_id":"web1/http","occurred_at":"2026-08-04T10:00:00Z","data":{...}}

Short, snake_case keys — v, type, seq, epoch (omitted when zero), object_id, occurred_at, data — because this is a public contract read by jq and by ClickHouse, not Go field names leaking through encoding/json’s default. type is the wire discriminator; a codec other than JSON is free to use a different discriminator shape (an integer tag, a protobuf oneof) — nothing above is JSON-specific except the object itself.

One row per type defined in eventlog/payload_*.go. Every payload implements ObjectID() state.ObjectID and OccurredAt() time.Time; ObjectID() is the zero state.ObjectID for the two reload events, which are not about one object.

Type Wire type Emitted when Key fields
StateChanged state_changed Status, Type, Attempt, or Flapping changed on an object. ID, From state.State, To state.State, At
ReachabilityChanged reachability_changed Once per object returned by graph.Reachability.SetHostDown. ID, Reachable bool, At
CheckExecuted check_executed Every completed check. Result state.CheckResult, Origin (active/passive/stale)
NotificationRequested notification_requested Before any delivery attempt — the intent to notify is durable before the attempt exists. ID, NotificationID, Kind state.NotifyKind, Level, Contacts []string, At
NotificationSent notification_sent Delivery for a prior NotificationRequested succeeds. ID, NotificationID, Contact, At
NotificationFailed notification_failed A delivery attempt for a prior NotificationRequested fails. ID, NotificationID, Contact, Attempt, Err string, Terminal bool, At
AcknowledgementSet acknowledgement_set Operator runs ACKNOWLEDGE_HOST_PROBLEM/ACKNOWLEDGE_SVC_PROBLEM. ID, Author, Comment, Sticky bool, At
AcknowledgementCleared acknowledgement_cleared Operator runs REMOVE_HOST_ACKNOWLEDGEMENT/REMOVE_SVC_ACKNOWLEDGEMENT. ID, Author, At
DowntimeScheduled downtime_scheduled Operator runs SCHEDULE_HOST_DOWNTIME/SCHEDULE_SVC_DOWNTIME. ID, DowntimeID string, Author, Comment, Start, End, At
DowntimeCancelled downtime_cancelled Operator runs DEL_HOST_DOWNTIME/DEL_SVC_DOWNTIME. ID, DowntimeID string, At
ConfigReloaded config_reloaded A SIGHUP-triggered reload applies successfully. Added, Removed, Changed, Unchanged int, At (no ID)
ConfigReloadRejected config_reload_rejected A SIGHUP-triggered reload fails validation; the old config keeps running. Err string, At (no ID)
ObjectRetired object_retired A reload removes an object from the config. ID, At

Every field above is a plain string, number, bool, or timestamp — no opaque blob, no jaque-internal type leaking onto the wire — and the codec is the only thing that knows how to turn a Payload into bytes, so the shape above is the format, not an approximation of it. That is what lets the archive sink hand its zstd-compressed JSON lines to jq, ClickHouse, or DuckDB directly: reading the log back never requires running jaque or linking against its code, only knowing the table above.