Skip to content

fix(sink-pino): thread wrapper level into pino so debug records actually emit#25

Merged
dio merged 1 commit into
mainfrom
fix/pino-sink-level
May 13, 2026
Merged

fix(sink-pino): thread wrapper level into pino so debug records actually emit#25
dio merged 1 commit into
mainfrom
fix/pino-sink-level

Conversation

@dio
Copy link
Copy Markdown
Owner

@dio dio commented May 13, 2026

What

Fix createLogger({ level: "debug" }) so debug records actually reach the default pino stream. Export parseLevel and accept pino aliases (trace, fatal) so callers porting from pino do not get silence on unknown LOG_LEVEL values.

Why

Caught by @nascode while reviewing tetratelabs/fraser-auth#170. The pino sink was building its pino instance from opts?.pino ?? {} only, so opts.level never reached pino. Pino defaulted to info, the wrapper allowed debug calls through, and pino dropped them at the sink. Dev and tests lost debug output. Prod was fine because the GCP sink writes via console.log and never went through pino's level filter.

The secondary LOG_LEVEL=trace silence is a footgun in the same vein: an unsafe as Level cast lets unrecognised strings through, then shouldLog evaluates undefined >= N as false for every level, including error.

How

  • sink-pino.ts threads opts.level into pino when pino.level is not already set. Explicit pino.level still wins.
  • SinkOptions grows an optional level field so the sink can read it.
  • parseLevel is exported from both node and edge entry points. It maps trace to debug and fatal to error; other unknown values fall back to info.
  • README gains a short paragraph for each.

Verification

  • pnpm typecheck
  • pnpm build
  • pnpm test — 90 / 90 passing, 7 new tests in test/sink-pino.test.ts cover the regression and the pino aliases.
  • pnpm format:check
  • Manual repro from the issue now prints both debug-visible and info-visible.

Notes

Consumer side (fraser-auth#170) lands in a follow-up that bumps to 0.3.2 and swaps the inline as Level cast for parseLevel.

…lly emit

Closes #24

Without this, createLogger({ level: "debug" }) silently dropped debug
records on the default Node pino stream because the underlying pino
instance was constructed with no level and defaulted to info. The
wrapper-level filter let debug calls through, but pino threw them away
at the sink. GCP and edge sinks were unaffected.

Also export parseLevel and map pino aliases (trace -> debug, fatal ->
error) so consumers can validate process.env.LOG_LEVEL without an
unsafe cast and without producing total silence on unknown values.
@dio dio merged commit dfd9954 into main May 13, 2026
3 checks passed
@dio dio deleted the fix/pino-sink-level branch May 13, 2026 03:00
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