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("测试错误"), "处理数据时") |