【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"))
logger.py

 

 

执行结果:

 

 

 

posted @ 2022-04-15 17:21  Phoenixy  阅读(961)  评论(0)    收藏  举报