Delete Set public Set private Add tags Delete tags
  Add tag   Cancel
  Delete tag   Cancel
  • • DevOps notes •
  •  
  • AI
  • Tags
  • Login

Declarative Logging/shaare/gWRxQw

  • python
  • python

Declarative Logging Configuration

  • Declarative configuration separates setup from code, making it easier to maintain and adjust.
  • Python’s logging.config module supports both INI-style (fileConfig) and dictionary-based (dictConfig) configurations.
  • Configuration objects can be loaded from files (INI, JSON, YAML) or defined in code.
  • Benefits include environment-specific overrides, less boilerplate, and clearer visibility of logger/handler relationships.

INI-Style Configuration with fileConfig

  • Uses an INI-format file to define loggers, handlers, and formatters.
  • Sections: [loggers], [handlers], [formatters], plus one section per named logger/handler/formatter.
  • Good for simple setups and backwards compatibility, but less flexible for dynamic structures.

Dictionary-Based Configuration with dictConfig

  • Configuration defined as a Python dict, offering full programmatic control.
  • Keys: version, disable_existing_loggers, and mappings for formatters, handlers, loggers, and optionally root.
  • Easy to build or modify at runtime, and to serialize/deserialize via JSON/YAML.

Loading Configuration from JSON or YAML

  • Store the same dict-based schema in a JSON/YAML file for external editing.
  • Read and parse the file, then pass the resulting dict to dictConfig.
  • Enables separation of concerns: ops teams can tweak logging without touching code.

Dynamic and Programmatic Adjustments

  • You can modify the config dict at runtime before calling dictConfig.
  • Handlers, formatters, and levels can be added, removed, or tweaked based on environment variables or feature flags.
  • Example: switch file logging on/off depending on a DEBUG flag.
import logging
import logging.config
import json
from typing import Any, Dict

"""
# Uncomment to test INI configuration

# Declarative logging configuration - INI-file
print("Declarative configuration using INI files")
print("---------\n")

config_path = "declarative-config.ini"

logging.config.fileConfig(
    fname=config_path,
)

app_logger = logging.getLogger("app")
app_logger.debug("INI-style fileConfig is working!")
"""

"""
# Uncomment to test Dictionary configuration

# Declarative logging configuration - Dictionary config
print("Declarative configuration using dictionary config")
print("---------\n")

dict_config: Dict[str, Any] = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "simple": {"format": "%(levelname)-8s - %(message)s"}
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "simple",
            "stream": "ext://sys.stdout",
        }
    },
    "loggers": {
        "config.dict": {
            "level": "DEBUG",
            "handlers": ["console"],
        }
    },
}

logging.config.dictConfig(dict_config)
config_logger = logging.getLogger("config.dict")
config_logger.debug("dictConfig setup successfully")
config_logger.info("Info goes to console")
"""

"""
# Uncomment to test JSON configuration

# Declarative logging configuration - JSON config
print("Declarative configuration using JSON config")
print("---------\n")

config_path = "declarative-config.json"

with open(config_path, "r") as config_file:
    json_config = json.load(config_file)

logging.config.dictConfig(json_config)
config_logger = logging.getLogger("config.json")
config_logger.debug("JSON config setup successfully")
config_logger.info("Info goes to console")
"""

# Dynamically building config
print("Dynamically building config")
print("---------\n")

base_config: Dict[str, Any] = {
    "version": 1,
    "disable_existing_loggers": True,
    "handlers": {},
    "formatters": {},
    "loggers": {},
}

base_config["formatters"]["simple"] = {
    "format": "%(levelname)-8s - %(message)s"
}

base_config["handlers"]["console"] = {
    "class": "logging.StreamHandler",
    "level": "DEBUG",
    "formatter": "simple",
    "stream": "ext://sys.stdout",
}

base_config["loggers"]["config.dynamic"] = {
    "level": "WARNING",
    "handlers": ["console"],
}

def is_debug():
    return True

if is_debug():
    for logger, _config in base_config["loggers"].items():
        base_config["loggers"][logger]["level"] = "DEBUG"

logging.config.dictConfig(base_config)
config_logger = logging.getLogger("config.dynamic")
config_logger.debug("Dynamic config setup successfully")
config_logger.info("Info goes to console")

Example of declarative-config.ini

[loggers]
keys=root,app

[handlers]
keys=consoleHandler,nullHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=INFO
handlers=consoleHandler

[logger_app]
level=DEBUG
handlers=nullHandler
qualname=app

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_nullHandler]
class=NullHandler
level=NOTSET
formatter=
args=()

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)-8s - %(message)s

Example of declarative-config.json

{
  "version": 1,
  "disable_existing_loggers": false,
  "formatters": {
    "simple": { "format": "%(levelname)-8s - %(message)s" },
    "detailed": {
      "format": "%(asctime)s %(name)s [%(levelname)s]: %(message)s",
      "datefmt": "%Y-%m-%d %H:%M:%S"
    }
  },
  "handlers": {
    "console": {
      "class": "logging.StreamHandler",
      "level": "INFO",
      "formatter": "detailed",
      "stream": "ext://sys.stdout"
    }
  },
  "loggers": {
    "config.json": {
      "level": "DEBUG"
    }
  },
  "root": {
    "level": "DEBUG",
    "handlers": ["console"]
  }
}
1 month ago Permalink
cluster icon
  • Mocking : Mocking Fundamentals Introduction When unit testing DevOps scripts that interact with external systems, tests can become slow, unreliable, difficult ...
  • Typing : Introduction Python is a dynamically typed language, meaning you can assign values to variables without declaring their types, and type checking happ...
  • Dictionaries : Dictionaries (dict) Dictionaries are mutable, insertion-ordered collections of key-value pairs. Keys must be unique and immutable; values can be of an...
  • Working with JSON files : Working with JSON files JSON is the standard format for data exchange in web services and cloud APIs. Python’s built-in json module provides function...
  • Generics typing : Introduction to Generics Generic types let you write reusable, type-safe functions and classes that work uniformly across different data types. They ...


(97)
Filter untagged links
Fold Fold all Expand Expand all Are you sure you want to delete this link? Are you sure you want to delete this tag? The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community