color_tools.logging_config
Centralized logging configuration for color_tools.
Provides a single-call setup that fans out to both a colorized console handler
(via Rich if available) and an optional rotating file handler — following the
DRY principle: one logger.info() call reaches every configured destination.
Rich is an optional dependency (pip install color-match-tools[logging]).
If Rich is not installed the module falls back to a plain StreamHandler
without raising any import errors.
Quick start:
from color_tools.logging_config import setup_logging, get_logger
# Console only (INFO+), no file
setup_logging()
# Console (DEBUG+) + rotating file
from pathlib import Path
setup_logging(log_file=Path("color_tools.log"), console_level=logging.DEBUG)
# Module-level logger (inherits handlers from setup_logging)
logger = get_logger(__name__)
logger.info("Loaded %d colors", count)
Shortcut functions for the library root logger:
from color_tools.logging_config import log_info, log_error
log_info("Processing %d colors", count)
log_error("Failed to load %s", path)
- Security note:
All log messages are sanitized to strip CR / LF / NUL characters before they reach any handler. This prevents log-injection attacks where an attacker-controlled value (e.g. a color name read from a user-supplied JSON file) could forge additional log lines.
- color_tools.logging_config.LOG_LEVEL: int = 10
Default minimum level written to the rotating file (captures everything).
- color_tools.logging_config.CONSOLE_LEVEL: int = 20
Default minimum level written to the console (only meaningful events).
- color_tools.logging_config.setup_logging(log_file=None, log_level=10, console_level=20, *, rich=None)[source]
Configure the color_tools library logger with console and optional file output.
DRY guarantee: a single
logger.info("msg")call fans out to every registered handler automatically. There is no separate “file logger” to call alongside the “console logger”.Calling this function more than once is safe: existing handlers are removed and rebuilt each time, so handler counts never accumulate.
- Parameters:
log_file (
Path|str|None) – Destination for the rotating log file. PassNone(the default) to disable file logging entirely.log_level (
int) – Minimum level for file output (default:DEBUG).console_level (
int) – Minimum level for console output (default:INFO).rich (
bool|None) –True/Falseto force-enable/disable Rich.None(default) uses Rich when it is installed.
- Return type:
- Returns:
The configured
logging.Loggerfor thecolor_toolsnamespace.
Example:
from pathlib import Path import logging from color_tools.logging_config import setup_logging # INFO+ to console, DEBUG+ to file setup_logging(log_file=Path("color_tools.log")) # Verbose console mode setup_logging(console_level=logging.DEBUG) # Force plain output even if Rich is installed setup_logging(rich=False)
- color_tools.logging_config.get_logger(name=None)[source]
Return a logger scoped under the
color_toolsnamespace.All such loggers inherit the handlers registered by
setup_logging(), so no per-module setup is required.- Parameters:
name (
str|None) – Sub-name appended tocolor_tools.. Pass__name__from the calling module for automatic hierarchy.Nonereturns the library root logger.- Return type:
- Returns:
A
logging.Loggerinstance.
Example:
# At the top of any module: from color_tools.logging_config import get_logger logger = get_logger(__name__) # e.g. "color_tools.conversions" # Use with lazy % formatting (no cost when level is disabled): logger.debug("Cache hit for key: %s", key) logger.info("Loaded %d colors", len(colors)) logger.error("Unexpected value %r", value, exc_info=True)
- color_tools.logging_config.log_debug(msg, *args, **kwargs)[source]
Log a DEBUG-level message on the color_tools root logger.
- color_tools.logging_config.log_info(msg, *args, **kwargs)[source]
Log an INFO-level message on the color_tools root logger.
- color_tools.logging_config.log_warning(msg, *args, **kwargs)[source]
Log a WARNING-level message on the color_tools root logger.