如何在Python中记录源文件名和行号

是否可以修饰/扩展Python标准日志记录系统,以便在调用日志记录方法时,它也记录文件和调用它的行号,或者可能是调用它的方法?

126283 次浏览

当然,检查日志文档中的格式化程序。特别是LINENO和PATHNAME变量。

%(路径名)s发出日志记录调用的源文件的完整路径名(如果可用)。

__路径名的ABC0文件名部分。

%(模块)s模块(文件名的名称部分)。

%(funcName)s包含日志记录调用的函数的名称。

发出日志记录调用的%(行号)d源行号(如果可用)。

看起来像这样:

formatter = logging.Formatter('[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s','%m-%d %H:%M:%S')

Seb非常有用的答案之上,有一个方便的代码片段,它以合理的格式演示了记录器的用法:

#!/usr/bin/env python
import logging


logging.basicConfig(format='%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d:%H:%M:%S',
level=logging.DEBUG)


logger = logging.getLogger(__name__)
logger.debug("This is a debug log")
logger.info("This is an info log")
logger.critical("This is critical")
logger.error("An error occurred")

生成以下输出:

2017-06-06:17:07:02,158 DEBUG    [log.py:11] This is a debug log
2017-06-06:17:07:02,158 INFO     [log.py:12] This is an info log
2017-06-06:17:07:02,158 CRITICAL [log.py:13] This is critical
2017-06-06:17:07:02,158 ERROR    [log.py:14] An error occurred

以将调试日志记录发送到标准输出的方式在上述基础上进行构建:

import logging
import sys


root = logging.getLogger()
root.setLevel(logging.DEBUG)


ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.DEBUG)
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
formatter = logging.Formatter(FORMAT)
ch.setFormatter(formatter)
root.addHandler(ch)


logging.debug("I am sent to standard out.")

将上述内容放入名为debug_logging_example.py的文件中,将生成以下输出:

[debug_logging_example.py:14 -             <module>() ] I am sent to standard out.

然后,如果要关闭日志记录,请注释掉root.setLevel(logging.DEBUG)

对于单个文件(例如,课堂作业),我发现这是一种比使用print()语句更好的方法。它允许您在提交之前在单个位置关闭调试输出。

对于使用PyCharm或Eclipse PyDev的开发人员,以下内容将在控制台日志输出中生成指向日志语句源的链接:

import logging, sys, os
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format='%(message)s | \'%(name)s:%(lineno)s\'')
log = logging.getLogger(os.path.basename(__file__))




log.debug("hello logging linked to source")

有关详细讨论和历史,请参见Eclipse控制台中的Pydev源文件超链接

import logging


# your imports above ...




logging.basicConfig(
format='%(asctime)s,%(msecs)d %(levelname)-8s [%(pathname)s:%(lineno)d in ' \
'function %(funcName)s] %(message)s',
datefmt='%Y-%m-%d:%H:%M:%S',
level=logging.DEBUG
)


logger = logging.getLogger(__name__)


# your classes and methods below ...
# A very naive sample of usage:
try:
logger.info('Sample of info log')
# your code here
except Exception as e:
logger.error(e)

与其他答案不同的是,这将记录文件的完整路径和可能发生错误的函数名称。如果您有一个包含多个模块的项目,并且这些模块中分布了多个同名文件,这将非常有用。

示例输出:

2022-12-02:10:00:00,000 INFO     [<stdin>:2 in function <module>] Sample of info log
2022-12-02:10:00:00,000 INFO     [<full path>/logging_test_file.py:15 in function <module>] Sample of info log

如果使用GetLogger(名称)选项设置记录器,其中名称是您指定的名称,则还可以使用%(name)s格式化记录器。您可以使用GetLogger函数在每个文件中指定不同的名称,当生成日志时,您将知道您设置的名称来自哪个文件。

示例:

import logging


logging.getLogger("main")
logging.basicConfig(#filename=log_fpath,
level=log_level,
format='[%(asctime)s] src:%(name)s %(levelname)s:%(message)s',
handlers=[logging.FileHandler(log_fpath)])