114 lines
3.3 KiB
Python
114 lines
3.3 KiB
Python
# 日志系统配置
|
|
import logging
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
import uuid
|
|
from logging.handlers import RotatingFileHandler
|
|
|
|
class JSONFormatter(logging.Formatter):
|
|
"""JSON 格式日志处理器"""
|
|
|
|
def format(self, record):
|
|
log_data = {
|
|
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
'level': record.levelname,
|
|
'logger': record.name,
|
|
'message': record.getMessage(),
|
|
'trace_id': getattr(record, 'trace_id', str(uuid.uuid4())),
|
|
'user_id': getattr(record, 'user_id', None),
|
|
'request_id': getattr(record, 'request_id', str(uuid.uuid4())),
|
|
'ip_address': getattr(record, 'ip_address', None),
|
|
'duration_ms': getattr(record, 'duration_ms', None),
|
|
}
|
|
|
|
# 添加额外字段
|
|
if hasattr(record, 'data'):
|
|
log_data['data'] = record.data
|
|
|
|
# 添加异常信息
|
|
if record.exc_info:
|
|
log_data['exception'] = self.formatException(record.exc_info)
|
|
|
|
return json.dumps(log_data, ensure_ascii=False, default=str)
|
|
|
|
|
|
def setup_logging(
|
|
log_file: str = 'logs/app.log',
|
|
level: str = 'INFO',
|
|
max_bytes: int = 10*1024*1024, # 10MB
|
|
backup_count: int = 5
|
|
):
|
|
"""配置日志系统"""
|
|
|
|
# 创建日志目录
|
|
os.makedirs(os.path.dirname(log_file), exist_ok=True)
|
|
|
|
# 根日志器
|
|
logger = logging.getLogger()
|
|
logger.setLevel(level)
|
|
|
|
# 清空现有处理器
|
|
logger.handlers.clear()
|
|
|
|
# 文件处理器(带轮转)
|
|
file_handler = RotatingFileHandler(
|
|
log_file,
|
|
maxBytes=max_bytes,
|
|
backupCount=backup_count,
|
|
encoding='utf-8'
|
|
)
|
|
file_handler.setFormatter(JSONFormatter())
|
|
logger.addHandler(file_handler)
|
|
|
|
# 控制台处理器(仅开发环境)
|
|
if os.getenv('ENV', 'development') == 'development':
|
|
console_handler = logging.StreamHandler()
|
|
console_handler.setFormatter(JSONFormatter())
|
|
logger.addHandler(console_handler)
|
|
|
|
return logger
|
|
|
|
|
|
# 创建日志器实例
|
|
logger = setup_logging()
|
|
|
|
|
|
# 日志装饰器
|
|
def log_operation(operation_name: str):
|
|
"""记录操作日志的装饰器"""
|
|
def decorator(func):
|
|
import functools
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
import time
|
|
start_time = time.time()
|
|
|
|
try:
|
|
result = func(*args, **kwargs)
|
|
duration = (time.time() - start_time) * 1000
|
|
|
|
logger.info(
|
|
f"{operation_name} 成功",
|
|
extra={
|
|
'duration_ms': duration,
|
|
'data': {'function': func.__name__}
|
|
}
|
|
)
|
|
return result
|
|
|
|
except Exception as e:
|
|
duration = (time.time() - start_time) * 1000
|
|
logger.error(
|
|
f"{operation_name} 失败:{str(e)}",
|
|
extra={
|
|
'duration_ms': duration,
|
|
'data': {'function': func.__name__, 'error': str(e)}
|
|
},
|
|
exc_info=True
|
|
)
|
|
raise
|
|
return wrapper
|
|
return decorator
|