logging日志改造---自定义参数传递到格式中

文章介绍了如何在Python的日志记录中添加自定义参数,并通过Logger类实现。讨论了现有代码的问题,即定位到错误代码位置的问题,以及提供了一个解决方案,即通过修改调用链获取更精确的上下文信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:需求

  • 需求:将自定义的参数,放在日志的指定格式中。

二:实现方式

  • 例如:让debug, info,warning,error函数都允许传递一个trace_id, 并将这个trace_id输出到我们自定义日志指定的格式中。
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time   : 2023/10/19 10:08
    # @Author : shanwen.ren
    import logging
    import inspect
    import logging.config
    
    self_logger = logging.getLogger("debug")
    
    
    class Logger(logging.Logger):
    
        @staticmethod
        def check_trace_id(kwargs):
            """kwargs mush has trace_id and trace_id value type mush is str."""
            trace_id = str(kwargs.get("trace_id", ""))
            if "extra" not in kwargs:
                extra = {"trace_id": trace_id}
            else:
                assert isinstance(kwargs["extra"], dict)
                extra = kwargs["extra"]
                extra.update({"trace_id": trace_id})
    
            if "trace_id" in kwargs.keys():
                kwargs.pop("trace_id")
            return extra, kwargs
    
        def debug(self, msg, *args, **kwargs):
            extra, kwargs = self.check_trace_id(kwargs)
            self_logger.debug(msg, *args, extra=extra, **kwargs)
    
        def info(self, msg, *args, **kwargs):
            extra, kwargs = self.check_trace_id(kwargs)
            self_logger.info(msg, *args, extra=extra, **kwargs)
    
        def warning(self, msg, *args, **kwargs):
            extra, kwargs = self.check_trace_id(kwargs)
            self_logger.warning(msg, *args, extra=extra, **kwargs)
    
        def error(self, msg, *args, **kwargs):
            extra, kwargs = self.check_trace_id(kwargs)
            self_logger.error(msg, *args, extra=extra, **kwargs)
    
    
    logger = Logger()
    
    
    def init_log(log_path, log_name, log_level="DEBUG"):
        log_level = log_level.upper()
        LOG_PATH_DEBUG = "%s/%s.log" % (log_path, log_name)
        LOG_FILE_BACKUP_COUNT = 10
    
        log_conf = {
            "version": 1,
            "formatters": {
                "format1": {
                    "format": '|%(asctime)s.%(msecs)03d|%(levelname)s|%(trace_id)s|%(thread)d|%(filename)s %(lineno)d|%(message)s',
                    "datefmt": '%Y-%m-%d %H:%M:%S',
                },
            },
    
            "handlers": {
                "handler": {
                    "class": "logging.handlers.TimedRotatingFileHandler",
                    "level": log_level,
                    "formatter": "format1",
                    "when": "midnight",
                    "backupCount": LOG_FILE_BACKUP_COUNT,
                    "filename": LOG_PATH_DEBUG
                },
            },
    
            "loggers": {
                "debug": {
                    "handlers": ["handler"],
                    "level": log_level
                },
            }
        }
        logging.config.dictConfig(log_conf)
    
    
    def close_log():
        logging.shutdown()
    

三:存在的问题

3.1: 问题描述

  • 上面代码中由于本质是使用的self_logger对象, 因此filename和lineno都会定位到我们自定义的Logger对象的debug, info,warning,error方法中, 无法真正的定位到真实代码所在地。

3.2: 源码分析

  • 调用warning后会调用_log方法。
    在这里插入图片描述
  • findCaller会去取调用位置。
    在这里插入图片描述
  • 底层使用f_back获取上层调用, 返回上层调用的行号lno等信息。
    在这里插入图片描述
  • makeRecord最终作用于日志格式中。
    在这里插入图片描述

3.3: 解决方案

  • 基于源码分析, 发现底层用的inspect.currentframe().f_back,返回的上层调用者, 因此产生一个思路:废弃日志格式中的文件名和行号, 改成自己传递N-任意层调用的位置和行号。
  • 代码调整:
    在这里插入图片描述
    在这里插入图片描述
  • 改为自定义名称原因:
    在这里插入图片描述

四:相关链接

  • 官方文档:https://docs.python.org/zh-cn/3/library/logging.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈何桥上的幽灵野草

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值