One reviewable config (often loaded from YAML or TOML) replaces scattered setup code and works across environments.
logging.config.dictConfig(config) builds the whole logging setup from a dictionary, the format frameworks like Django use. Keys:
version: always1.formatters: named formatters (format,datefmt,style, or()for a custom factory).filters: named filters.handlers: each withclass,level,formatter, and constructor arguments such asfilenameorstream.loggers: per-namelevel,handlers,propagate.root: the root logger's config.disable_existing_loggers: defaults to True, which disables every logger created before the call. Set it toFalsealmost always, otherwise module-level loggers created at import time go silent.
Values like "ext://sys.stdout" refer to Python objects, and "cfg://..." refers to other parts of the config. Since 3.12 a QueueHandler can be configured fully here, including its listener.
Keep the dict in a module or load it from a file (json.load, tomllib.load), apply it once at startup, and vary only the levels per environment. logging.getHandlerByName("console") (3.12+) fetches a configured handler later. The older fileConfig (INI format) still works but is less capable.
Example
import logging, logging.config
CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {"short": {"format": "%(levelname)s %(name)s: %(message)s"}},
"handlers": {
"console": {"class": "logging.StreamHandler", "level": "INFO",
"formatter": "short", "stream": "ext://sys.stdout"},
},
"loggers": {"urllib3": {"level": "WARNING"}},
"root": {"level": "DEBUG", "handlers": ["console"]},
}
logging.config.dictConfig(CONFIG)
logging.getLogger("myapp").info("configured") # INFO myapp: configured
logging.getLogger("urllib3").info("noise") # filtered by level
print(logging.getHandlerByName("console").level) # 20Remember
- dictConfig sets up formatters, handlers, loggers and root from one dict
- Set disable_existing_loggers to False
- ext:// and cfg:// reference objects and other config entries
Watch out for
- Leaving disable_existing_loggers at its default True, silencing loggers created at import time.