230 lines
6.2 KiB
Python
230 lines
6.2 KiB
Python
# -*- encoding=utf8 -*-
|
||
"""
|
||
统一的日志配置模块
|
||
|
||
此模块提供了整个项目的日志管理功能,包括:
|
||
- 统一的日志格式
|
||
- 集中的日志级别控制
|
||
- 第三方库日志管理
|
||
- 支持文件和控制台输出
|
||
"""
|
||
import logging
|
||
import sys
|
||
from pathlib import Path
|
||
from typing import Optional, List
|
||
|
||
|
||
# 默认日志格式
|
||
DEFAULT_LOG_FORMAT = '%(asctime)s %(name)-20s %(levelname)-8s %(message)s'
|
||
DEFAULT_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||
|
||
# 需要抑制的第三方库logger
|
||
THIRD_PARTY_LOGGERS = [
|
||
# Airtest相关
|
||
'airtest',
|
||
'adb',
|
||
'airtest.core.android.adb',
|
||
|
||
# 网络相关
|
||
'urllib3',
|
||
'urllib3.connectionpool',
|
||
'requests',
|
||
|
||
# AI/ML相关
|
||
'transformers',
|
||
'torch',
|
||
'tensorflow',
|
||
|
||
# 图像处理
|
||
'PIL',
|
||
'PIL.PngImagePlugin',
|
||
'PIL.Image',
|
||
'matplotlib',
|
||
'cv2',
|
||
|
||
# 其他
|
||
'filelock',
|
||
'webdriver_manager',
|
||
]
|
||
|
||
|
||
def setup_logging(
|
||
level: int = logging.INFO,
|
||
log_file: Optional[str] = None,
|
||
log_format: str = DEFAULT_LOG_FORMAT,
|
||
date_format: str = DEFAULT_DATE_FORMAT,
|
||
debug_mode: bool = False,
|
||
enable_file_handler: bool = True,
|
||
enable_console_handler: bool = True,
|
||
third_party_level: int = logging.WARNING,
|
||
custom_third_party_loggers: Optional[List[str]] = None
|
||
) -> logging.Logger:
|
||
"""
|
||
统一配置项目日志系统
|
||
|
||
Args:
|
||
level: 主日志级别 (默认: logging.INFO)
|
||
log_file: 日志文件路径,None表示不写入文件
|
||
log_format: 日志格式字符串
|
||
date_format: 日期格式字符串
|
||
debug_mode: 是否启用调试模式(会将level设为DEBUG)
|
||
enable_file_handler: 是否启用文件处理器
|
||
enable_console_handler: 是否启用控制台处理器
|
||
third_party_level: 第三方库的日志级别
|
||
custom_third_party_loggers: 额外需要抑制的第三方logger名称列表
|
||
|
||
Returns:
|
||
配置好的根logger对象
|
||
|
||
Example:
|
||
# 基本使用
|
||
setup_logging()
|
||
logger = logging.getLogger(__name__)
|
||
logger.info("Application started")
|
||
|
||
# 带文件输出
|
||
setup_logging(log_file="app.log", debug_mode=True)
|
||
|
||
# 仅文件输出,不输出到控制台
|
||
setup_logging(log_file="app.log", enable_console_handler=False)
|
||
"""
|
||
# Debug模式覆盖级别设置
|
||
if debug_mode:
|
||
level = logging.DEBUG
|
||
|
||
# 准备handlers
|
||
handlers = []
|
||
formatter = logging.Formatter(log_format, datefmt=date_format)
|
||
|
||
# 控制台handler
|
||
if enable_console_handler:
|
||
console_handler = logging.StreamHandler(sys.stdout)
|
||
console_handler.setFormatter(formatter)
|
||
console_handler.setLevel(level)
|
||
handlers.append(console_handler)
|
||
|
||
# 文件handler
|
||
if enable_file_handler and log_file:
|
||
# 确保日志目录存在
|
||
log_path = Path(log_file)
|
||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
||
file_handler = logging.FileHandler(log_file, encoding='utf-8')
|
||
file_handler.setFormatter(formatter)
|
||
file_handler.setLevel(level)
|
||
handlers.append(file_handler)
|
||
|
||
# 配置根logger
|
||
logging.basicConfig(
|
||
level=level,
|
||
format=log_format,
|
||
datefmt=date_format,
|
||
handlers=handlers,
|
||
force=True # 强制覆盖已有配置
|
||
)
|
||
|
||
# 配置第三方库日志级别
|
||
all_third_party = THIRD_PARTY_LOGGERS.copy()
|
||
if custom_third_party_loggers:
|
||
all_third_party.extend(custom_third_party_loggers)
|
||
|
||
for logger_name in all_third_party:
|
||
logging.getLogger(logger_name).setLevel(third_party_level)
|
||
|
||
root_logger = logging.getLogger()
|
||
return root_logger
|
||
|
||
|
||
def get_logger(name: str = None) -> logging.Logger:
|
||
"""
|
||
获取logger实例的便捷函数
|
||
|
||
Args:
|
||
name: logger名称,通常传入 __name__。如果为None,返回root logger
|
||
|
||
Returns:
|
||
Logger实例
|
||
|
||
Example:
|
||
logger = get_logger(__name__)
|
||
logger.info("Message")
|
||
"""
|
||
return logging.getLogger(name)
|
||
|
||
|
||
def set_module_log_level(module_name: str, level: int):
|
||
"""
|
||
设置特定模块的日志级别
|
||
|
||
Args:
|
||
module_name: 模块名称
|
||
level: 日志级别
|
||
|
||
Example:
|
||
# 只看DroidBot的DEBUG日志
|
||
set_module_log_level('DroidBot', logging.DEBUG)
|
||
|
||
# 完全禁用某个模块的日志
|
||
set_module_log_level('noisy_module', logging.CRITICAL)
|
||
"""
|
||
logging.getLogger(module_name).setLevel(level)
|
||
|
||
|
||
def disable_third_party_logs():
|
||
"""
|
||
完全禁用所有第三方库的日志输出
|
||
|
||
Example:
|
||
disable_third_party_logs()
|
||
"""
|
||
for logger_name in THIRD_PARTY_LOGGERS:
|
||
logging.getLogger(logger_name).setLevel(logging.CRITICAL + 1)
|
||
|
||
|
||
# 便捷的配置预设
|
||
def setup_basic_logging():
|
||
"""基础配置:INFO级别,仅控制台输出"""
|
||
return setup_logging(level=logging.INFO, enable_file_handler=False)
|
||
|
||
|
||
def setup_debug_logging(log_file: str = None):
|
||
"""调试配置:DEBUG级别,控制台+文件输出"""
|
||
return setup_logging(
|
||
level=logging.DEBUG,
|
||
log_file=log_file,
|
||
debug_mode=True
|
||
)
|
||
|
||
|
||
def setup_production_logging(log_file: str):
|
||
"""生产配置:INFO级别,仅文件输出"""
|
||
return setup_logging(
|
||
level=logging.INFO,
|
||
log_file=log_file,
|
||
enable_console_handler=False
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
# 测试日志配置
|
||
print("=== 测试日志配置 ===\n")
|
||
|
||
# 测试1: 基础配置
|
||
print("1. 基础配置测试")
|
||
setup_basic_logging()
|
||
logger = get_logger(__name__)
|
||
logger.debug("这条DEBUG不会显示")
|
||
logger.info("这条INFO会显示")
|
||
logger.warning("这条WARNING会显示")
|
||
|
||
print("\n2. 调试模式测试")
|
||
setup_debug_logging()
|
||
logger.debug("调试模式下,这条DEBUG会显示")
|
||
logger.info("这条INFO也会显示")
|
||
|
||
print("\n3. 第三方库日志抑制测试")
|
||
third_party_logger = logging.getLogger('urllib3')
|
||
third_party_logger.warning("这条第三方WARNING不会显示(被抑制到WARNING级别以上)")
|
||
|
||
print("\n测试完成!")
|