日志管理详细设计:
1. 设置日志等级
Level name Severity value Logger method
TRACE 5 logger.trace()
DEBUG 10 logger.debug()
INFO 20 logger.info()
SUCCESS 25 logger.success()
WARNING 30 logger.warning()
ERROR 40 logger.error()
CRITICAL 50 logger.critical()
2.设置日志输出路径
控制台:可输出info及以上等级的日志
指定文件:可输出debug及以上等级的日志
3. 日志模块使用方法
#首先引入日志管理模块并初始化
from LogManager.logconfig import Mylogger
logger = Mylogger().logger #通过单例模式可保证只会有一个logger实例
使用示例:
logger.debug("This is debug log")
logger.info("This is info log")
logger.success("This is success log")
logger.warning("This is warning log")
logger.error("This is error log")
logger.critical("This is critical log")
4. 输出log格式化
#类似于使用python 字符串的format方法: str.format()
format = "This is format"
logger.info("log_download start info %s"%format)
logger.info("If you're using Python {}, prefer {feature} of course!", 3.6, feature="f-strings")
5. 异常处理
在程序执行过程中出现不可预知的错误时会突然崩溃,且很难保存详细的问题现场用于debug,这种情况增大了问题修复的难度。
因此需要有合理的异常处理机制来记录问题现场,Loguru中的装饰器catch()可以很好的实现上述功能。
记录代码中发生的异常对于跟踪错误很重要,但如果不知道失败的原因,那么它就毫无用处。
Loguru 通过允许显示整个堆栈跟踪(包括变量值)来帮助开发者识别问题,在捕获异常后使用logger.exception打印堆栈信息。
import sys
import os
from time import strftime, localtime
from datetime import datetime
import pytz
#导入log管理模块
#官方文档 https://github.com/Delgan/loguru
from loguru import logger
"""
"""
#定义日志保存路径
LOG_SAVE_PATH = "staticlog/bugautoanalysis_log"
if getattr(sys, 'frozen', False):
# 打包后的可执行程序
LOG_SAVE_PATH = os.path.join(os.path.dirname(os.path.realpath(sys.executable)),LOG_SAVE_PATH)
else:
# 运行脚本文件
LOG_SAVE_PATH = os.path.join(sys.path[0],LOG_SAVE_PATH)
def GetStrTime():
"""
Function:
获取当前时间并格式化为时间字符串
"""
localtime = datetime.now(tz=pytz.timezone('Asia/Shanghai'))
fmt = "%Y%m%d_%H%M%S"
strtime = localtime.strftime(fmt)
return strtime
#通过单例模式保证只有一个logger对象
#不同文件中都通过该对象进行log输出
class Mylogger:
# 私有类属性,用于存储单例实例
_instance = None
mylogpath = None
def __new__(cls):
# 如果尚未创建实例,则创建并返回它
if cls._instance is None:
# print("Creating new logger instance")
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self) -> None:
# 设置往控制台和文件中输出log的等级
self.set_custom_logger(console_level='INFO',write_level='DEBUG')
self.logger = logger
def set_custom_logger(self, console_level='INFO', write_level='DEBUG'):
self.mylogpath = LOG_SAVE_PATH+"_%s.log"%(GetStrTime())
#参考文档 https://blog.youkuaiyun.com/weixin_42149982/article/details/125645235
console_log_level_list = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
if console_level.upper() not in console_log_level_list:
raise Exception(f'控制台log设置的等级不存在,控制台log等级为:{console_log_level_list}')
write_log_level_list = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
if write_level.upper() not in write_log_level_list:
raise Exception(f'写入log设置的等级不存在,写入log等级为:{write_log_level_list}')
logger.remove() # 删除原来的样式
# 控制台输出
logger.add(
sink=sys.stdout,
level=console_level, # 设置log的level等级
colorize=True, # 开启颜色
enqueue=True, # 开启异步
)
# 记录设置writer_level
logger.add(
sink=self.mylogpath, #每次调用时都生成新的log文件
rotation='50 MB', # 超过50MB就会重新生产一个文件(常用),其他用法可以查一下
encoding='utf-8',
compression='zip', # 压缩
level=write_level,
enqueue=True, # 开启异步
# colorize=True, # 开启颜色 开启颜色导致乱码
)
def setHandle(self,myhandle,printlevel = "INFO"):
# logger.add(myhandle)
print_log_level_list = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
if printlevel.upper() not in print_log_level_list:
raise Exception(f'写入log设置的等级不存在,写入log等级为:{print_log_level_list}')
# 控制台输出
logger.add(
sink= myhandle,
level=printlevel, # 设置log的level等级
colorize=True, # 开启颜色
enqueue=True, # 开启异步
)
def getLogpath(self):
return self.mylogpath
def resetLogger(self):
# 设置往控制台和文件中输出log的等级
self.set_custom_logger(console_level='INFO',write_level='DEBUG')
self.logger = logger