DOC: contextflo
STATUS: ● PUBLISHED
SYSTEM CONTEXTFLOW

structlog Is Not logging: The %s Trap

Two logging APIs that look identical and behave completely differently.

Cover image — structlog Is Not logging: The %s Trap

Log lines came out with %s placeholders left unformatted, and in some cases the logging call raised a TypeError instead of logging anything. The cause was muscle memory: writing structlog calls in the logging style.

// 01 — THE SETUP

The project standardized on structlog for structured, JSON-able logs across every module. But in places, the code had been written with the standard-library logging signature.

// 02 — THE SYMPTOM

log.info("processed %s chunks", count)

Output showed a literal processed %s chunks with no substitution, or threw a TypeError when the processor chain tried to handle the printf markers. The logs were either wrong or fatal.

// 03 — THE CULPRIT

The two APIs look the same and aren’t. Standard logging does lazy printf-style interpolation: log.info("processed %s", count) substitutes %s later. structlog expects structured keyword arguments like log.info("event_name", count=count) and treats the first argument as an event key, not a format string. Hand structlog a %s string and there’s nothing to interpolate it; the marker survives to the output, or trips the processor chain.

// 04 — THE FIX

Convert every call to the structured form across all modules:

# before (logging style)
log.info("processed %s chunks for %s", count, source)
# after (structlog style)
log.info("chunks_processed", count=count, source=source)

This is also strictly better: count and source are now queryable fields in the JSON output, not baked into a string.

TAKEAWAYS

NEXT

@frogwebp brand mark
ANTHONY PENA · @FROGWEBP
I build data systems and write about everything around them, the architecture, the failures, what each one teaches me. Documenting in public since 2021: the process, not just the result.

// NEWSLETTER — THE BUILD LOG SIGNAL

When I ship something or learn something worth keeping, it lands here first — build logs, concepts, and the honest process behind them. Come along; no spam, leave anytime.