Monitor the Broker
Goal
Wire Prometheus scraping, log aggregation, and trace consumption
against ovstorage-broker using its built-in surfaces. No
audit-record subsystem ships today; tracing fields are the audit
trail.
Recipe
- Read
docs/public/broker-operator/README.md
§ Observability for the full reference.
- Enable Prometheus by adding
[observability] prometheus_bind = "HOST:PORT" to the broker
TOML. The broker spawns an axum listener serving
text/plain; version=0.0.4 exposition.
- Scrape the listener with your Prometheus / VictoriaMetrics /
etc. setup. Expect these 11 metric families (some are dormant
today — registered but not yet observed):
broker_rpc_seconds{op} — RPC latency. Dormant.
broker_cache_metadata_hits_total — metadata-cache hits.
broker_cache_object_hits_total — object-byte-cache hits.
broker_cache_object_fills_total — object-byte-cache fills.
broker_cache_evictions_total — dormant.
broker_authz_decisions_total{outcome} — labels are
allow, deny, error.
broker_watch_fanout (gauge) — dormant.
broker_policy_epoch_advances_total — increments per
successful SIGHUP reload.
broker_redirect_emissions_total{kind} — labels are
read, write. Increments at every fixture-driven and
plugin-driven redirect emission site.
broker_lifecycle_events_total{event} — labels are
reload_ok, reload_failed, drain_start,
drain_complete.
broker_uptime_seconds.
- Pipe
grpc.health.v1.Health/Check to your health-check probe.
Reports Serving whenever backend-kind introspection on the active
Stack succeeds. Readiness is not flipped during drain (the gRPC
server stops accepting new connections via
serve_with_incoming_shutdown but Health/Check keeps the
last reported state until the server thread exits).
- Wire tracing. The broker uses
init_tracing_from_env so the standard RUST_LOG /
OTEL_* env vars apply. OTLP push as a [observability] otlp_endpoint field is reserved (surfaces Unsupported if
set); layer opentelemetry_otlp onto init_tracing_from_env
manually if you need it.
Tracing fields to collect
Per the broker-operator persona doc:
principal.id — on every object-IO span (broker.stat,
broker.read, broker.write, broker.list,
broker.list_versions, broker.list_address_roots).
policy_epoch — on every object-IO span and every
pb::ErrorDetail.
object.address — redacted via RedactedUrl (scheme + host +
port + path only, no query / fragment / userinfo).
audit_id — on ReadRedirect and WriteRedirect envelopes
and on every pb::ErrorDetail. Freshly minted when the host's
RequestContext.audit_id is None.
cache.hit, redirect.kind — when applicable.
outcome ∈ {allow, deny, error} — on the
broker_authz_decisions_total counter.
Fields not stamped today: route.id and backend.id on
per-RPC spans. Closing the gap is tracked.
Audit log shape (what you don't get)
There is no AuditRecord / AuditEvent type, durable sink, or
operator-facing explain-decision <audit-id> tool. Diagnostic
fields land in tracing spans, error details, and redirect
envelopes only. Operators that need an audit log point a log
aggregator at the broker's tracing output and filter on
audit_id + policy_epoch + principal.id.
Sinks must redact physical URLs before logging query strings or
signed headers. The pipeline must never log raw bearer tokens,
credential bytes, or usable signed URLs.
Suggested alerts
rate(broker_lifecycle_events_total{event="reload_failed"}[5m]) > 0
— a SIGHUP reload failed validation; the old broker is still live
on stale config.
rate(ovstorage_auth_decisions_total{outcome="error"}[5m]) > 0 —
the built-in auth Layer returned evaluation errors (not denies). Check the
active policy and listener authentication configuration.
broker_uptime_seconds reset implies a restart — pair with
broker_policy_epoch_advances_total to distinguish a clean
reload-induced advance from a process crash.
rate(broker_redirect_emissions_total{kind="write"}[5m]) falling
to zero on a route that previously emitted them suggests the
plugin can no longer mint redirects (and the broker is falling
back to inline upload, which has the 64 MiB
WRITE_BODY_BYTE_CAP).
References
1---2name: ovstorage-operator-monitor-broker3description: Use when wiring observability for a running ovstorage-broker - covers the Prometheus /metrics surface, the 11 metric families, the tracing span fields, and the audit-safe diagnostic shape.4license: CC-BY-4.05---67# Monitor the Broker89## Goal1011Wire Prometheus scraping, log aggregation, and trace consumption12against `ovstorage-broker` using its built-in surfaces. No13audit-record subsystem ships today; tracing fields are the audit14trail.1516## Recipe17181. Read19 [`docs/public/broker-operator/README.md`](../../docs/public/broker-operator/README.md)20 § *Observability* for the full reference.212. Enable Prometheus by adding22 `[observability] prometheus_bind = "HOST:PORT"` to the broker23 TOML. The broker spawns an axum listener serving24 `text/plain; version=0.0.4` exposition.253. Scrape the listener with your Prometheus / VictoriaMetrics /26 etc. setup. Expect these 11 metric families (some are dormant27 today — registered but not yet observed):28 - `broker_rpc_seconds{op}` — RPC latency. **Dormant.**29 - `broker_cache_metadata_hits_total` — metadata-cache hits.30 - `broker_cache_object_hits_total` — object-byte-cache hits.31 - `broker_cache_object_fills_total` — object-byte-cache fills.32 - `broker_cache_evictions_total` — **dormant.**33 - `broker_authz_decisions_total{outcome}` — labels are34 `allow`, `deny`, `error`.35 - `broker_watch_fanout` (gauge) — **dormant.**36 - `broker_policy_epoch_advances_total` — increments per37 successful SIGHUP reload.38 - `broker_redirect_emissions_total{kind}` — labels are39 `read`, `write`. Increments at every fixture-driven and40 plugin-driven redirect emission site.41 - `broker_lifecycle_events_total{event}` — labels are42 `reload_ok`, `reload_failed`, `drain_start`,43 `drain_complete`.44 - `broker_uptime_seconds`.454. Pipe `grpc.health.v1.Health/Check` to your health-check probe.46 Reports `Serving` whenever backend-kind introspection on the active47 Stack succeeds. **Readiness is not flipped during drain** (the gRPC48 server stops accepting new connections via49 `serve_with_incoming_shutdown` but `Health/Check` keeps the50 last reported state until the server thread exits).515. Wire tracing. The broker uses52 `init_tracing_from_env` so the standard `RUST_LOG` /53 `OTEL_*` env vars apply. OTLP push as a `[observability]54 otlp_endpoint` field is reserved (surfaces `Unsupported` if55 set); layer `opentelemetry_otlp` onto `init_tracing_from_env`56 manually if you need it.5758## Tracing fields to collect5960Per the broker-operator persona doc:6162- `principal.id` — on every object-IO span (`broker.stat`,63 `broker.read`, `broker.write`, `broker.list`,64 `broker.list_versions`, `broker.list_address_roots`).65- `policy_epoch` — on every object-IO span and every66 `pb::ErrorDetail`.67- `object.address` — redacted via `RedactedUrl` (scheme + host +68 port + path only, no query / fragment / userinfo).69- `audit_id` — on `ReadRedirect` and `WriteRedirect` envelopes70 and on every `pb::ErrorDetail`. Freshly minted when the host's71 `RequestContext.audit_id` is `None`.72- `cache.hit`, `redirect.kind` — when applicable.73- `outcome ∈ {allow, deny, error}` — on the74 `broker_authz_decisions_total` counter.7576Fields **not** stamped today: `route.id` and `backend.id` on77per-RPC spans. Closing the gap is tracked.7879## Audit log shape (what you don't get)8081There is no `AuditRecord` / `AuditEvent` type, durable sink, or82operator-facing `explain-decision <audit-id>` tool. Diagnostic83fields land in tracing spans, error details, and redirect84envelopes only. Operators that need an audit log point a log85aggregator at the broker's tracing output and filter on86`audit_id` + `policy_epoch` + `principal.id`.8788**Sinks must redact physical URLs before logging query strings or89signed headers.** The pipeline must never log raw bearer tokens,90credential bytes, or usable signed URLs.9192## Suggested alerts9394- `rate(broker_lifecycle_events_total{event="reload_failed"}[5m]) > 0`95 — a SIGHUP reload failed validation; the old broker is still live96 on stale config.97- `rate(ovstorage_auth_decisions_total{outcome="error"}[5m]) > 0` —98 the built-in auth Layer returned evaluation errors (not denies). Check the99 active policy and listener authentication configuration.100- `broker_uptime_seconds` reset implies a restart — pair with101 `broker_policy_epoch_advances_total` to distinguish a clean102 reload-induced advance from a process crash.103- `rate(broker_redirect_emissions_total{kind="write"}[5m])` falling104 to zero on a route that previously emitted them suggests the105 plugin can no longer mint redirects (and the broker is falling106 back to inline upload, which has the 64 MiB107 `WRITE_BODY_BYTE_CAP`).108109## References110111- [`docs/public/broker-operator/README.md`](../../docs/public/broker-operator/README.md)112 § Observability — the full reference.113- [`ovstorage-operator-debug-broker`](../ovstorage-operator-debug-broker/SKILL.md) —114 using these surfaces to triage runtime issues.115- [`ovstorage-operator-configure-broker-policy`](../ovstorage-operator-configure-broker-policy/SKILL.md)116 — interpreting `broker_authz_decisions_total{outcome="deny"}`.