【Python】loguru模块_打印日志
loguru
安装及使用
# 安装 pip install loguru
# 引用 from loguru import logger as logs # 打印日志 logs.debug("debug") logs.warning("warning")
执行结果:
生成日志文件
# 写入文件 logg.add("logs_20220415.log")
# 将日志保存在当前路径上一级目录的logs目录下,命名为 log_name log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d')) logs.add(sink=os.path.abspath("..") + "\\logs\\{}".format(log_name), level=log_level.upper())
# 设置生成日志文件,utf-8编码,每天0点切割,zip压缩,保留3天,异步写入 logs.add(sink='test.log', level="INFO", rotation="00:00", retention="3 days", compression="zip", encoding="utf-8", enqueue=True)
# rotation 参数,文件记录条件 logs.add("file_name1.log", rotation="50MB") # 超过50MB即生成新文件 logs.add("file_name1.log", rotation="12:00") # 每天12点生成新文件 logs.add("file_name1.log", rotation="1 week") # 每1周 生成新文件 logs.add("file_name1.log", rotation="3 days") # 每3天 生成新文件
# compression 参数 配置文件压缩格式 logs.add("file_name1.log", compression="zip") # 压缩成zip
# 仅输出到文件 不打印到控制台 # 删除以前添加的处理程序并停止向其接收器发送日志。 logs.remove(handler_id=None) # 移除控制台输出
# 添加控制台输出的格式,sys.stdout为输出到屏幕 logs.add(sys.stdout, format="<green>{time:YYYY-MM-DD HH:mm:ss:SSS}</green> | " # 颜色>时间 "<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名 "<cyan>[{line}]</cyan> | " # 行号 "<level>{level}[{thread.name}]</level>: " # 等级 # 线程名 "<level>{message}</level>", # 日志内容 )
执行结果 
# 添加logging 集成loguru输出到控制台(及html报告) class PropogateHandler(logging.Handler): def emit(self, record): logging.getLogger(record.name).handle(record) logs.add(PropogateHandler(), format="{time:YYYY-MM-DD at HH:mm:ss} | {message}")
执行结果:
log.add(PropogateHandler(), format="{time:YYYY-MM-DD HH:mm:ss} - {file}[{line}] - {level} : {message}")
执行结果:
根据启动文件名称包含关键字,判断是否打印日志到控制台(此处举例Pytest)
#!/usr/bin/env python # coding:utf-8 import datetime import os import sys import logging from loguru import logger as logs class PropogateHandler(logging.Handler): """添加logging 集成loguru到控制台(即html报告)""" def emit(self, record): logging.getLogger(record.name).handle(record) class Log(): """日志打印""" @staticmethod def saveLog(): """保存日志""" # 当前日期滚动写入日志 log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d')) log_error = "log_error.log" # 单次写入日志 # log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d%H%M%S')) # log_error = "log_error_{}.log".format(datetime.datetime.now().strftime('%Y%m%d')) # 判断文件路径,未找到则在当前路径生成文件夹 if "config.ini" in os.listdir(os.path.abspath("..")): # 设置生成日志文件,utf-8编码,每天0点切割,zip压缩,保留3天,异步写入 # logs.add(sink='test.log', level="INFO", rotation="00:00", retention="3 days", compression="zip", encoding="utf-8", enqueue=True) logs.add(sink=os.path.abspath("..") + "\\logs\\{}".format(log_name), level=config.get("basic", "log_level").upper()) logs.add(sink=os.path.abspath("..") + "\\logs\\{}".format(log_error), level="ERROR") # 错误单独打印文件 else: logs.add(sink=os.getcwd() + "\\logs\\{}".format(log_name), level=config.get("basic", "log_level").upper()) logs.add(sink=os.getcwd() + "\\logs\\{}".format(log_error), level="ERROR") # 错误单独打印文件 def __init__(self, to_console): # 判断打印类型 if to_console == "on":
logs.remove(handler_id=None) # 保存日志并打印到控制台 self.saveLog() else: # 删除以前添加的处理程序并停止向其接收器发送日志。 logs.remove(handler_id=None) # 清除之前的设置 logs.add(PropogateHandler(), format=" - {time:YYYY-MM-DD HH:mm:ss:SSSS} : {message}") # 判断程序启动文件名是否包含test,执行日志打印操作 run_file_name = os.path.basename(sys.argv[0]).upper() to_console = "off" if "TEST_" in run_file_name else "on" Log(to_console=to_console)
异常捕获
catch装饰器的方式实现异常捕获
@logs.catch def test_case_logc(self): anv = "" return anv[0]
执行结果:
exception方法也可以实现异常的捕获与记录
def test_case_logc(self): try: 1/0 except: logs.exception("异常捕获")
执行结果:
示例:
#!/usr/bin/env python # coding:utf-8 import os import sys import logging import datetime import configparser from loguru import logger as logs class PropogateHandler(logging.Handler): """添加logging 集成loguru到控制台(即html报告)""" def emit(self, record): logging.getLogger(record.name).handle(record) class Log: """封装日志打印""" @staticmethod def saveLog(): """保存日志""" if config.get("basic", "log.filename.type") == "date": # 当前日期滚动写入日志 log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d')) log_error = "log_error.log" else: # 单次写入日志 log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d%H%M%S')) log_error = "log_error_{}.log".format(datetime.datetime.now().strftime('%Y%m%d')) cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] # 获取根目录 # 添加到日志文件中的格式 logs.add(sink=os.path.join(proj_path, "logs\\{}".format(log_name)), level=config.get("basic", "log_level").upper(), # rotation="00:00", retention="3 days", compression="zip", encoding="utf-8", enqueue=True, # utf-8编码,每天0点切割,zip压缩,保留3天,异步写入 format="{time:YYYY-MM-DD HH:mm:ss:SSS} - {file}[{line}] - {level} <{thread.name}>: {message}") logs.add(sink=os.path.join(proj_path, "logs\\{}".format(log_error)), level="ERROR", format="{time:YYYY-MM-DD HH:mm:ss:SSS} - {file}[{line}] - {level} <{thread.name}>: {message}") # 错误单独打印文件 @staticmethod def sys_stdout(): """添加控制台输出的格式,sys.stdout为输出到屏幕""" logs.add(sys.stdout, level=config.get("basic", "log_level").upper(), format="<green>{time:YYYY-MM-DD HH:mm:ss:SSS}</green> | " # 颜色>时间 "<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名 "<cyan>[{line}]</cyan> | " # 行号 "<level>{level} <{thread.name}>:</level> " # 等级 # 线程名 "<level>{message}</level>", # 日志内容 ) # sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030') # 1TODO: 2023-2-28 改变标准输出的默认编码 def __init__(self, to_console): """判断打印类型""" logs.remove(handler_id=None) # 删除以前添加的处理程序并停止向其接收器发送日志。 self.saveLog() # 保存日志 if to_console == "on": self.sys_stdout() # 控制台的输出格式 else: logs.add(PropogateHandler(), level=config.get("basic", "log_level").upper(), format=" - {thread.name} - {time:YYYY-MM-DD HH:mm:ss:SSSS} : <level>{message}</level>") # 集成到html报告中 class Config: """封装配置文件获取""" def __init__(self): """构建函数""" # 获取配置文件 self.config = configparser.ConfigParser(comment_prefixes='/', allow_no_value=True) # 配置文件存储位置/根目录 try: cur_path = os.path.abspath(os.path.dirname(__file__)) # 获取当前文件的目录 proj_path = cur_path[:cur_path.find('base')] # 获取根目录 self.inipath = os.path.join(proj_path, "config.ini") self.config.read(self.inipath, encoding="utf-8") except Exception as e: print("打开配置文件异常;异常原因:", e) def getConfig(self): """获取配置文件""" return self.config def setConfig(self, section, option, value): """改写配置文件""" # 获取配置文件 self.config.set(section, option, value) with open(self.inipath, 'w+', encoding="utf-8") as confini: self.config.write(confini) # 获取配置文件 config = Config().getConfig() # 根据启动文件名判断是否为pytest,执行日志打印操作 cur_path = os.path.abspath(os.path.dirname(sys.argv[0])) run_file_name = os.path.basename(sys.argv[0]).upper() # print(run_file_name) # 文件以test开头或结尾或在pycase目录下的文件均不打印日志到控制台 to_console = "off" if run_file_name.startswith("TEST") or run_file_name.endswith("TEST") or cur_path.find("pycase") != -1 else "on" Log(to_console=to_console) # logs.debug(to_console) # 该部分只有文件作为脚本时才会被执行,而 import 到其他脚本中是不会被执行的 if __name__ == '__main__': logs.debug('调试') logs.info('正常') logs.warning('警告') logs.error('报错') logs.critical('严重') logs.info(config.get("basic", "log_level"))
执行结果:

-------------------------------------------------------------------------------------
如果万事开头难 那请结局一定圆满 @ Phoenixy
-------------------------------------------------------------------------------------
浙公网安备 33010602011771号