文章目录
更新记录
时间 | 版本 | 内容 | 修订者 | 备注 |
---|---|---|---|---|
2024/08/15 | 0.1.0 | 创建 | henry.xu |
开发组日志记录SPEC_v0.1.0
1. 目的
1.1 区分用户日志和开发人员日志
- 实现效果:
logger = LoggerManager()
# 为记录器添加文件处理器;不添加则不生成日志文件;
logger.logfile(log_path, encoding='utf-8', mode='w')
# 设置log_level
logger.set_log_level(level=DEBUG)
# 启用 Dev 记录器的控制台处理器;
# 为True的时候,控制台会打印属于 Dev 记录器的日志信息,反之则不打印;
logger.dev_log_enabled = True
# dev参数默认为False;
# True表示该日志属于 Dev 日志记录器,反之表示该日志属于 User 记录器;
# 表示这条消息在logger.dev_log_enabled设置为False的时候,不会打印在系统终端;
logger.info('This is an info message', dev=True)
logger.debug('This is a debug message')
logger.info('This is an info message')
- 当logger.dev_log_enabled设置为True的时候控制台打印的消息:
[Dev I 2024-08-16 13:12:49 auto_logger:122] This is an info message
[User D 2024-08-16 13:12:49 auto_logger:124] This is a debug message
[User I 2024-08-16 13:12:49 auto_logger:125] This is an info message
- 当logger.dev_log_enabled设置为False的时候控制台打印的消息:
[User D 2024-08-16 13:13:35 auto_logger:124] This is a debug message
[User I 2024-08-16 13:13:35 auto_logger:125] This is an info message
1. 2. 帮助开发人员快速定位
- 合理利用装饰器实现,详情可以参考4.2
2. 设计逻辑
以下是 logging
模块中记录器、格式器、处理器、筛选器作用介绍:
组件 | 主要作用 |
---|---|
Logger- 日志记录器 | 提供记录日志的接口,并将日志消息传递给 Handler |
Handler-处理器 | 将日志消息传递到指定的目标位置,如文件、控制台、网络等 |
Formatter-格式器 | 定义日志消息的输出格式,包括时间戳、日志级别、消息内容等 |
Filter-筛选器 | 控制哪些日志消息应该被记录或忽略,提供细粒度的日志控制 |
- 重新封装logging模块,在基本不改变代码的情况下替换掉之前使用的log日志系统;
- 定义两个日志记录器分别对应User 和 Dev;
- 提供参数dev区分两个日志记录器;dev=True代表Dev日志记录器;dev=False代表User日志记录器
- 为了方便开发人员开发调试,提供参数dev_log_enabled,为True的时候,控制台会打印属于 Dev 记录器的日志信息,反之则不打印;
- 同时为了方便开发人员debug,能够在生产端脚本报错的情况下,在开发端快速定位,引入装饰器快速实现执行每个方法时,方法开始和结束的日志记录;
3. User日志记录器
- 高于或等于设置的日志事件等级的日志,控制台和log文件都会记录;
3.1 记录器标签内容介绍
- User 代表给用户看的日志内容;
- D 代表该日志等级为debug;
- 2024-08-12 18:57:44 代表打印日志的时间;
- auto_logger 代表当前模块名称;
- 121代表代码在当前模块所在行数;
- This is a debug message 代表用户要看到的信息;
[User D 2024-08-12 18:57:44 auto_logger:121] This is a debug message
3.2 程序打印User日志规则
-
按照需求分析表步骤编号打印
-
日志内容格式规则:
- Step:按照项目需求分析表中的步骤编号填写;
- 步骤内容:按照项目需求分析表中的需求描述或功能介绍填写;
- 信息反馈:按照项目需求分析表中的预期效果填写;
- 测试结果:执行成功为PASS, 反之则为FAIL;
#例子:
#代码
logger.info("""
Step: 1-1-1
步骤内容: 设置UAC:搜索UAC->选择Change User Account Control settings打开UAC设置界面->设置UAC为Never notify->点击ok完成
信息反馈: 成功设置UAC为Never notify
测试结果: PASS
""")
# 实际效果:
[User I 2024-08-15 10:54:59 auto_logger:130]
Step: 1-1-1
步骤内容: 设置UAC:搜索UAC->选择Change User Account Control settings打开UAC设置界面->设置UAC为Never notify->点击ok完成
信息反馈: 成功设置UAC为Never notify
测试结果: PASS
4. Dev日志记录器
4.1 记录器标签内容介绍
- Dev代表这是给开发/测试/需求人员的,可以设置是否需要在控制台上打印
- 其他内容同User日志记录器;
[Dev I 2024-08-12 19:00:26 auto_logger:122] This is an info message
4.2 程序打印Dev日志规则
- 要求程序执行每个方法前需要打印"STA: 方法名",执行完方法以后,打印"END:方法名";
# 例子
# 利用装饰器实现
import time
def log_execution(func):
def wrapper(*args, **kwargs):
logger.info(f"STA: {func.__qualname__}", dev=True)
result = func(*args, **kwargs)
logger.info(f"END: {func.__qualname__}", dev=True)
return result
return wrapper
class MyClass:
@log_execution
def my_method_1(self):
time.sleep(1)
logger.info("正在执行 my_method_1")
@log_execution
def my_method_2(self, x):
time.sleep(2)
logger.info(f"正在执行 my_method_2,参数: {x}")
# 示例用法
obj = MyClass()
obj.my_method_1()
obj.my_method_2(5)
# log展示:
"""
[Dev I 2024-08-15 14:07:41 auto_logger:142] STA: MyClass.my_method_1
[User I 2024-08-15 14:07:42 auto_logger:154] 正在执行 my_method_1
[Dev I 2024-08-15 14:07:42 auto_logger:144] END: MyClass.my_method_1
[Dev I 2024-08-15 14:07:42 auto_logger:142] STA: MyClass.my_method_2
[User I 2024-08-15 14:07:44 auto_logger:159] 正在执行 my_method_2,参数: 5
[Dev I 2024-08-15 14:07:44 auto_logger:144] END: MyClass.my_method_2
"""
5.代码说明
5.1 代码详情
import logging
import os
import colorlog
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
class LoggerManager:
def __init__(self, log_file='log.txt'):
self.file_handler_formatter = '[%(name)s %(levelname)1.1s %(asctime)s %(module)s:%(lineno)d] %(message)s'
self.console_handler_formatter = '%(log_color)s[%(name)s %(levelname)1.1s %(asctime)s %(module)s:%(lineno)d] %(log_color)s%(message)s'
self.color_formatter = colorlog.ColoredFormatter(
self.console_handler_formatter,
datefmt='%Y-%m-%d %H:%M:%S',
log_colors={
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'bold_red'
}
)
# 设置日志文件路径
self.log_file = os.path.join(os.getcwd(), log_file)
# 控制台处理器(可选)
self._dev_log_enabled = False
self.console_handler = None
self.user_logger = self._create_user_logger()
self.dev_logger = self._create_dev_logger()
def logfile(self, filename, mode='a', encoding=None, delay=False, errors=None):
# 添加文件处理器
file_handler = logging.FileHandler(filename, mode=mode, encoding=encoding, delay=delay, errors=errors)
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(self.file_handler_formatter, datefmt="%Y-%m-%d %H:%M:%S")
file_handler.setFormatter(formatter)
# 添加文件处理器
self.user_logger.addHandler(file_handler)
self.dev_logger.addHandler(file_handler)
def _create_user_logger(self):
logger_ = logging.getLogger('User')
logger_.setLevel(logging.DEBUG)
# 控制台处理器
console_handler = colorlog.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(self.color_formatter)
logger_.addHandler(console_handler)
return logger_
@staticmethod
def _create_dev_logger():
logger_ = logging.getLogger('Dev ')
logger_.setLevel(logging.DEBUG)
return logger_
@property
def dev_log_enabled(self):
"""控制Dev记录器的控制台处理器的启用和禁用"""
return self._dev_log_enabled
@dev_log_enabled.setter
def dev_log_enabled(self, value):
"""启用或禁用控制台处理器"""
if value and not self._dev_log_enabled:
# 如果请求启用并且当前未启用,则添加控制台处理器
if self.console_handler is None:
self.console_handler = colorlog.StreamHandler()
self.console_handler.setLevel(logging.DEBUG)
self.console_handler.setFormatter(self.color_formatter)
self.dev_logger.addHandler(self.console_handler)
elif not value and self._dev_log_enabled:
# 如果请求禁用并且当前已启用,则移除控制台处理器
self.dev_logger.removeHandler(self.console_handler)
self._dev_log_enabled = value
def set_log_level(self, level):
"""设置 User 和 Dev 记录器的日志级别"""
self.user_logger.setLevel(level)
self.dev_logger.setLevel(level)
for handler in self.user_logger.handlers:
handler.setLevel(level)
for handler in self.dev_logger.handlers:
handler.setLevel(level)
def debug(self, message, dev=False):
logger_ = self.dev_logger if dev else self.user_logger
logger_.debug(message, stacklevel=2)
def info(self, message, dev=False):
logger_ = self.dev_logger if dev else self.user_logger
logger_.info(message, stacklevel=2)
def warning(self, message, dev=False):
logger_ = self.dev_logger if dev else self.user_logger
logger_.warning(message, stacklevel=2)
def error(self, message, dev=False):
logger_ = self.dev_logger if dev else self.user_logger
logger_.error(message, stacklevel=2)
def critical(self, message, dev=False):
logger_ = self.dev_logger if dev else self.user_logger
logger_.critical(message, stacklevel=2)
logger = LoggerManager()
5.2 使用说明
# 日志模块
# 实例化;
logger = LoggerManager()
# 为记录器添加文件处理器;不添加则不生成日志文件;
logger.logfile(filename="1.txt")
# 设置log_level
logger.set_log_level(level=INFO)
# 启用 Dev 记录器的控制台处理器;
# 为True的时候,控制台会打印属于 Dev 记录器的日志信息,反之则不打印;
logger.dev_log_enabled = True
# dev参数默认为False;
# True表示该日志属于 Dev 日志记录器,反之表示该日志属于 User 记录器;
# 表示这条消息在logger.dev_log_enabled设置为False的时候,不会打印在系统终端;
logger.info('This is an info message', dev=True)
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')