Structlog Contextual Bound Logging

Bind request-scoped context with structlog, so every log line carries correlation fields without threading state through call stacks.

PythonResilience

Code

snippet
import logging
import uuid

import structlog

structlog.configure(
    processors=[
        structlog.contextvars.merge_contextvars,
        structlog.processors.add_log_level,
        structlog.processors.TimeStamper(fmt='iso'),
        structlog.processors.JSONRenderer(),
    ],
    wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
    logger_factory=structlog.PrintLoggerFactory(),
)

logger = structlog.get_logger()


def charge_order(order_id: str, amount: int) -> None:
    logger.info('charge_started', order_id=order_id, amount=amount)
    try:
        if amount > 100_000:
            raise ValueError('amount exceeds single-charge limit')
    except ValueError:
        logger.exception('charge_rejected', order_id=order_id)
        raise


def handle_request(request_id: str, order: dict) -> None:
    structlog.contextvars.bind_contextvars(
        request_id=request_id,
        tenant=order['tenant'],
    )
    charge_order(order['id'], order['amount'])


handle_request(
    request_id=str(uuid.uuid4())[:8],
    order={'id': 'ord-91', 'tenant': 'acme', 'amount': 250_000},
)