jmisak's picture
Upload 41 files
aeb3f7c verified
"""Structured logging configuration with rotation support."""
import logging
import sys
from logging.handlers import RotatingFileHandler
from pathlib import Path
from typing import Optional
from pythonjsonlogger import jsonlogger
from writing_studio.core.config import settings
class CustomJsonFormatter(jsonlogger.JsonFormatter):
"""Custom JSON formatter with additional fields."""
def add_fields(self, log_record: dict, record: logging.LogRecord, message_dict: dict) -> None:
"""Add custom fields to log records."""
super().add_fields(log_record, record, message_dict)
log_record["level"] = record.levelname
log_record["logger"] = record.name
log_record["app"] = settings.app_name
log_record["environment"] = settings.environment
def setup_logging(
name: Optional[str] = None,
level: Optional[str] = None,
log_file: Optional[str] = None,
) -> logging.Logger:
"""
Configure structured logging with file rotation.
Args:
name: Logger name (default: root logger)
level: Log level (default: from settings)
log_file: Log file path (default: from settings)
Returns:
Configured logger instance
"""
logger = logging.getLogger(name)
logger.setLevel(level or settings.log_level)
logger.handlers.clear()
# Console handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(level or settings.log_level)
# Format based on settings
if settings.log_format == "json":
formatter = CustomJsonFormatter(
"%(timestamp)s %(level)s %(name)s %(message)s",
rename_fields={"timestamp": "asctime"},
)
else:
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# File handler with rotation
log_file_path = log_file or settings.log_file_path
if log_file_path:
# Ensure log directory exists
Path(log_file_path).parent.mkdir(parents=True, exist_ok=True)
file_handler = RotatingFileHandler(
log_file_path,
maxBytes=settings.log_max_bytes,
backupCount=settings.log_backup_count,
)
file_handler.setLevel(level or settings.log_level)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# Prevent propagation to avoid duplicate logs
logger.propagate = False
return logger
# Global logger instance
logger = setup_logging("writing_studio")