80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
"""Loguru logging configuration."""
|
|
import sys
|
|
import logging
|
|
import inspect
|
|
from loguru import logger
|
|
from pathlib import Path
|
|
from .config import Config
|
|
|
|
# Remove default logger
|
|
logger.remove()
|
|
|
|
# Add console handler with color
|
|
logger.add(
|
|
sys.stderr,
|
|
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
|
level="DEBUG" if Config.DEBUG else "INFO",
|
|
colorize=True,
|
|
)
|
|
|
|
# Add file handler with rotation
|
|
log_dir = Path("logs")
|
|
log_dir.mkdir(exist_ok=True)
|
|
|
|
logger.add(
|
|
log_dir / "server_{time:YYYY-MM-DD}.log",
|
|
rotation="00:00", # Rotate at midnight
|
|
retention="30 days", # Keep logs for 30 days
|
|
compression="zip", # Compress old logs
|
|
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}",
|
|
level="DEBUG",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
# Add error file handler
|
|
logger.add(
|
|
log_dir / "error_{time:YYYY-MM-DD}.log",
|
|
rotation="00:00",
|
|
retention="90 days",
|
|
compression="zip",
|
|
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}",
|
|
level="ERROR",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
# Configure uvicorn logging to use loguru
|
|
class InterceptHandler(logging.Handler):
|
|
"""Intercept standard logging messages toward loguru."""
|
|
|
|
def emit(self, record: logging.LogRecord) -> None:
|
|
# Get corresponding Loguru level if it exists
|
|
try:
|
|
level = logger.level(record.levelname).name
|
|
except ValueError:
|
|
level = str(record.levelno)
|
|
|
|
# Find caller from where originated the logged message
|
|
frame, depth = inspect.currentframe(), 2
|
|
while frame and frame.f_code.co_filename == logging.__file__:
|
|
frame = frame.f_back
|
|
depth += 1
|
|
|
|
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
|
|
|
|
|
|
def setup_logging():
|
|
"""Configure logging for the application."""
|
|
# Intercept uvicorn and fastapi loggers
|
|
logging.getLogger("uvicorn").handlers = [InterceptHandler()]
|
|
logging.getLogger("uvicorn.access").handlers = [InterceptHandler()]
|
|
logging.getLogger("fastapi").handlers = [InterceptHandler()]
|
|
|
|
# Set log levels
|
|
logging.getLogger("uvicorn").setLevel(logging.INFO)
|
|
logging.getLogger("uvicorn.access").setLevel(logging.INFO)
|
|
logging.getLogger("fastapi").setLevel(logging.INFO)
|
|
|
|
# Intercept httpx logs if needed
|
|
logging.getLogger("httpx").handlers = [InterceptHandler()]
|
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|