tsunami / src /tsuwave /utils /logger.py
Gitdeeper4's picture
رفع جميع ملفات TSU-WAVE مع YAML
12834b7
"""Logging configuration for TSU-WAVE"""
import logging
import sys
import json
from pathlib import Path
from datetime import datetime
from typing import Optional, Dict, Any
import traceback
class JsonFormatter(logging.Formatter):
"""JSON formatter for structured logging"""
def format(self, record):
log_record = {
'timestamp': datetime.utcnow().isoformat(),
'level': record.levelname,
'name': record.name,
'message': record.getMessage(),
'module': record.module,
'line': record.lineno
}
if hasattr(record, 'extra'):
log_record.update(record.extra)
if record.exc_info:
log_record['exception'] = {
'type': record.exc_info[0].__name__,
'message': str(record.exc_info[1]),
'traceback': traceback.format_exception(*record.exc_info)
}
return json.dumps(log_record)
def setup_logging(
name: str = 'tsu-wave',
log_file: Optional[str] = None,
log_level: str = 'INFO',
json_format: bool = False
) -> logging.Logger:
"""Setup logging configuration"""
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, log_level.upper()))
# Remove existing handlers
logger.handlers.clear()
# Console handler
console_handler = logging.StreamHandler(sys.stdout)
if json_format:
console_handler.setFormatter(JsonFormatter())
else:
console_handler.setFormatter(
logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
)
logger.addHandler(console_handler)
# File handler (if specified)
if log_file:
log_path = Path(log_file)
log_path.parent.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(log_file)
if json_format:
file_handler.setFormatter(JsonFormatter())
else:
file_handler.setFormatter(
logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
)
logger.addHandler(file_handler)
return logger
def get_logger(name: str) -> logging.Logger:
"""Get logger instance"""
return logging.getLogger(name)
class LoggerAdapter(logging.LoggerAdapter):
"""Logger adapter with extra context"""
def __init__(self, logger, extra=None):
super().__init__(logger, extra or {})
def process(self, msg, kwargs):
kwargs['extra'] = self.extra
return msg, kwargs
def with_context(self, **context):
"""Create new adapter with additional context"""
new_extra = self.extra.copy()
new_extra.update(context)
return LoggerAdapter(self.logger, new_extra)
def log_function_call(logger=None):
"""Decorator to log function calls"""
def decorator(func):
def wrapper(*args, **kwargs):
log = logger or logging.getLogger(func.__module__)
# Log function call
log.debug(f"Calling {func.__name__}")
try:
result = func(*args, **kwargs)
log.debug(f"{func.__name__} completed successfully")
return result
except Exception as e:
log.error(f"{func.__name__} failed: {e}", exc_info=True)
raise
return wrapper
return decorator
def log_execution_time(logger=None):
"""Decorator to log function execution time"""
def decorator(func):
def wrapper(*args, **kwargs):
log = logger or logging.getLogger(func.__module__)
import time
start = time.time()
try:
result = func(*args, **kwargs)
elapsed = time.time() - start
log.debug(f"{func.__name__} took {elapsed:.3f}s")
return result
except Exception as e:
elapsed = time.time() - start
log.error(f"{func.__name__} failed after {elapsed:.3f}s: {e}")
raise
return wrapper
return decorator
class PerformanceLogger:
"""Context manager for performance logging"""
def __init__(self, name: str, logger=None):
self.name = name
self.logger = logger or logging.getLogger(__name__)
self.start_time = None
def __enter__(self):
import time
self.start_time = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
elapsed = time.time() - self.start_time
if exc_type:
self.logger.error(f"{self.name} failed after {elapsed:.3f}s: {exc_val}")
else:
self.logger.debug(f"{self.name} completed in {elapsed:.3f}s")
def setup_module_logger(module_name: str, log_level: str = 'INFO'):
"""Setup logger for a module"""
logger = logging.getLogger(module_name)
logger.setLevel(getattr(logging, log_level.upper()))
# Only add handler if none exists
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(
logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
)
logger.addHandler(handler)
return logger