Skip to content

Configuration (dictConfig, fileConfig)

Configure logging using dictConfig for Python dicts or fileConfig for configuration files.

Mental Model

Logging configuration wires together three things: loggers (who emits), handlers (where it goes), and formatters (how it looks). dictConfig lets you declare all three in a single dictionary, applied once at startup. This separates "what to log" in your code from "how to deliver it" in configuration — so you can redirect output without touching a single log call.

dictConfig - Dictionary Configuration

Configure logging with a dictionary.

```python import logging.config

config = { 'version': 1, 'formatters': { 'standard': { 'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s' } }, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'formatter': 'standard', 'level': 'INFO' } }, 'loggers': { 'myapp': { 'handlers': ['console'], 'level': 'DEBUG' } } }

logging.config.dictConfig(config) logger = logging.getLogger('myapp') logger.info("Application started") ```

2026-02-12 12:34:56,789 - myapp - INFO - Application started

fileConfig - Configuration File

Configure logging from an INI file.

```python import logging.config import tempfile import os

Create temporary config file

config_content = '''[loggers] keys=root,myapp

[handlers] keys=console

[formatters] keys=standard

[logger_root] level=WARNING handlers=console

[logger_myapp] level=DEBUG handlers=console qualname=myapp

[handler_console] class=StreamHandler level=DEBUG formatter=standard args=(sys.stdout,)

[formatter_standard] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s '''

Write config to temp file

with tempfile.NamedTemporaryFile(mode='w', suffix='.conf', delete=False) as f: f.write(config_content) config_path = f.name

try: logging.config.fileConfig(config_path) logger = logging.getLogger('myapp') logger.info("Configured from file") finally: os.unlink(config_path) ```

2026-02-12 12:34:56,789 - myapp - INFO - Configured from file


Exercises

Exercise 1. Create a dictConfig configuration that sets up two handlers: a StreamHandler for WARNING and above, and a simulated FileHandler for DEBUG and above. Both should use different formatters. Apply the configuration and test by logging messages at DEBUG, INFO, and WARNING levels.

Solution to Exercise 1

```python import logging import logging.config

config = { "version": 1, "formatters": { "brief": {"format": "%(levelname)s: %(message)s"}, "detailed": { "format": "%(asctime)s %(name)s %(levelname)s %(message)s" }, }, "handlers": { "console": { "class": "logging.StreamHandler", "level": "WARNING", "formatter": "brief", }, "file": { "class": "logging.StreamHandler", # Using stream for demo "level": "DEBUG", "formatter": "detailed", }, }, "root": { "level": "DEBUG", "handlers": ["console", "file"], }, }

logging.config.dictConfig(config) logger = logging.getLogger() logger.debug("Debug message") # Only in 'file' handler logger.warning("Warning message") # In both handlers ```


Exercise 2. Write a function configure_from_dict that takes a dictionary with keys "level", "format", and "filename" (optional), and returns a properly configured logger using logging.config.dictConfig. If "filename" is provided, log to a file; otherwise, log to the console.

Solution to Exercise 2

```python import logging import logging.config

def configure_from_dict(settings): handler_config = { "class": "logging.StreamHandler", "level": settings.get("level", "INFO"), "formatter": "default", } if "filename" in settings: handler_config["class"] = "logging.FileHandler" handler_config["filename"] = settings["filename"]

config = {
    "version": 1,
    "formatters": {
        "default": {
            "format": settings.get(
                "format", "%(levelname)s - %(message)s"
            )
        }
    },
    "handlers": {"main": handler_config},
    "root": {
        "level": settings.get("level", "INFO"),
        "handlers": ["main"],
    },
}
logging.config.dictConfig(config)
return logging.getLogger()

Test

logger = configure_from_dict({"level": "DEBUG", "format": "%(message)s"}) logger.info("Hello from configured logger") ```


Exercise 3. Write a logging configuration that creates a logger hierarchy: a root logger at WARNING, a "myapp" logger at INFO, and a "myapp.debug" logger at DEBUG. Demonstrate that each logger only processes messages at or above its configured level.

Solution to Exercise 3

```python import logging

Root logger

logging.basicConfig(level=logging.WARNING, format="%(name)s - %(levelname)s - %(message)s")

App logger

app_logger = logging.getLogger("myapp") app_logger.setLevel(logging.INFO)

Debug logger

debug_logger = logging.getLogger("myapp.debug") debug_logger.setLevel(logging.DEBUG) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter("%(name)s - %(levelname)s - %(message)s")) debug_logger.addHandler(handler)

debug_logger.debug("Debug detail") # Shown (DEBUG level) app_logger.info("App info") # Shown (INFO level) logging.warning("Root warning") # Shown (WARNING level) ```