Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Observability

Every Parsec deployment exposes three streams: Prometheus metrics at /metrics, OpenTelemetry traces to an OTLP collector, and structured access logs through slog.

The defaults are operator-friendly: metrics are always on; tracing is off until you set an endpoint; the access log uses the Logger you pass into parsec.Options (or slog.Default() if none).

Metrics

Scraping /metrics

The route is mounted on the same HTTP mux as everything else. Set Options.MetricsBearerToken to require Authorization: Bearer <token> on every scrape; leave it empty to run unguarded (firewall the route at the network layer in that case).

curl -H "Authorization: Bearer $METRICS_TOKEN" \
     http://parsec.internal:8000/metrics

The registry includes Go runtime + process collectors by default. To share a registry with the rest of your service, pass Options.MetricsRegistry.

Metric reference

MetricTypeLabelsSource
parsec_publishes_totalcounterchannel_visibility, resultevery Publish call
parsec_publish_duration_secondshistogramchannel_visibilityevery Publish call
parsec_subscribers_activegaugechannel_visibilitybroker subscribe / unsubscribe hooks
parsec_channels_activegaugestate, visibilitysweeper, after every tick
parsec_token_verifications_totalcountertype, resultevery Verifier.Verify
parsec_sink_attempts_totalcountersink, resultevery sink Send
parsec_sink_duration_secondshistogramsinkevery sink Send
parsec_dlq_sizegaugesinkperiodic scrape (sweep interval)
parsec_key_rotations_totalcounteractionGenerateKey / PromoteKey / RetireKey
parsec_rpc_requests_totalcountermethod, statusHTTP middleware (last URL segment)
parsec_rpc_duration_secondshistogrammethodHTTP middleware

result values are success or failure. channel_visibility is public or private (or unknown for the rare race where a name has not been parsed). action for key_rotations_total is one of generated, promoted, retired.

Cardinality contract

Channel names, subject IDs, and bearer tokens are never labels. The label set is bounded by:

  • channel_visibility ∈ {public, private, unknown}
  • result ∈ {success, failure}
  • type ∈ {access, refresh, mgmt, unknown}
  • sink — bounded by the registered sink registry (3 in the default build)
  • state ∈ {open, closed, deleted}
  • method — the last URL segment of a /twirp/parsec.ParsecService/ path; anything outside the prefix is collapsed to the literal non_rpc

If you add a new subsystem with internal state, add a metric or document why none is needed (see CLAUDE.md Update Demand).

Tracing

Set Options.OTLPEndpoint to enable the OTLP HTTP exporter:

parsec.Options{
    OTLPEndpoint: "otel-collector.observability:4318",
}

When the endpoint is empty (the default), internal/tracing.NewTracer returns a no-op tracer that performs no allocations. There is no runtime cost to leaving tracing off.

The service name is baked in as parsec. The exporter uses insecure transport — terminate TLS at your collector or run a sidecar.

Each RPC request gets a server span; sub-spans for token verification, broker publish, and sink delivery are emitted by the corresponding subsystems. Trace context propagates via standard W3C headers — Parsec is a participant, not an originator.

Access logs

The HTTP surface emits one slog INFO line per request:

{
  "time": "2026-05-22T14:03:11.123Z",
  "level": "INFO",
  "msg": "http_request",
  "method": "POST",
  "path": "/twirp/parsec.ParsecService/Publish",
  "status": 200,
  "duration_ms": 7,
  "remote_addr": "203.0.113.42",
  "request_id": "f9e3c0d1...",
  "bearer_subject": "ops-alice",
  "trace_id": "9c5f1a..."
}

Failed token verifications emit a WARN line with a PARSEC_AUTH_* code; the token contents are never logged:

{
  "level": "WARN",
  "msg": "auth_failure",
  "code": "PARSEC_AUTH_EXPIRED",
  "request_id": "f9e3c0d1..."
}

Trusting X-Forwarded-For

Options.TrustedProxies is the list of CIDRs Parsec will honor an X-Forwarded-For chain from. If the immediate TCP peer is not in the list, XFF is ignored and the TCP peer is logged. This prevents any unauthenticated client from spoofing their IP by setting a header.

_, lb, _ := net.ParseCIDR("10.0.0.0/8")
opts := parsec.Options{
    TrustedProxies: []net.IPNet{*lb},
}

Request IDs

The middleware honors X-Request-ID when the client provides one and generates a fresh 24-character hex value otherwise. The chosen ID is echoed back in the response so clients can correlate.

Grafana dashboard

A starter dashboard JSON lives at examples/grafana/parsec-overview.json. It includes panels for:

  • publish rate by visibility
  • sink success ratio
  • active channel inventory
  • token verification failures
  • key rotation activity

Import via the Grafana UI (Dashboards → Import → Upload JSON).

Telemetry alerts and Prometheus exposition

The aggregated /parsec/metrics JSON view can also surface declarative alert firings and a parallel Prometheus text exposition for external scraping. See Telemetry Alerts & Prometheus Exposition for the rule shape, metric reference, and AlertManager wiring.