The library provides ContextualLogFilter, a logging.Filter subclass that
automatically injects the current correlation ID and user ID into log records.
This allows standard logging.Formatter format strings to include
%(correlation_id)s and %(user_id)s without any manual per-call effort.
When a context variable is not set (for example, outside a request), the
placeholder string "-" is used instead. If the record already carries the
attribute (e.g. attached via extra= or a LoggerAdapter), the existing value
is preserved and the filter does not overwrite it.
Basic usage
Attach the filter to a handler or logger:
import logging
from falcon_correlate import ContextualLogFilter
handler = logging.StreamHandler()
handler.addFilter(ContextualLogFilter())
handler.setFormatter(
logging.Formatter(
"%(asctime)s [%(correlation_id)s] [%(user_id)s] %(name)s - %(message)s"
)
)
logger = logging.getLogger("myapp")
logger.addHandler(handler)
logger.setLevel(logging.INFO)
Recommended format string
The library exports RECOMMENDED_LOG_FORMAT, a ready-made format string that
includes a timestamp, log level, correlation ID, user ID, logger name, and
message:
from falcon_correlate import RECOMMENDED_LOG_FORMAT
# Value:
# "%(asctime)s - [%(levelname)s] - [%(correlation_id)s] - "
# "[%(user_id)s] - %(name)s - %(message)s"
This produces output like:
2026-02-25 14:30:00,123 - [INFO] - [abc123] - [user42] - myapp - Handling request
Use it with a handler:
import logging
from falcon_correlate import ContextualLogFilter, RECOMMENDED_LOG_FORMAT
handler = logging.StreamHandler()
handler.addFilter(ContextualLogFilter())
handler.setFormatter(logging.Formatter(RECOMMENDED_LOG_FORMAT))
logger = logging.getLogger("myapp")
logger.addHandler(handler)
logger.setLevel(logging.INFO)
The constant is provided as a convenience; callers may supply a custom format string if the recommended layout does not suit their needs.
Using `dictConfig`
For applications that configure logging via logging.config.dictConfig, the
filter can be referenced by its dotted path:
import logging.config
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"filters": {
"contextual": {
"()": "falcon_correlate.ContextualLogFilter",
},
},
"formatters": {
"standard": {
"format": (
"%(asctime)s [%(levelname)s] [%(correlation_id)s] "
"[%(user_id)s] %(name)s: %(message)s"
),
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "standard",
"filters": ["contextual"],
},
},
"root": {
"handlers": ["console"],
"level": "INFO",
},
}
logging.config.dictConfig(LOGGING_CONFIG)
Placeholder behaviour
When the correlation ID or user ID context variable is not set, the filter
substitutes the string "-" on the log record. This ensures that format
strings referencing %(correlation_id)s or %(user_id)s never raise a
KeyError and produce clean output even outside request handling:
2026-02-23 12:00:00 [INFO] [-] [-] myapp: Application started
2026-02-23 12:00:01 [INFO] [abc123] [user42] myapp: Handling request
Preserving explicit metadata
The filter only fills in attributes that are missing from the record. If a
caller already attached correlation_id or user_id via extra= or a
LoggerAdapter, the filter preserves those values. This is useful for
background jobs or other non-request code paths that want to supply their own
traceability IDs:
logger.info(
"Running background job",
extra={"correlation_id": "job-abc-123"},
)
# The filter will NOT overwrite "job-abc-123" with the contextvar
# value (or the "-" placeholder).