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

如何让日志显示调用Logger的文件行号而非Logger自身文件的行号?

问题:自定义Logger日志的filename和lineno始终指向logger.py而非调用文件

我自定义了Logger类,日志格式如下:

log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"

项目目录结构:

.
├── exceptions.py
├── logger.py
├── settings.py
└── main.py

在main.py中通过Logger.info("Transcribed audio successfully.")调用日志,但日志输出里的filename和lineno始终指向logger.py:

2023-02-15 10:48:06,241.241 INFO     [MainProcess] [MainThread] logger.py:38 --- Transcribed audio successfully.

期望日志显示调用方的文件和行号:

2023-02-15 10:48:06,241.241 INFO     [MainProcess] [MainThread] main.py:98 --- Transcribed audio successfully.

当前logger.py代码:

import logging
from logging.handlers import RotatingFileHandler


class Logger:
    log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"

    @staticmethod
    def setup_single_logger(name, logfile, level):
        handler = RotatingFileHandler(logfile, mode='a', maxBytes=1024 * 1024, backupCount=10)
        handler.setFormatter(logging.Formatter(Logger.log_format))
        logger = logging.getLogger(name)
        logger.setLevel(level)
        logger.addHandler(handler)
        return logger

    @staticmethod
    def setup_logging():
        Logger.info_logger = Logger.setup_single_logger('INFO', '/path/to/your/logfile.log', logging.INFO)

    @staticmethod
    def info(msg, *args, **kwargs):
        Logger.info_logger.info(msg, *args, **kwargs)


Logger.setup_logging()

main.py示例代码:

from logger import Logger

Logger.info("Transcribed audio successfully.")
解决方案

问题根源是:Logger.info作为静态方法,调用info_logger.info时,日志模块会捕获当前栈帧(即logger.py中info方法的行号),而非实际调用Logger.info的位置。需要让日志模块跳过当前栈层级,定位到真正的调用方。

方法1:使用Python 3.8+的stacklevel参数(推荐)

Python 3.8及以上版本的日志模块支持stacklevel参数,指定要跳过的栈层级数。修改Logger.info方法如下:

@staticmethod
def info(msg, *args, **kwargs):
    # stacklevel=2 表示跳过当前方法的栈帧,直接获取调用者的信息
    Logger.info_logger.info(msg, *args, stacklevel=2, **kwargs)

方法2:兼容旧版本Python(手动获取调用者信息)

如果项目运行在Python 3.8以下版本,可通过inspect模块手动提取调用者的栈帧信息,再通过extra参数传递给日志记录器:

import logging
from logging.handlers import RotatingFileHandler
import inspect  # 新增导入


class Logger:
    log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"

    @staticmethod
    def setup_single_logger(name, logfile, level):
        handler = RotatingFileHandler(logfile, mode='a', maxBytes=1024 * 1024, backupCount=10)
        handler.setFormatter(logging.Formatter(Logger.log_format))
        logger = logging.getLogger(name)
        logger.setLevel(level)
        logger.addHandler(handler)
        return logger

    @staticmethod
    def setup_logging():
        Logger.info_logger = Logger.setup_single_logger('INFO', '/path/to/your/logfile.log', logging.INFO)

    @staticmethod
    def info(msg, *args, **kwargs):
        # 获取调用者的栈帧
        frame = inspect.currentframe().f_back
        try:
            # 提取文件名(仅保留最后部分)和行号
            filename = frame.f_code.co_filename.split('/')[-1]
            lineno = frame.f_lineno
            # 传递自定义的文件名和行号
            extra = {'filename': filename, 'lineno': lineno}
            Logger.info_logger.info(msg, *args, extra=extra, **kwargs)
        finally:
            # 手动删除帧引用,避免循环引用导致内存泄漏
            del frame


Logger.setup_logging()

修改后,日志输出将正确显示实际调用日志的文件和行号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:25:22