suna/backend/utils/logger.py

131 lines
4.4 KiB
Python
Raw Normal View History

2025-04-01 09:26:52 +08:00
"""
Centralized logging configuration for AgentPress.
This module provides a unified logging interface with:
- Structured JSON logging for better parsing
- Log levels for different environments
- Correlation IDs for request tracing
- Contextual information for debugging
"""
import logging
import json
import sys
import os
from datetime import datetime, timezone
2025-04-01 09:26:52 +08:00
from contextvars import ContextVar
from functools import wraps
import traceback
from logging.handlers import RotatingFileHandler
2025-04-24 11:34:45 +08:00
from utils.config import config, EnvMode
2025-04-01 09:26:52 +08:00
# Context variable for request correlation ID
request_id: ContextVar[str] = ContextVar('request_id', default='')
class JSONFormatter(logging.Formatter):
"""Custom JSON formatter for structured logging."""
def format(self, record: logging.LogRecord) -> str:
"""Format log record as JSON with contextual information."""
log_data = {
'timestamp': datetime.now(timezone.utc).replace(tzinfo=None).isoformat(),
2025-04-01 09:26:52 +08:00
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno,
'request_id': request_id.get(),
'thread_id': getattr(record, 'thread_id', None),
'correlation_id': getattr(record, 'correlation_id', None)
}
# Add extra fields if present
if hasattr(record, 'extra'):
log_data.update(record.extra)
# Add exception info if present
if record.exc_info:
log_data['exception'] = {
'type': str(record.exc_info[0].__name__),
'message': str(record.exc_info[1]),
'traceback': traceback.format_exception(*record.exc_info)
}
return json.dumps(log_data)
def setup_logger(name: str = 'agentpress') -> logging.Logger:
"""
Set up a centralized logger with both file and console handlers.
Args:
name: The name of the logger
Returns:
logging.Logger: Configured logger instance
"""
logger = logging.getLogger(name)
2025-04-25 06:04:59 +08:00
logger.setLevel(logging.DEBUG)
2025-04-01 09:26:52 +08:00
# Create logs directory if it doesn't exist
2025-04-25 06:04:59 +08:00
log_dir = os.path.join(os.getcwd(), 'logs')
try:
if not os.path.exists(log_dir):
os.makedirs(log_dir)
print(f"Created log directory at: {log_dir}")
except Exception as e:
print(f"Error creating log directory: {e}")
return logger
2025-04-01 09:26:52 +08:00
# File handler with rotation
2025-04-25 06:04:59 +08:00
try:
log_file = os.path.join(log_dir, f'{name}_{datetime.now().strftime("%Y%m%d")}.log')
file_handler = RotatingFileHandler(
log_file,
maxBytes=10*1024*1024, # 10MB
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(logging.DEBUG)
# Create formatters
file_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
)
file_handler.setFormatter(file_formatter)
# Add file handler to logger
logger.addHandler(file_handler)
print(f"Added file handler for: {log_file}")
except Exception as e:
print(f"Error setting up file handler: {e}")
2025-04-01 09:26:52 +08:00
# Console handler - WARNING in production, DEBUG in other environments
2025-04-25 06:04:59 +08:00
try:
console_handler = logging.StreamHandler(sys.stdout)
if config.ENV_MODE == EnvMode.PRODUCTION:
console_handler.setLevel(logging.WARNING)
else:
console_handler.setLevel(logging.DEBUG)
2025-04-25 06:04:59 +08:00
console_formatter = logging.Formatter(
'%(asctime)s - %(levelname)s - %(name)s - %(message)s'
2025-04-25 06:04:59 +08:00
)
console_handler.setFormatter(console_formatter)
# Add console handler to logger
logger.addHandler(console_handler)
logger.info(f"Added console handler with level: {console_handler.level}")
logger.info(f"Log file will be created at: {log_dir}")
2025-04-25 06:04:59 +08:00
except Exception as e:
print(f"Error setting up console handler: {e}")
2025-04-01 09:26:52 +08:00
2025-04-25 06:04:59 +08:00
# # Test logging
# logger.debug("Logger setup complete - DEBUG test")
# logger.info("Logger setup complete - INFO test")
# logger.warning("Logger setup complete - WARNING test")
2025-04-01 09:26:52 +08:00
return logger
# Create default logger instance
logger = setup_logger()