structlog

25.5.0 · active · verified Wed Mar 25

Structured logging for Python. Current version: 25.5.0 (Mar 2026). No level filtering by default — ALL log levels emitted until configured. structlog.configure() must be called before first use; loggers obtained before configure() use default settings. bind() is immutable — returns a new logger, does not mutate in place. structlog.contextvars.merge_contextvars needed for request-scoped context. stdlib interop requires ProcessorFormatter. _context attribute deprecated — use structlog.get_context().

Warnings

Install

Imports

Quickstart

structlog — configure, bind, contextvars, and event filtering.

# pip install structlog
import logging
import structlog

# Configure at app startup
structlog.configure(
    processors=[
        structlog.contextvars.merge_contextvars,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt='iso'),
        structlog.processors.JSONRenderer(),
    ],
    wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
    cache_logger_on_first_use=True,
)

log = structlog.get_logger()

# Basic structured logging
log.info('user_login', user_id='usr-123', method='oauth')
log.error('payment_failed', order_id='ord-456', reason='insufficient_funds')

# bind() — immutable, returns new logger
req_log = log.bind(request_id='req-789', ip='1.2.3.4')
req_log.info('request_received', path='/api/checkout')
req_log.info('request_completed', status=200, duration_ms=42)

# Request-scoped context via contextvars (for async/web frameworks)
structlog.contextvars.bind_contextvars(trace_id='abc123')
log.info('db_query', table='orders')  # trace_id auto-included
structlog.contextvars.clear_contextvars()

# Drop event from pipeline
def filter_health_checks(logger, method, event_dict):
    if event_dict.get('path') == '/health':
        raise structlog.DropEvent()
    return event_dict

view raw JSON →