Source code for src.utils.logging
"""Structured logging configuration for Share of Search analysis."""
import logging
import sys
from pathlib import Path
from datetime import datetime
from typing import Optional
[docs]
def setup_logging(
log_level: str = "INFO",
log_file: Optional[Path] = None,
console: bool = True
) -> logging.Logger:
"""
Configure structured logging.
Args:
log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
log_file: Optional path to log file
console: Whether to output to console
Returns:
Configured logger instance
"""
logger = logging.getLogger("share_of_search")
logger.setLevel(getattr(logging, log_level.upper()))
logger.handlers.clear() # Remove any existing handlers
# Console handler with colors
if console:
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(getattr(logging, log_level.upper()))
console_formatter = ColoredFormatter(
fmt='[%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
# File handler without colors
if log_file:
log_file.parent.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setLevel(logging.DEBUG) # Always log everything to file
file_formatter = logging.Formatter(
fmt='[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
return logger
[docs]
def get_logger(name: str = "") -> logging.Logger:
"""
Get logger instance in the share_of_search hierarchy.
Args:
name: Logger name (usually __name__ from calling module)
Returns:
Logger instance that's a child of the package logger
"""
base = logging.getLogger("share_of_search")
return base.getChild(name) if name else base