ReMe/reme/core/utils/std_logger.py
zouyingcao e5bb845196
refactor(cli): using AgentScope components to reimplement the reme_cli logic (#153)
* add: as_token_counters config for reme_cli

* add: reme_cli function

* update: format the terminal printing for reme_cli

* update: check for pre-commit

* single quotes for the inner dictionary keys

* update the usage of get_std_logger for pre-commit

* update the usage of get_std_logger for pre-commit

* add 'console_enabled' param in compactor&summarizer
2026-03-12 11:23:36 +08:00

122 lines
4 KiB
Python

"""Standard logging module configuration with loguru-like features."""
import logging
import os
import sys
from datetime import datetime
from logging.handlers import TimedRotatingFileHandler
# Store created logger instances
_loggers: dict[str, logging.Logger] = {}
class CustomFormatter(logging.Formatter):
"""Custom formatter with colorized output support."""
# ANSI color codes
COLORS = {
logging.DEBUG: "\033[36m", # Cyan
logging.INFO: "\033[32m", # Green
logging.WARNING: "\033[33m", # Yellow
logging.ERROR: "\033[31m", # Red
logging.CRITICAL: "\033[35m", # Magenta
}
RESET = "\033[0m"
def __init__(self, fmt: str, colorize: bool = False):
super().__init__(fmt)
self.colorize = colorize
def format(self, record: logging.LogRecord) -> str:
# Add custom attribute: simplified filename and line number
record.file_line = f"{record.filename}:{record.lineno}"
if self.colorize:
color = self.COLORS.get(record.levelno, self.RESET)
record.levelname = f"{color}{record.levelname}{self.RESET}"
return super().format(record)
def get_loggerv2(
name: str = "reme",
log_dir: str = "logs",
level: str = "INFO",
log_to_console: bool = True,
log_to_file: bool = True,
log_file_prefix: str = "reme",
rotation: str = "midnight",
retention_days: int = 7,
force_update: bool = False,
) -> logging.Logger:
"""Get a configured logger instance.
Args:
name: Logger name for distinguishing different loggers.
log_dir: Directory path for log files.
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL).
log_to_console: Whether to output logs to console.
log_to_file: Whether to output logs to file.
log_file_prefix: Prefix for log file names (e.g., 'reme' -> 'reme_2024-01-01.log').
rotation: Log rotation time, defaults to midnight.
retention_days: Number of days to retain log files.
force_update: Whether to force update the logger configuration even if it already exists.
Returns:
Configured Logger instance.
"""
# Return existing logger if already created and not force updating
if name in _loggers and not force_update:
return _loggers[name]
# Create new logger without using root logger
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, level.upper(), logging.INFO))
logger.propagate = False # Do not propagate to root logger
# Clear existing handlers
logger.handlers.clear()
# Log format
log_format = "%(asctime)s | %(levelname)s | %(file_line)s | %(funcName)s | %(message)s"
# Configure file logging
if log_to_file:
try:
os.makedirs(log_dir, exist_ok=True)
current_ts = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
log_filename = f"{log_file_prefix}_{current_ts}.log"
log_filepath = os.path.join(log_dir, log_filename)
file_handler = TimedRotatingFileHandler(
log_filepath,
when=rotation,
interval=1,
backupCount=retention_days,
encoding="utf-8",
)
file_handler.setLevel(getattr(logging, level.upper(), logging.INFO))
file_handler.setFormatter(CustomFormatter(log_format, colorize=False))
file_handler.suffix = "%Y-%m-%d"
logger.addHandler(file_handler)
except Exception as e:
logger.error(f"Error configuring file logging: {e}")
# Configure console logging
if log_to_console:
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(getattr(logging, level.upper(), logging.INFO))
console_handler.setFormatter(CustomFormatter(log_format, colorize=True))
logger.addHandler(console_handler)
# Cache logger
_loggers[name] = logger
return logger
def get_logger():
"""Get a configured logger instance using loguru."""
from loguru import logger
return logger