Skip to content

v0.4.0 observability: structured JSON logs + Prometheus metrics #10

Description

@NovaLux12

Scope

After v0.3.0 reliability is in. Observability is what turns "the bridge is running" into "I can tell when something is wrong without tailing journalctl."

Items

1. Structured JSON logs

Current logger.ts emits human-readable text. Switch to JSON by default with --pretty for humans.

  • Add LOG_FORMAT=json|pretty env var, default pretty
  • JSON shape: { ts, level, msg, ...fields } (one JSON object per line)
  • Use a minimal logger (write our own, ~30 lines, no dep) — pino is overkill for this app
  • The bridge's [Bridge], [Fetch], [Token], [Proxy] prefixes should become structured fields (component: 'bridge', component: 'fetch', etc.) not text prefixes

This lets journalctl show structured fields via journalctl -o json and downstream tools (Loki, Vector) ingest cleanly.

2. Prometheus metrics endpoint

Standard /metrics endpoint on the same port as /healthz (or its own port). Exposes:

# HELP carelink_fetches_total Total fetch attempts
# TYPE carelink_fetches_total counter
carelink_fetches_total{result="success"} 42
carelink_fetches_total{result="failure"} 3

# HELP carelink_last_success_timestamp_seconds Unix timestamp of last successful fetch
# TYPE carelink_last_success_timestamp_seconds gauge
carelink_last_success_timestamp_seconds 1721305200

# HELP carelink_fetch_duration_seconds Duration of fetch attempts
# TYPE carelink_fetch_duration_seconds histogram
carelink_fetch_duration_seconds_bucket{le="1"} 30
carelink_fetch_duration_seconds_bucket{le="5"} 40
carelink_fetch_duration_seconds_bucket{le="30"} 42
  • Counters: carelink_fetches_total, carelink_uploads_total (per endpoint), carelink_token_refreshes_total
  • Gauges: carelink_last_success_timestamp_seconds, carelink_circuit_open (0/1)
  • Histograms: carelink_fetch_duration_seconds, carelink_upload_duration_seconds

Bind to 127.0.0.1:PORT/metrics. Use prom-client (~30kb, audited, well-known) OR a tiny hand-rolled prom exposition format (~80 lines).

3. Required for the above

The persistent state from v0.3.0 is the data source for the gauges; the circuit breaker is the data source for carelink_circuit_open.

Reference

  • ROADMAP.md "v0.4.0 — observability" section
  • src/logger.ts (current text logger)
  • v0.3.0 persistent state (dependency)
  • v0.3.0 circuit breaker (dependency)

Why this is v0.4.0, not earlier

Without real-data validation we can't tell what the right histograms / useful metrics are. The "interesting" failures (CareLink rate-limit responses, token refresh edge cases, Nightscout upload timeouts) all need real traffic to know how to bucket them.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions