Skip to content

fix(logging): stable leading-key order on every JSON line#54

Merged
trick77 merged 1 commit into
masterfrom
fix/stable-json-field-order
May 17, 2026
Merged

fix(logging): stable leading-key order on every JSON line#54
trick77 merged 1 commit into
masterfrom
fix/stable-json-field-order

Conversation

@trick77
Copy link
Copy Markdown
Owner

@trick77 trick77 commented May 17, 2026

Summary

structlog inserts user kwargs into `event_dict` before the timestamp / metadata processors run, so `logger.info("event", k=v)` ends up with `k` at position 0 — ahead of `timestamp`. Lines without kwargs (uvicorn bridge) lead with `timestamp` instead. Visible regression: the `riptide_collector_starting` line started with `"version"` while every other line started with `"timestamp"`.

All 22 structured-log call sites use the same kwargs style → all of them have the same shape problem. Adding one reorder processor at the formatter level fixes every line — uvicorn bridge, access middleware, every router — without touching call sites.

Also drops the redundant `version=version` kwarg in the lifespan call (the metadata processor already supplies it).

Test plan

  • `pytest` — 191 passed (2 new tests: chain-level reorder, end-to-end first-key-is-timestamp)
  • `ruff check` + `ruff format --check` — clean
  • `pyright src` — 0 errors
  • After merge: confirm container start emits every JSON line with `timestamp` first

structlog inserts user-supplied kwargs into event_dict before TimeStamper /
EventRenamer / the metadata processor run, which means
`logger.info("event", k=v)` produces JSON where `k` lands at position 0,
ahead of `timestamp`. Lines from the uvicorn bridge — which carry no user
kwargs — put `timestamp` first. The mixed shape is what produced the
out-of-order `riptide_collector_starting` line where `version` led:

    {"version": "0.1.0", "teams": 1, ..., "timestamp": "...", "msg": "..."}

All 22 structured-log call sites in the codebase use the same kwargs
convention so every one of them has the same problem. Adding a final
reorder processor at the formatter level catches every line — uvicorn
bridge, access middleware, every router — without per-call-site edits.

Also drop the redundant `version=__version__` kwarg in lifespan: the
metadata processor already supplies it, the kwarg was a duplicate that
landed at position 0 in the dict.

Tests:
- test_stable_leading_key_order_with_user_kwargs — unit-level: the chain
  reorders even when the caller passes kwargs that would otherwise lead.
- test_every_emitted_line_starts_with_timestamp — end-to-end: parse the
  actual JSON output of a real webhook request and assert every line
  starts with `timestamp`.
@trick77 trick77 merged commit 3862325 into master May 17, 2026
2 checks passed
@trick77 trick77 deleted the fix/stable-json-field-order branch May 17, 2026 09:16
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