Python Loguru日志封装 - 装饰器实现

发布时间 2023-06-29 20:54:49作者: 搬砖路上的大马猴

Python Loguru日志封装

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# @Time    : 2023/6/25 15:49
# @Author  : jingang.hou082613@gmail.com
# @Site    : 
# @File    : operateLogs.py
# @Software: PyCharm
""" 日志处理 """
import inspect
import os
import sys
from functools import wraps
from time import strftime
from time import perf_counter
from base.singletonModel import Singleton
from loguru import logger
from utils.operateFile._ini import IniFile


class MyLogs(metaclass=Singleton):
    LOG_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "../logs")   # 存放日志
    INI_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "../config/log_config.ini")  # ini配置文件
    ini_data = IniFile(INI_DIR).get_itemsAll()  # 获取ini配置中的数据
    logger_h = logger.opt(colors=True)

    def __new__(cls, *args, **kwargs):
        # hasattr是Python的一个内置函数,用于检查对象是否具有指定的属性或方法。
        if not hasattr(cls, '_logger'):
            cls._setup_logger()
        return super().__new__(cls)

    @classmethod
    def _setup_logger(cls):
        logger.remove()
        # 设置日志文件路径和格式
        filename = strftime("%Y%m%d-%H%M%S")
        log_file_path = os.path.join(cls.LOG_DIR, f'{filename}.log')
        log_format = "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | " \
                     "<level>{level}</level> " \
                     "| <level>{message}</level>"
        level_: str = MyLogs.ini_data["level"]
        rotation_: str = MyLogs.ini_data["rotation"]

        # 添加日志处理器:写入文件

        cls.logger_h.add(log_file_path,
                         enqueue=True,
                         backtrace=True,
                         diagnose=True,
                         encoding="utf8",
                         rotation=rotation_
                         )

        # 添加日志处理器:控制台输出
        cls.logger_h.add(
            sys.stderr,
            format=log_format,
            enqueue=True,
            colorize=True,
            backtrace=True,
            diagnose=True,
            level=level_,
            # filter=cls._debug_filter  # 使用自定义过滤器函数

        )

    # @staticmethod
    # def _debug_filter(record):
    #     """自定义过滤器函数,仅输出 DEBUG 级别的日志"""
    #     if record["level"].name == MyLogs.ini_data["filter_level"]:
    #         return True
    #     return False

    @classmethod
    def log(cls, level: str, msg: str):
        """
        ···

        :param level: 日志等级:info,debug,trace,error,warning,critical,exception
        :param msg: 要输出的内容
        :return: msg

        # 栗子
        MyLogs.log("info", "-----------分割线-----------")

        """
        getattr(cls.logger_h, level)(msg)

    @classmethod
    def log_decorator(cls, msg: str):
        """
         日志装饰器,记录函数的名称、参数、返回值、运行时间和异常信息

         栗子:
            @log.log_decorator("这里填写def功能")
                def test_zero_division_error(a, b):
                    return a / b
         """

        def decorator(func):
            func_line = inspect.currentframe().f_back.f_lineno

            @wraps(func)
            def wrapper(*args, **kwargs):
                cls.log("info", "\n")
                cls.log("info", "<green>-----------分割线-----------</>")
                cls.log("info", f"<white>{msg}  ↓↓↓</>")
                cls.log("debug", f'<red>{func.__qualname__}:{func.__name__}:{func_line} |</>  <white> args: {args}, kwargs:{kwargs}</>')

                start = perf_counter()
                try:
                    result = func(*args, **kwargs)
                    end = perf_counter()
                    duration = end - start
                    cls.log("debug",
                            f"<red>{func.__qualname__}:{func.__name__}:{func_line} |</>  <white> 返回结果:{result}, 耗时:{duration:4f}s</>")
                    return result

                except Exception as e:
                    cls.log("exception", f"<red>{func.__qualname__}:{func.__name__}:{func_line} |</>: {msg}")

                finally:
                    cls.log("info", "<green>-----------分割线-----------</>")

            return wrapper

        return decorator


MyLogs()
if __name__ == '__main__':
    MyLogs.log("debug", "Executing step 3 of the algorithm")
    MyLogs.log("info", "Server started on port")
    MyLogs.log("warning", "Invalid input provided, using default values")
    MyLogs.log("error", "Invalid user input detected, unable to proceed")
    MyLogs.log("critical", "Database connection lost, terminating the application")


    @MyLogs.log_decorator("1111111111111111111")
    def A(a, b):
        a / b


    A(1, 0)

输出结果:

image-20230629204434899