You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Python logging显示间接调用者的源代码行号?

解决Python Logging封装中行号显示为封装文件而非调用文件的问题

首先,先看一下你当前的log.py代码:

from .color import Color
import logging

class Log:
    logging.basicConfig(
        format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
        datefmt='%d-%m-%Y:%H:%M:%S',
        level=logging.INFO
    )
    logger = logging.getLogger('anywordcanbethis')

    @classmethod
    def warning(self, msg):
        Log.logger.warning(Color.fg.yellow + msg + Color.reset)

    @classmethod
    def error(self, msg):
        Log.logger.error(Color.fg.red + msg + Color.reset)

    @classmethod
    def debug(self, msg):
        Log.logger.info(Color.fg.pink + msg + Color.reset)

你遇到的问题是:当其他文件调用Log.warning()或Log.error()时,日志里的filename和lineno始终指向log.py里的行号,而不是调用方的文件和行号。这是因为logging默认记录的是直接调用logger.warning()/logger.error()的位置——也就是你封装的这些类方法内部的行号,而不是上层调用者的位置。

下面给你两种可行的解决方案,根据你的Python版本选择:

方案一:Python 3.8+ 推荐使用stacklevel参数

从Python 3.8开始,logging的日志方法(warning/error/info等)新增了stacklevel参数,用来指定要跳过多少层栈帧,直接获取上层调用者的信息。

你只需要修改Log类里的三个方法,给每个日志调用加上stacklevel=2:

@classmethod
def warning(cls, msg):
    Log.logger.warning(Color.fg.yellow + msg + Color.reset, stacklevel=2)

@classmethod
def error(cls, msg):
    Log.logger.error(Color.fg.red + msg + Color.reset, stacklevel=2)

@classmethod
def debug(cls, msg):
    Log.logger.info(Color.fg.pink + msg + Color.reset, stacklevel=2)

这里的stacklevel=2表示:跳过当前的Log.warning()这一层栈帧,直接取调用Log.warning()的那个代码位置的信息。修改后,日志里就会显示调用方的文件名和行号了。

方案二:Python 3.7及以下 自定义Logger子类重写findCaller

如果你的项目还在使用Python 3.7或更早的版本,没有stacklevel参数,可以通过自定义Logger子类,重写findCaller方法来实现。这个方法的作用是找到日志调用的栈帧信息,我们让它多跳过一层即可:

from .color import Color
import logging

class MyLogger(logging.Logger):
    def findCaller(self, stack_info=False, stacklevel=1):
        # 多跳过一层栈帧,跳过Log类的方法调用
        return super().findCaller(stack_info, stacklevel + 1)

class Log:
    # 先设置自定义的Logger类
    logging.setLoggerClass(MyLogger)
    logging.basicConfig(
        format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
        datefmt='%d-%m-%Y:%H:%M:%S',
        level=logging.INFO
    )
    logger = logging.getLogger('anywordcanbethis')

    @classmethod
    def warning(cls, msg):
        Log.logger.warning(Color.fg.yellow + msg + Color.reset)

    @classmethod
    def error(cls, msg):
        Log.logger.error(Color.fg.red + msg + Color.reset)

    @classmethod
    def debug(cls, msg):
        Log.logger.info(Color.fg.pink + msg + Color.reset)

这样修改后,Logger在查找调用栈时会自动跳过你封装的Log类方法那一层,直接记录调用方的文件和行号。

验证效果

假设你在main.py的第10行调用:

from log import Log
Log.warning("测试警告日志")

修改后的日志会显示:

31-05-2018:18:06:45,313 WARNING  [main.py:10] 测试警告日志 (yellow)

而不是之前的log.py:12了。

内容的提问来源于stack exchange,提问作者kispi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:43:26