Skip to content

Metrics: several families are registered but never incremented (export as 0) #44

Description

@oreofeolurin

Surfaced by #43, which wired up the Prometheus exporter. Now that /metrics is actually served, it's visible that several metric families are created and exported but never written to — they scrape as 0 forever, which reads as "this node is idle" rather than "this isn't instrumented".

The registry and the exporter are both fine. The gap is that the write paths never call the record* methods.

Current state

Counted callers outside the metrics modules themselves:

Family Registered? Recorded? Effect
ServerMetrics (flo_commands_total, bytes, connections, uptime) n/a recordCommand, recordBytesReceived/Sent, connectionOpened/Closed works
ReplicationMetrics (flo_replication_*) n/a ✅ wired in #16 works
ProcessingMetrics (flo_processing_*) n/a ⚠️ partial — recordProcessed (2), recordCheckpoint (1), recordError (1); recordDropped, recordSubmitted, recordFailed have none partly live
ShardMetrics (flo_shard_*) sized by initShards (#43) shardMetrics() has 0 callers all rows 0
StreamMetrics (flo_stream_*) registerStream ×8 recordAppend / recordRead 0 callers series appear, all values 0
QueueMetrics (flo_queue_*) registerQueue ×15 recordEnqueue / recordDequeue 0 callers queues appear, all values 0
WorkflowMetrics (flo_workflow_*) n/a workflow/handler.zig never references metrics_registry at all all 0
TieredLogMetrics (flo_tiered_log_*) registerTieredLog 0 callers family never appears
KVMetrics ⚠️ registerKVNamespace ×1 recordGet / recordSet 0 callers not emitted by exportPrometheus at all

Why it matters

A scrape today shows flo_stream_append_records_total{topic="orders"} 0 on a stream that is actively taking writes. That's worse than the family being absent: a dashboard or alert built on it silently reads "no traffic". It's the same shape as the fabricated ingest_rate: 0 / retention: "7d" values fixed in #29 — a number that looks real and isn't.

What to do

Call the existing record* methods from the write paths. The handlers already hold metrics_registry (and registerStream/registerQueue are already called there), so most of this is a one-line call next to the existing register:

  • stream/handler.zigrecordAppend(records, bytes) on append, recordRead(...) on read/group-read; also the trim and consumer-group counters the family already defines.
  • queue/handler.zigrecordEnqueue / recordDequeue / ack / nack / DLQ / lease counters.
  • workflow/handler.zig — wire metrics_registry in (it has none today), then recordStarted / recordCompleted / recordFailed / recordSignalDelivered / recordStepExecuted.
  • node/shard.zig — take registry.shardMetrics(self.id) once at wire-up and record commands / bytes / connections / reactor loops / inbox depth per shard. Note the shard already records the global server.* counters, so this is about attribution, not new data.
  • processing/handler.zig — fill in recordSubmitted / recordFailed / recordDropped.
  • Decide whether KVMetrics and TieredLogMetrics should be exported at all; if yes, add them to exportPrometheus and call registerTieredLog. If not, delete them rather than leaving dead structs.

Acceptance

Assert real values, not presence. E.g. append 3 records, scrape, assert flo_stream_append_records_total{...} 3 — a test that only checks the metric name appears would pass today and is exactly what let this hide.

Until this lands, docs/deployment/clustering.mdx carries a note that these families export as 0; remove it when they're populated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions