95 lines
3.3 KiB
Python
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()
|
|
|