Skip to content

feat(worker): ship trace-stamped log lines to Loki, dark by default#87

Closed
xBalbinus wants to merge 2 commits into
mainfrom
feat/worker-loki-logs
Closed

feat(worker): ship trace-stamped log lines to Loki, dark by default#87
xBalbinus wants to merge 2 commits into
mainfrom
feat/worker-loki-logs

Conversation

@xBalbinus

Copy link
Copy Markdown

What

Ship the worker's (and DOs') trace-stamped JSON log lines to Loki, dark by default — today log.warn/log.info lines are visible only in wrangler tail; verified 2026-07-06 that no valet service exists in Loki, so e.g. #70/#82's integration auth/refresh failed warns are invisible in Grafana.

Design

  • lib/log.ts emit() additionally buffers each line (bounded 500; oldest dropped + drop-count reported as a synthetic warn on next flush) when LOKI_PUSH_URL is configured; unconfigured cost = one boolean check, console output byte-identical (tail unaffected)
  • flushLogs() POSTs Loki push payloads (service_name + level labels, ns timestamps, line = the exact JSON incl. trace_id/span_id → trace↔log correlation in Grafana)
  • Flush drivers: Hono middleware (waitUntil after response), the DOs' existing trace-flush drivers, and the scheduled handler (cron lines would otherwise sit buffered)
  • Failed pushes drop the batch (counted), mirroring the fire-and-forget OTLP trace exporter

Evidence

  • Live e2e against local grafana/otel-lgtm: real worker under wrangler dev/health traffic → Loki query_range returns the lines with trace_id present
  • Worker suite 95 files / 1245 tests green (2 new for drop accounting); root typecheck green (review caught a TS2352 in the new test — fixed)

To turn it on

Needs a logs:write token + the stack's Loki instance ID from Paul — this is not the existing traces token (410780 is the Tempo push instance). Set LOKI_PUSH_URL + LOKI_BASIC_AUTH as worker secrets. Docs: docs/observability.md § Log shipping to Loki (includes the local otel-lgtm test recipe).

xBalbinus added 2 commits July 6, 2026 16:32
Structured log lines from lib/log.ts were console-only — visible in
wrangler tail but absent from Grafana, so trace<->log pivoting on
trace_id never worked in Loki. Buffer each emitted line (bounded at 500,
oldest dropped and reported as dropped_total on the next flush) and push
batches to {LOKI_PUSH_URL}/loki/api/v1/push labeled {service_name,
level}, keeping console output byte-identical.

Workers have no cross-request timers, so flushing rides existing
lifecycle hooks via waitUntil: a Hono middleware on the fetch path, the
end of the scheduled tick, and the DOs' flushTraces drivers
(alarm/close/hibernate) — no new flush sites. Unset LOKI_PUSH_URL costs
one boolean per line and zero network; push failures are swallowed
(single console.warn, batch counted dropped) like the trace exporter.
…nting

Review fixes on the Loki log-shipping branch:
- log.test.ts cast '[]' -> tuple via unknown (TS2352 failed 'tsc --build',
  the CI typecheck gate, even though vitest passed)
- flushLogs now ships a pending drop report even when the buffer is empty,
  so drops from a failed final push are visible in Loki, not just console
- a failed push no longer re-counts the synthetic report line in
  dropped_total, and drops whose report line was lost are re-reported
- docs: drop the verbatim Tempo push instance ID; the warning reads the
  same without committing an internal account identifier
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Preview deployment: https://pr-87.dev-valet-turnkey-client.pages.dev

@xBalbinus

Copy link
Copy Markdown
Author

Consolidated into #86 (observability rails) — the branch was merged there with full history (signed merge commit); all tests re-run green on the combined branch.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant