97 lines
3.2 KiB
Python
97 lines
3.2 KiB
Python
|
|
import inspect
|
||
|
|
import logging
|
||
|
|
import os
|
||
|
|
from datetime import datetime
|
||
|
|
from logging import Logger
|
||
|
|
|
||
|
|
import colorama
|
||
|
|
from colorama import Fore, Style
|
||
|
|
|
||
|
|
from texteller.globals import Globals
|
||
|
|
|
||
|
|
# Initialize colorama for colored console output
|
||
|
|
colorama.init(autoreset=True)
|
||
|
|
|
||
|
|
|
||
|
|
TEMPLATE = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||
|
|
|
||
|
|
|
||
|
|
class ColoredFormatter(logging.Formatter):
|
||
|
|
"""Custom formatter to add colors based on log level."""
|
||
|
|
|
||
|
|
FORMATS = { # noqa: E501
|
||
|
|
logging.DEBUG: Fore.LIGHTBLACK_EX + TEMPLATE + Style.RESET_ALL,
|
||
|
|
logging.INFO: Fore.WHITE + TEMPLATE + Style.RESET_ALL,
|
||
|
|
logging.WARNING: Fore.YELLOW + TEMPLATE + Style.RESET_ALL,
|
||
|
|
logging.ERROR: Fore.RED + TEMPLATE + Style.RESET_ALL,
|
||
|
|
logging.CRITICAL: Fore.RED + Style.BRIGHT + TEMPLATE + Style.RESET_ALL,
|
||
|
|
} # noqa: E501
|
||
|
|
|
||
|
|
def format(self, record):
|
||
|
|
log_fmt = self.FORMATS.get(record.levelno, self.FORMATS[logging.INFO])
|
||
|
|
formatter = logging.Formatter(log_fmt, datefmt="%Y-%m-%d %H:%M:%S")
|
||
|
|
return formatter.format(record)
|
||
|
|
|
||
|
|
|
||
|
|
def get_logger(name: str | None = None, use_file_handler: bool = False) -> Logger:
|
||
|
|
"""
|
||
|
|
Creates and configures a logger with the caller's module name (if provided) or the first two modules.
|
||
|
|
If the module name is too long, it takes the first two modules.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
name (str, optional): Custom logger name. If None, derives from caller's module.
|
||
|
|
use_file_handler (bool, optional): Whether to use a file handler. Defaults to False.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Logger: Configured logger with colored console output and file handler.
|
||
|
|
"""
|
||
|
|
# If name is not provided, derive it from the caller's module
|
||
|
|
if name is None:
|
||
|
|
# Get the caller's stack frame
|
||
|
|
frame = inspect.stack()[1]
|
||
|
|
module = inspect.getmodule(frame[0])
|
||
|
|
if module and module.__name__:
|
||
|
|
module_name = module.__name__
|
||
|
|
# Split module name and take first two components if too long
|
||
|
|
parts = module_name.split(".")
|
||
|
|
if len(parts) > 2:
|
||
|
|
name = ".".join(parts[:2])
|
||
|
|
else:
|
||
|
|
name = module_name
|
||
|
|
else:
|
||
|
|
name = "root"
|
||
|
|
|
||
|
|
# Create or get logger
|
||
|
|
logger = logging.getLogger(name)
|
||
|
|
|
||
|
|
# Prevent duplicate handlers
|
||
|
|
if logger.handlers:
|
||
|
|
return logger
|
||
|
|
|
||
|
|
# Set logger level
|
||
|
|
logger.setLevel(Globals().logging_level)
|
||
|
|
|
||
|
|
# Create console handler with colored formatter
|
||
|
|
console_handler = logging.StreamHandler()
|
||
|
|
console_handler.setLevel(Globals().logging_level)
|
||
|
|
console_formatter = ColoredFormatter()
|
||
|
|
console_handler.setFormatter(console_formatter)
|
||
|
|
logger.addHandler(console_handler)
|
||
|
|
|
||
|
|
# Create file handler
|
||
|
|
if use_file_handler:
|
||
|
|
log_dir = "logs"
|
||
|
|
os.makedirs(log_dir, exist_ok=True)
|
||
|
|
log_file = os.path.join(log_dir, f"{datetime.now().strftime('%Y%m%d')}.log")
|
||
|
|
file_handler = logging.FileHandler(log_file)
|
||
|
|
file_handler.setLevel(Globals().logging_level)
|
||
|
|
# File formatter (no colors)
|
||
|
|
file_formatter = logging.Formatter(TEMPLATE, datefmt="%Y-%m-%d %H:%M:%S")
|
||
|
|
file_handler.setFormatter(file_formatter)
|
||
|
|
logger.addHandler(file_handler)
|
||
|
|
|
||
|
|
# Prevent logger from propagating to root logger
|
||
|
|
logger.propagate = False
|
||
|
|
|
||
|
|
return logger
|