Source code for cligram.logger
"""Logger setup with colored logger names using Rich markup."""
import hashlib
import logging
import time
from logging import FileHandler
from pathlib import Path
from typing import TYPE_CHECKING
from . import DEFAULT_LOGS_PATH
if TYPE_CHECKING:
pass
[docs]
class ColoredNameFormatter(logging.Formatter):
"""Logging formatter with colored logger names using Rich markup."""
# Rich color palette for logger names (distinct, readable colors)
COLORS = [
"cyan",
"magenta",
"green",
"yellow",
"blue",
"bright_cyan",
"bright_magenta",
"bright_green",
"bright_yellow",
"bright_blue",
"deep_sky_blue1",
"medium_purple",
"spring_green1",
"gold1",
"orange1",
]
def __init__(self, fmt=None, datefmt=None, style="%"):
"""Initialize the ColoredNameFormatter."""
super().__init__(fmt, datefmt, style) # type: ignore
self._color_cache = {}
def _get_color_for_name(self, name: str) -> str:
"""Get consistent color for a logger name using hash."""
if name not in self._color_cache:
# Use hash to consistently map names to colors
hash_value = int(hashlib.md5(name.encode()).hexdigest(), 16) # nosec
color_index = hash_value % len(self.COLORS)
self._color_cache[name] = self.COLORS[color_index]
return self._color_cache[name]
[docs]
def format(self, record):
"""Format the log record with colored logger name."""
# Color the logger name
original_name = record.name
color = self._get_color_for_name(original_name)
record.name = f"[{color}]{original_name}[/{color}]"
result = super().format(record)
# Restore original name
record.name = original_name
return result
[docs]
def setup_logger():
"""Set up the main logger with file handler."""
log_file = DEFAULT_LOGS_PATH / f"{_get_date()}.log"
logging.basicConfig(
level=logging.DEBUG,
)
logger = logging.getLogger()
for h in logger.handlers[:]:
logger.removeHandler(h)
h.close()
# add file handler
logger.handlers
log_path = Path(log_file)
log_path.parent.mkdir(parents=True, exist_ok=True)
fh = FileHandler(log_path, encoding="utf-8")
fh.setLevel(logging.DEBUG)
fh_formatter = logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s")
fh.setFormatter(fh_formatter)
logger.addHandler(fh)
def _add_console_handler():
# Add rich logging for console output
from rich.logging import RichHandler
logger = logging.getLogger()
console_handler = RichHandler(
markup=True,
omit_repeated_times=False,
)
console_handler.setLevel(logging.DEBUG)
console_formatter = ColoredNameFormatter("%(name)s: %(message)s")
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
def _get_date():
"""Get the current date as a string in YYYY-MM-DD format."""
return time.strftime("%Y-%m-%d", time.localtime())