如何区分 Python logging 中的文件和子模块?

How to distinguish between files and submodules in Python logging?

我写了一个子模块,在那里我定义了日志记录,因为我主要使用我的子模块来重用我不同的其余 api 项目中的代码。如何设置我的自定义日志记录,以便日志记录知道哪个代码(main.pysub.py)调用了日志记录?我尝试使用 __file__,但它总是显示 "sub.py"。

我的子模块:

# sub.py
import logging
from secrets import token_urlsafe

# 
def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.session_id = session_id

    # What do I do here?
    # This doesn't work:
    record.src = __file__

    return record

session_id = token_urlsafe(8)

logger = logging.getLogger(__name__)
old_factory = logging.getLogRecordFactory()
logging.setLogRecordFactory(record_factory)

# Always prepend session_id and src to logs
format = logging.Formatter("%(asctime)s %(session_id) %(src) %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
handler = logging.StreamHandler()
handler.setFormatter(format)
logger.addHandler(handler)

logger.info("Hello!") # Should also print out "sub.py".

我的主脚本:

# main.py
import logging
import sub

logger = logging.getLogger("sub")
logger.info("Hi!") # Should also print out "main.py".

Logging 为模块名称提供了一个属性,与 __file__ 的值相同,名称为 pathname

%(src)s替换为%(pathname)s

Logger 的方法是通过 Logger.findCaller 方法中的堆栈检查。它在堆栈中向上走,直到找到一个不在日志记录模块中的帧。然后提取该帧的文件名、行号和函数名。

有关 __name__ 的问题,请参阅 Is module __file__ attribute absolute or relative?

在这种情况下,您可以使用 inspect 模块。

import inspect as insp

def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.session_id = session_id

    (filename, line_number,func_name, lines, index) = insp.getframeinfo(insp.currentframe().f_back)

    #Do whatever with this values.
    return record

currentframe() 的工作方式是 returns 调用者栈帧的帧对象。这可以传递到 getframeinfo() 方法中。

在此处查找更多详细信息:inspect Module