如何在整个程序中一次在python中定义一个记录器? [英] How to define a logger in python once for the whole program?

查看:66
本文介绍了如何在整个程序中一次在python中定义一个记录器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的Python项目中设置一次记录器,并在整个项目中使用它.

I want to set up my logger once in my Python project and use that throughout the project.

main.py:

import logging
import test    

hostname = {"hostname": socket.gethostname()}
logger = logging.getLogger()
syslog = logging.StreamHandler()
formatter = logging.Formatter("{\"label\":\"%(name)s\", \"level\":\"%(levelname)s\", \"hostname\":\"%(hostname)s\", \"logEntry\": %(message)s, \"timestamp\", \"%(asctime)s\"}")
syslog.setFormatter(formatter)
logger.setLevel(logging.DEBUG)
logger.addHandler(syslog)
logger = logging.LoggerAdapter(logger, hostname)

def entry_point():
    logger.debug("entry_point")
    test.test_function()

entry_point()

test.py:

import logging

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

def test_function():
    logger.debug("test_function")

这应该给我:

entry_point
test_function

...都使用格式提供程序进行了格式化.

... both formatted with the format provider.

但是实际上我得到一个错误KeyError: 'hostname',因为似乎第二个记录器不知道hostname格式提供程序.我也尝试过使用__name__初始化两个记录器,但随后我得到了No handlers could be found for logger "test".

However I actually get an error KeyError: 'hostname' because it would seem the second logger does not know about the hostname format provider. I've also tried initialising both loggers with __name__ but then I get No handlers could be found for logger "test".

有没有一种方法可以一次定义日志记录配置,然后在整个应用程序中重复使用它?

Is there a way I can define my logging configuration once and re-use it throughout my application?

推荐答案

LoggingAdapter是一个单独的对象,它不替代logging.getLogger()调用的结果.您需要将其存储在可以在不同模块之间共享的位置.例如,您可以使用一个单独的模块,项目中的其他所有内容都可以从该模块中导入.

A LoggingAdapter is a separate object, it does not replace the result of logging.getLogger() calls. You'll need to store it somewhere that it can be shared between different modules. You could use a separate module that everything else in your project imports from, for example.

我将在下面详细说明如何处理,但还有一个替代方案,它根本不涉及适配器,而是使用附加到您创建的处理程序的过滤器,从而避免了处理适配器的麻烦.共.进一步查看.

I'll detail below how to handle this, but there is also an alternative that doesn't involve adapters at all, and instead uses a filter which is attached to the handler you created, letting you avoid having to deal with adapters altogether. See further down.

我也将配置和日志对象处理分开了;让主模块调用"setup"功能来配置处理程序和日志级别,并在模块中设置适配器以供其他人导入:

I'd separate out configuration and log object handling too; have the main module call the 'setup' function to configure the handlers and log levels, and set up the adapter in the module for others to import:

log.py:

import logging
import socket
def setup_logging():
    """Adds a configured stream handler to the root logger"""
    syslog = logging.StreamHandler()
    formatter = logging.Formatter(
        '{"label":"%(name)s", "level":"%(levelname)s",'
        ' "hostname":"%(hostname)s", "logEntry": %(message)s,'
        ' "timestamp", "%(asctime)s"}')
    syslog.setFormatter(formatter)

    logger = logging.getLogger()
    logger.addHandler(syslog)
    logger.setLevel(logging.DEBUG)


def host_log_adapter(logger):
    hostname = {"hostname": socket.gethostname()}
    return logging.LoggerAdapter(logger, hostname)


logger = host_log_adapter(logging.getLogger())

然后在main中执行:

import log
import test

log.setup_logging()

def entry_point():
    log.logger.debug("entry_point")
    test.test_function()

entry_point()

test中的

from log import logger

def test_function():
    logger.debug("test_function")

或者,您可以使用过滤器通过(ab)将信息添加到日志记录中,而不是使用 adapter :

Alternatively, rather than use an adapter, you could add information to log records by (ab)using a filter:

class HostnameInjectingFilter(logging.Filter):
    def __init__(self):
        self.hostname = socket.gethostname()}
    def filter(self, record):
        record.hostname = self.hostname
        return True

这直接在记录对象上添加了额外的字段,并且始终返回True.然后只需将此过滤器添加到需要具有可用主机名的处理程序中即可:

This adds the extra field directly on the record object and always returns True. Then just add this filter to the handler that needs to have the hostname available:

syslog = logging.StreamHandler()
formatter = logging.Formatter(
    '{"label":"%(name)s", "level":"%(levelname)s",'
    ' "hostname":"%(hostname)s", "logEntry": %(message)s,'
    ' "timestamp", "%(asctime)s"}')
syslog.setFormatter(formatter)
syslog.setFilter(HostnameInjectingFilter())

这完全不需要使用适配器,因此您可以完全删除host_log_adapter()功能,而只需在任何地方使用logging.getLogger().

This removes the need to use an adapter entirely, so you can remove the host_log_adapter() function entirely and just use logging.getLogger() everywhere.

这篇关于如何在整个程序中一次在python中定义一个记录器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆