首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用structlog添加代码行号

如何使用structlog添加代码行号
EN

Stack Overflow用户
提问于 2019-02-26 02:21:46
回答 2查看 1.3K关注 0票数 10

使用python标准日志记录模块,可以使用以下命令添加发起日志调用的行号:%(lineno)s.

如何使用structlog来实现这一点?

EN

回答 2

Stack Overflow用户

发布于 2019-07-05 09:30:26

我也有类似的需求,我最终创建了一个custom processor

what structlog does被告知要“假装”以与logging库兼容的模式进行格式化时(意思是:当它使用常规stdlib.LoggerFactory时),我查看了一下它以输出模块和行号,我从中找到了灵感。关键是下面这几个字。

通过使用结构日志的structlog.stdlib.LoggerFactory,还可以确保像函数名和行号这样的变量在您的日志格式中正确展开。

..。来自this documentation page

代码似乎一直在寻找执行框架,直到它找到一个与日志记录无关的模块。

我将structlog的所有设置都放在一个名为my_libs.util.logger的模块中,所以我希望获得不在该模块中的第一个帧。为此,我告诉它将与日志相关的my_libs.util.logger添加到这些排除项中。下面代码中的additional_ignores就是这样做的。

在示例中,为了清楚起见,我在排除列表中硬编码了模块的名称('my_libs.util.logger'),但是如果您有类似的设置,那么使用__name__可能会更好。这样做的目的是忽略由于适当的日志机制而存在的执行框架。您可以将其视为忽略在实际记录消息的过程中可能发生的调用的一种方式。或者,换句话说,在您希望输出的实际模块/行中发生的logging.info("Foo")之后发生的调用。

一旦找到正确的框架,就可以提取任何类型的信息(模块名、函数名、行号……)是非常简单的,特别是使用inspect module。我选择输出模块名称和行号,但可以添加更多字段。

代码语言:javascript
复制
# file my_libs/util/logger.py
import inspect
from structlog._frames import _find_first_app_frame_and_name

def show_module_info_processor(logger, _, event_dict):
    # If by any chance the record already contains a `modline` key,
    # (very rare) move that into a 'modline_original' key
    if 'modline' in event_dict:
        event_dict['modline_original'] = event_dict['modline']
    f, name = _find_first_app_frame_and_name(additional_ignores=[
        "logging",
        'my_libs.util.logger',  # could just be __name__
    ])
    if not f:
        return event_dict
    frameinfo = inspect.getframeinfo(f)
    if not frameinfo:
        return event_dict
    module = inspect.getmodule(f)
    if not module:
        return event_dict

    if frameinfo and module:
        # The `if` above is probably redundant, since we already
        # checked for frameinfo and module but... eh... paranoia.
        event_dict['modline'] = '{}:{}'.format(
            module.__name__,
            frameinfo.lineno,
        )
    return event_dict

def setup_structlog(env=None):
    # . . . 
    ch.setFormatter(logging.Formatter('%(message)s'))

    logging.getLogger().handlers = [ch]

    processors = [
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        # . . . more . . . 
        show_module_info_processor,  # THIS!!!
        structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S"),
        structlog.processors.format_exc_info,
        structlog.processors.StackInfoRenderer(),
        # . . . more . . . 
    ]

    # . . . more . . . 
    structlog.configure_once(
        logger_factory=structlog.stdlib.LoggerFactory(),
        wrapper_class=structlog.stdlib.BoundLogger,
        context_class=structlog.threadlocal.wrap_dict(dict),
        processors=processors,
    )

这将产生类似以下内容的输出:

代码语言:javascript
复制
server_1                           
| INFO  [my_libs.hdfs] 2019-07-01 01:01:01 [info     ] Initialized HDFS               
[my_libs.hdfs] modline=my_libs.hdfs:31
票数 5
EN

Stack Overflow用户

发布于 2019-03-18 20:47:58

让我们看一下如何获得行号这一更一般问题的答案。https://stackoverflow.com/a/3056270/5909155无法使用log.bind(...)将其绑定到记录器因为您每次登录时都要对其进行评估。因此,您应该像这样添加一个键-值对

代码语言:javascript
复制
logger.log(..., lineno=inspect.getframeinfo(inspect.currentframe()).lineno)

每一次。也许可以将其封装在一个函数中,如下所示:https://stackoverflow.com/a/20372465/5909155不要忘了

代码语言:javascript
复制
import inspect
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54872447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档