185 lines
4.9 KiB
Python
185 lines
4.9 KiB
Python
|
|
"""
|
|||
|
|
日志记录工具
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import Optional
|
|||
|
|
|
|||
|
|
|
|||
|
|
def setup_logger(
|
|||
|
|
name: str = 'screen2feishu',
|
|||
|
|
log_file: Optional[str] = None,
|
|||
|
|
level: str = 'INFO',
|
|||
|
|
format: str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|||
|
|
) -> logging.Logger:
|
|||
|
|
"""
|
|||
|
|
设置日志记录器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
name: 日志记录器名称
|
|||
|
|
log_file: 日志文件路径,如果为None则只输出到控制台
|
|||
|
|
level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|||
|
|
format: 日志格式
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
配置好的日志记录器
|
|||
|
|
"""
|
|||
|
|
# 创建日志记录器
|
|||
|
|
logger = logging.getLogger(name)
|
|||
|
|
|
|||
|
|
# 避免重复配置
|
|||
|
|
if logger.handlers:
|
|||
|
|
return logger
|
|||
|
|
|
|||
|
|
# 设置日志级别
|
|||
|
|
level_map = {
|
|||
|
|
'DEBUG': logging.DEBUG,
|
|||
|
|
'INFO': logging.INFO,
|
|||
|
|
'WARNING': logging.WARNING,
|
|||
|
|
'ERROR': logging.ERROR,
|
|||
|
|
'CRITICAL': logging.CRITICAL
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
log_level = level_map.get(level.upper(), logging.INFO)
|
|||
|
|
logger.setLevel(log_level)
|
|||
|
|
|
|||
|
|
# 创建格式化器
|
|||
|
|
formatter = logging.Formatter(format, datefmt='%Y-%m-%d %H:%M:%S')
|
|||
|
|
|
|||
|
|
# 创建控制台处理器
|
|||
|
|
# 在Windows系统上,确保使用UTF-8编码输出
|
|||
|
|
if sys.platform == 'win32':
|
|||
|
|
import io
|
|||
|
|
console_handler = logging.StreamHandler(io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8'))
|
|||
|
|
else:
|
|||
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|||
|
|
console_handler.setFormatter(formatter)
|
|||
|
|
logger.addHandler(console_handler)
|
|||
|
|
|
|||
|
|
# 创建文件处理器(如果指定了日志文件)
|
|||
|
|
if log_file:
|
|||
|
|
log_path = Path(log_file)
|
|||
|
|
|
|||
|
|
# 确保日志目录存在
|
|||
|
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|
|||
|
|
file_handler = logging.FileHandler(log_path, encoding='utf-8')
|
|||
|
|
file_handler.setFormatter(formatter)
|
|||
|
|
logger.addHandler(file_handler)
|
|||
|
|
|
|||
|
|
return logger
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_logger(name: str = 'screen2feishu') -> logging.Logger:
|
|||
|
|
"""
|
|||
|
|
获取已配置的日志记录器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
name: 日志记录器名称
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
日志记录器
|
|||
|
|
"""
|
|||
|
|
return logging.getLogger(name)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def log_function_call(logger: logging.Logger, func_name: str, *args, **kwargs):
|
|||
|
|
"""
|
|||
|
|
记录函数调用日志
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
logger: 日志记录器
|
|||
|
|
func_name: 函数名
|
|||
|
|
*args: 位置参数
|
|||
|
|
**kwargs: 关键字参数
|
|||
|
|
"""
|
|||
|
|
args_str = ', '.join(repr(arg) for arg in args)
|
|||
|
|
kwargs_str = ', '.join(f'{k}={repr(v)}' for k, v in kwargs.items())
|
|||
|
|
all_args = ', '.join(filter(None, [args_str, kwargs_str]))
|
|||
|
|
|
|||
|
|
logger.debug(f"调用函数: {func_name}({all_args})")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def log_function_result(logger: logging.Logger, func_name: str, result):
|
|||
|
|
"""
|
|||
|
|
记录函数返回结果日志
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
logger: 日志记录器
|
|||
|
|
func_name: 函数名
|
|||
|
|
result: 函数返回结果
|
|||
|
|
"""
|
|||
|
|
logger.debug(f"函数 {func_name} 返回: {repr(result)}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def log_error_with_context(logger: logging.Logger, error: Exception, context: str = ""):
|
|||
|
|
"""
|
|||
|
|
记录错误日志,包含上下文信息
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
logger: 日志记录器
|
|||
|
|
error: 异常对象
|
|||
|
|
context: 错误上下文信息
|
|||
|
|
"""
|
|||
|
|
if context:
|
|||
|
|
logger.error(f"{context}: {str(error)}")
|
|||
|
|
else:
|
|||
|
|
logger.error(f"错误: {str(error)}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def create_log_rotation_handler(
|
|||
|
|
log_file: str,
|
|||
|
|
max_bytes: int = 10 * 1024 * 1024, # 10MB
|
|||
|
|
backup_count: int = 5
|
|||
|
|
) -> logging.Handler:
|
|||
|
|
"""
|
|||
|
|
创建支持日志轮转的文件处理器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
log_file: 日志文件路径
|
|||
|
|
max_bytes: 单个日志文件最大字节数
|
|||
|
|
backup_count: 备份文件数量
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
文件处理器
|
|||
|
|
"""
|
|||
|
|
from logging.handlers import RotatingFileHandler
|
|||
|
|
|
|||
|
|
log_path = Path(log_file)
|
|||
|
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|
|||
|
|
handler = RotatingFileHandler(
|
|||
|
|
log_file,
|
|||
|
|
maxBytes=max_bytes,
|
|||
|
|
backupCount=backup_count,
|
|||
|
|
encoding='utf-8'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
formatter = logging.Formatter(
|
|||
|
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|||
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|||
|
|
)
|
|||
|
|
handler.setFormatter(formatter)
|
|||
|
|
|
|||
|
|
return handler
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# 测试日志功能
|
|||
|
|
logger = setup_logger(
|
|||
|
|
name='test_logger',
|
|||
|
|
log_file='test.log',
|
|||
|
|
level='DEBUG'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
logger.debug("这是一条调试信息")
|
|||
|
|
logger.info("这是一条普通信息")
|
|||
|
|
logger.warning("这是一条警告信息")
|
|||
|
|
logger.error("这是一条错误信息")
|
|||
|
|
|
|||
|
|
# 测试函数调用日志
|
|||
|
|
log_function_call(logger, "test_function", "arg1", "arg2", key="value")
|
|||
|
|
log_function_result(logger, "test_function", {"result": "success"})
|
|||
|
|
log_error_with_context(logger, Exception("测试错误"), "处理数据时")
|