Summary
WH_LOG_LEVEL filters only the stdout handler. The OTLP log leg has no level filter, so DEBUG/INFO records are still built and exported when the level is WARN — the docs say it applies to both.
Detail
internal/observability/logger.go:64-89: the slog.LevelVar is passed only into the stdout HandlerOptions. The otelslog handler has no level filter, and neither slogmulti.Fanout nor the sdk/log Logger (no FilterProcessor on the BatchProcessor) drops sub-level records. Fanout.Handle checks per-handler Enabled, so stdout stays correctly filtered — only the OTLP leg leaks.
Docs (docs/src/content/docs/configuration.mdx:210) state WH_LOG_LEVEL "Applies to both stdout and (when OTel is enabled) the OTLP log exporter."
Impact
With OTLP logs enabled, WH_LOG_LEVEL=WARN still exports every DEBUG/INFO record at otel.logs.sample_rate (default 1.0) — unexpected collector cost/noise plus hot-path record-building overhead. (The intentional WARN+ 100% floor from invariant #15 is unaffected.)
Fix direction
Wrap the OTLP log path in a level filter tied to the same LevelVar (e.g. an slog level gate before the sampler, or a log-SDK processor), or fix the docs to match.
Found in a repo-wide audit; verified by code trace.
Summary
WH_LOG_LEVELfilters only the stdout handler. The OTLP log leg has no level filter, so DEBUG/INFO records are still built and exported when the level is WARN — the docs say it applies to both.Detail
internal/observability/logger.go:64-89: theslog.LevelVaris passed only into the stdoutHandlerOptions. Theotelsloghandler has no level filter, and neitherslogmulti.Fanoutnor the sdk/logLogger(noFilterProcessoron theBatchProcessor) drops sub-level records.Fanout.Handlechecks per-handlerEnabled, so stdout stays correctly filtered — only the OTLP leg leaks.Docs (
docs/src/content/docs/configuration.mdx:210) stateWH_LOG_LEVEL"Applies to both stdout and (when OTel is enabled) the OTLP log exporter."Impact
With OTLP logs enabled,
WH_LOG_LEVEL=WARNstill exports every DEBUG/INFO record atotel.logs.sample_rate(default 1.0) — unexpected collector cost/noise plus hot-path record-building overhead. (The intentional WARN+ 100% floor from invariant #15 is unaffected.)Fix direction
Wrap the OTLP log path in a level filter tied to the same
LevelVar(e.g. ansloglevel gate before the sampler, or a log-SDK processor), or fix the docs to match.Found in a repo-wide audit; verified by code trace.