Python 如何在 logging 中自动添加当前函数名和行号

10次阅读

python Logging可通过%(funcName)s和%(lineno)d自动添加函数名与行号,需在Formatter中配置格式字符串封装日志函数时应设stacklevel=2以准确定位调用位置。

Python 如何在 logging 中自动添加当前函数名和行号

在 Python 的 logging 模块中,可以通过配置日志格式自动添加当前函数名和行号,无需每次手动传入。关键在于使用内置的格式化占位符 %(funcName)s%(lineno)d,并确保日志记录时能正确捕获调用位置(默认即可,无需额外设置)。

配置 logging 格式字符串

在初始化 logger 时,通过 Formatter 指定包含函数名和行号的格式:

  • %(funcName)s:自动提取日志调用所在函数的名称(注意:不是被调用函数,而是写 logger.info(...) 那一行所在的函数)
  • %(lineno)d:自动提取该日志语句所在的源代码行号
  • 其他常用占位符如 %(filename)s%(levelname)s%(asctime)s 可一并加入,提升可读性

示例:

import logging 

formatter = logging.Formatter( '[%(asctime)s] %(levelname)-8s %(filename)s:%(lineno)d %(funcName)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' )

handler = logging.streamHandler() handler.setFormatter(formatter)

logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.addHandler(handler)

def example(): logger.debug("这条日志会显示函数名和行号")

example()

输出类似:
[2024-05-20 10:30:45] DEBUG test.py:12 example - 这条日志会显示函数名和行号

立即学习Python免费学习笔记(深入)”;

确保 logger 记录的是调用点而非内部位置

logging 默认使用 stacklevel=1,即向上查 1 层帧,正好定位到你写 logger.xxx() 的那行。一般无需改动。但如果你封装了日志函数(比如写了个 log_debug(msg)),则需显式设 stacklevel=2,否则函数名会显示为 log_debug,行号也会是封装函数内的行号。

  • 封装日志时,在调用 logger.xxx() 时加参数:extra={...}, stacklevel=2
  • 或直接用 logger.log(level, msg, stacklevel=2)

推荐的最小实用配置(支持文件+控制台)

兼顾开发调试与简单部署:

import logging 

def setup_logger(name=name, level=logging.DEBUG): logger = logging.getLogger(name) logger.setLevel(level)

# 避免重复添加 handler if not logger.handlers:     formatter = logging.Formatter(         '%(asctime)s | %(levelname)-8s | %(funcName)s:%(lineno)d | %(message)s',         datefmt='%H:%M:%S'     )      ch = logging.StreamHandler()     ch.setFormatter(formatter)     logger.addHandler(ch)      # 可选:添加文件 handler     # fh = logging.FileHandler('app.log')     # fh.setFormatter(formatter)     # logger.addHandler(fh)  return logger

logger = setup_logger()

注意事项

  • 函数名取自调用日志语句的函数,不是被调用函数;若在 Lambda 或顶层模块中调用,funcName 会显示为
  • lineno 是日志语句本身所在行,不是函数定义行
  • 线程下信息仍准确,logging 内部基于当前线程帧获取
  • 性能影响极小,格式化只在实际输出时发生(除非设置了 logging.basicConfig(level=logging.DEBUG) 且日志未被过滤)

text=ZqhQzanResources