Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsUse extra to attach a field to one logging call, LoggerAdapter to reuse context across calls, a filter to enrich records at a logger or handler, or a LogRecord factory to add fields as records are created. In every case, the formatter must know about the field, and every record reaching it must provide that field.
How custom logging attributes work
Python logging creates a LogRecord for each event. Custom attributes let you attach useful context—such as a request, tenant, or job ID—to that record and include it in formatted output. The logging cookbook explains that values passed through extra are merged into the record, so a formatter can reference them by name: Python Logging Cookbook.
Choose the narrowest mechanism that covers the records that need the value: extra for an individual event, an adapter for a group of calls, a filter for a logger or handler boundary, or a factory for attributes broadly added at record creation.
Add an attribute to one logging call with extra
Pass a dictionary to the extra parameter, then reference its key in the formatter:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
import logging
logging.basicConfig(
format="%(levelname)s %(message)s [request_id=%(request_id)s]",
level=logging.INFO,
)
logger = logging.getLogger(__name__)
logger.info("Request received", extra={"request_id": "req-123"})
The mapping’s values become attributes on that call’s LogRecord; %(request_id)s inserts the value when the formatter renders the message. Use stable, application-specific names such as request_id, tenant_id, or job_id. Do not use names that collide with built-in record attributes such as name, levelname, or message. The standard record fields are listed in the LogRecord attributes reference.
Make sure every formatted record has the field
If a formatter refers to %(request_id)s but a record reaching it has no request_id, formatting can fail. This commonly happens when only some calls provide extra but the same handler formats all records. Ensure the field is supplied consistently, or choose an enrichment method that covers all records reaching that formatter.
Rank #2
Reuse context across calls with LoggerAdapter
When several log calls share the same context, wrap the logger with a LoggerAdapter instead of repeating the same mapping:
import logging
logger = logging.getLogger(__name__)
request_logger = logging.LoggerAdapter(logger, {"request_id": "req-123"})
request_logger.info("Request received")
request_logger.warning("Request is taking longer than expected")
The adapter routes calls through the underlying logger and supplies its context as extra. This is useful for a request or job that generates multiple log events. Avoid creating a separate logger for every connection or request: logger instances are not garbage-collected, so an unbounded set is difficult to manage. The cookbook describes adapter use and its default context behavior in the Logging Cookbook.
Adapter context and per-call extra
With the documented default behavior, an adapter’s context replaces a caller-provided extra mapping. If a call needs both adapter-level context and its own fields, check the behavior for your Python version and implement an intentional merge strategy rather than assuming the mappings combine automatically.
Enrich records at a logger or handler with a filter
A filter can add, change, or remove attributes for records processed where it is installed. A handler-level filter is useful when only that handler’s output should receive the field:
import logging
class RequestContextFilter(logging.Filter):
def filter(self, record):
record.request_id = current_request_id()
return True
handler = logging.StreamHandler()
handler.addFilter(RequestContextFilter())
handler.setFormatter(logging.Formatter(
"%(levelname)s %(message)s [request_id=%(request_id)s]"
))
Install a filter on a logger or handler according to which records need enrichment. A handler filter applies at that handler’s processing point, so another handler will not automatically receive its changes. See the filter reference for the API.
Python 3.12 replacement-record behavior
Starting in Python 3.12, a filter may return a replacement LogRecord. A handler filter can use this to change the record emitted by that handler without mutating the original record that other handlers may process. Do not rely on replacement-record behavior when running an earlier Python version.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallBest Value
Add attributes when records are created with a factory
A custom LogRecord factory can attach a field broadly at record creation time. Chain the existing factory so its behavior is preserved:
import logging
old_factory = logging.getLogRecordFactory()
def record_factory(*args, **kwargs):
record = old_factory(*args, **kwargs)
record.application = "billing"
return record
logging.setLogRecordFactory(record_factory)
Use this for values that belong on records broadly, rather than for context needed only by a particular handler. Avoid replacing standard attributes or fields another factory already sets. Chaining factories adds runtime work to logging calls; the cookbook recommends a filter when it can achieve the same result. See the LogRecord factory reference.
Choose the right method
| Need | Mechanism | Key consideration |
|---|---|---|
| One custom value on one event | extra |
Include the key in the formatter and supply it for every record that uses that format. |
| Shared context across a group of calls | LoggerAdapter |
By default, adapter context replaces call-level extra. |
| Context at one logger or handler boundary | Filter |
Placement determines which records are enriched; replacement-record returns require Python 3.12 or later. |
| An attribute on records at creation time | LogRecord factory | Chain the existing factory and account for added runtime work. |
For request IDs on only selected calls, start with extra. When many calls in one request share the same value, use an adapter. Use a filter when enrichment belongs at a specific processing boundary, and a factory only when the attribute should be added broadly as records are created.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

