如何在 Python 日志记录语句中包含模块的相对路径?



我的项目有一个嵌套在根包下的子包,如下所示:

  • mypackage/
    • __init__.py
    • topmodule.py
    • subpackage/
      • __init__.py
      • nested.py

我的目标是获取日志记录的格式,如下所示:

mypackage/topmodule.py:123: First log message
mypackage/subpackage/nested.py:456: Second log message

这样路径在我的终端中变得可点击。


我尝试了以下格式。

  • '%(modulename).pys:%(lineno): %(message)s'不可点击(点需要是斜杠(:

    mypackage.topmodule.py:123: First log message
    mypackage.subpackage.nested.py:456: Second log message
    
  • 'mypackage/%(filename)s:%(lineno): %(message)s'不适用于子包:

    mypackage/topmodule.py:123: First log message
    mypackage/nested.py:456: Second log message
    
  • '%(pathname)s:%(lineno): %(message)s'会产生可点击的路径,但它们太长了,以至于它们切断了我的其余日志记录:

    /Users/jacebrowning/Documents/mypackage/topmodule.py:123: First log message
    /Users/jacebrowning/Documents/mypackage/subpackage/nested.py:456: Second log message
    

是否有一种日志记录模式可以传递给logging.basicConfig(format='???'),以生成我想要的日志记录?

您必须进行其他处理才能在此处获得所需的路径。

您可以通过创建自定义筛选器来执行此类处理并向日志记录添加其他信息,包括您自己的包的"本地"路径。

筛选器实际上不必执行筛选,但它们确实可以访问所有日志记录,因此它们是更新缺少信息的记录的好方法。只需确保完成后返回True

import logging
import os
import sys

class PackagePathFilter(logging.Filter):
def filter(self, record):
pathname = record.pathname
record.relativepath = None
abs_sys_paths = map(os.path.abspath, sys.path)
for path in sorted(abs_sys_paths, key=len, reverse=True):  # longer paths first
if not path.endswith(os.sep):
path += os.sep
if pathname.startswith(path):
record.relativepath = os.path.relpath(pathname, path)
break
return True

这将查找作为日志记录上pathname父目录的sys.path条目,并在日志记录上添加新的relativepath条目。然后,您可以使用%(relativepath)s将其包含在日志中。

将筛选器添加到使用自定义格式化程序配置的任何处理程序

handler.addFilter(PackagePathFilter())

并与'%(relativepath)s:%(lineno)s: %(message)s'一起作为日志消息的格式

,如下所示:
mypackage/topmodule.py:123: First log message
mypackage/subpackage/nested.py:456: Second log message

(实际输出,除了我更改了行号(。

这会产生相同的结果。

import os
import logging
class PackagePathFilter(logging.Filter):
def filter(self, record):
record.pathname = record.pathname.replace(os.getcwd(),"")
return True

添加处理程序

handler.addFilter(PackagePathFilter())

并与'%(pathname)s:%(lineno)s: %(message)s'一起作为日志的格式。

最新更新