aibilly_backend_code/src/infrastructure/observability/logger.py
2026-03-10 16:44:04 +05:30

95 lines
3.3 KiB
Python

import logging
import sys
import os
from logging.handlers import RotatingFileHandler
from pythonjsonlogger import jsonlogger
"""
Structured Logger Service
Production-ready logger with JSON formatting, file rotation, and log levels
"""
class Logger:
def __init__(self):
self.log_level = os.getenv('LOG_LEVEL', 'INFO').upper()
self.log_format = os.getenv('LOG_FORMAT', 'json') # 'json' or 'text'
self.log_dir = os.getenv('LOG_DIR', './logs')
# Ensure log directory exists
os.makedirs(self.log_dir, exist_ok=True)
# Create logger
self.logger = logging.getLogger('test_project')
self.logger.setLevel(getattr(logging, self.log_level, logging.INFO))
# Remove existing handlers
self.logger.handlers = []
# Add handlers
self._setup_handlers()
def _setup_handlers(self):
"""Setup log handlers"""
# Console handler (always enabled)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(getattr(logging, self.log_level, logging.INFO))
if self.log_format == 'json':
formatter = jsonlogger.JsonFormatter(
'%(timestamp)s %(level)s %(name)s %(message)s',
timestamp=True
)
else:
formatter = logging.Formatter(
'%(asctime)s [%(levelname)s] %(name)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(formatter)
self.logger.addHandler(console_handler)
# File handlers (only in production or if LOG_TO_FILE is enabled)
if os.getenv('ENVIRONMENT') == 'production' or os.getenv('LOG_TO_FILE', 'false').lower() == 'true':
# Combined log file
combined_handler = RotatingFileHandler(
filename=os.path.join(self.log_dir, 'combined.log'),
maxBytes=10 * 1024 * 1024, # 10MB
backupCount=5
)
combined_handler.setLevel(logging.DEBUG)
combined_handler.setFormatter(formatter)
self.logger.addHandler(combined_handler)
# Error log file
error_handler = RotatingFileHandler(
filename=os.path.join(self.log_dir, 'error.log'),
maxBytes=10 * 1024 * 1024, # 10MB
backupCount=5
)
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(formatter)
self.logger.addHandler(error_handler)
def info(self, message: str, extra: dict = None):
"""Log info message"""
self.logger.info(message, extra=extra or {})
def error(self, message: str, extra: dict = None):
"""Log error message"""
self.logger.error(message, extra=extra or {})
def warning(self, message: str, extra: dict = None):
"""Log warning message"""
self.logger.warning(message, extra=extra or {})
def debug(self, message: str, extra: dict = None):
"""Log debug message"""
self.logger.debug(message, extra=extra or {})
def critical(self, message: str, extra: dict = None):
"""Log critical message"""
self.logger.critical(message, extra=extra or {})
# Singleton instance
logger = Logger()