Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建以日志消息为前缀的记录器_Python_Logging - Fatal编程技术网

Python 创建以日志消息为前缀的记录器

Python 创建以日志消息为前缀的记录器,python,logging,Python,Logging,假设我有一个客户机和服务器类: import logging class Client: def __init__(self, name): self.logger = logging.getLogger(self.__class__.__name__) self.name = name def foo(self): self.logger.warn('[%s] foo', self.name) class Server:

假设我有一个客户机和服务器类:

import logging

class Client:
    def __init__(self, name):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.name = name

    def foo(self):
        self.logger.warn('[%s] foo', self.name)

class Server:
    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)

    def bar(self):
        self.logger.warn('bar')

我怎样才能为客户端创建一个记录器,神奇地处理
[self.name]
前缀?我唯一的想法是设置一个全局格式,包括
%(客户端)
-前缀,并为
客户端使用自定义过滤器。这似乎是不必要的、复杂的和全球性的。我觉得一定有一种我看不到的简单方法。

这可以通过使用库来完成(免责声明:我制作该库是为了让它更简单,但也可以使用标准库来完成)

填写客户端名称可以作为记录器的
格式化程序的一部分来完成,该格式化程序将日志记录格式化为字符串,在该步骤中,您可以为消息添加前缀

创建记录器:

import logging

logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter("%(client)s: %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
指定此记录器的客户端名称(即,在上述格式化日志字符串中为
%(客户端)s
填写的值):

logaugment.set(logger, client='Client')
从现在起,您可以像往常一样调用记录器方法,并自动填写客户端名称:

logger.warn("My message")

使用自定义的
LoggerAdapter
,无需任何附加依赖即可完成此操作:

import logging

class LoggerAdapter(logging.LoggerAdapter):
    def __init__(self, prefix, logger):
        super(LoggerAdapter, self).__init__(logger, {})
        self.prefix = prefix

    def process(self, msg, kwargs):
        return '[%s] %s' % (self.prefix, msg), kwargs

class Client:
    def __init__(self, name):
        logger = logging.getLogger(self.__class__.__name__) 
        self.logger = LoggerAdapter(name, logger)
        self.name = name

    def foo(self):
        self.logger.warning('foo: %s', 'bar')

client = Client('client1')
logging.basicConfig(format='%(message)s')
client.foo()
哪个应该打印

[client1] foo: bar

我想在C#world中使用类似PrefixedLog的东西,包装日志实例,但在Python世界中,日志记录的配置不同(不是传递实例,而是调用
getLogger
并依赖为库定义的处理程序似乎很常见)

Vitaly的回答很好,但如果您尝试链接适配器,则会失败,因为
logging.LoggerAdapter
不会继承
logging.Logger
。我的解决方案是:

导入日志
类前缀Logger(logging.LoggerAdapter):
定义初始化(self、前缀、记录器):
前缀=“[{}]”。格式(前缀)
#hack,因为LoggerAdapter不是从Logger继承的
如果存在(记录器、前置记录器):
内部前缀=logger.prefix
内部记录器=logger.logger
prefix=“{}{}”。格式(内部前缀,前缀)
记录器=内部记录器
super(PrefixedLogger,self)。\uuuu init\uuuu(logger,{})
self.logger=记录器
self.prefix=前缀
def流程(自我、味精、kwargs):
返回“%s%s%”(self.prefix,msg),kwargs

另一种解决方案是使用extradict指定前缀

首先,像平常一样创建记录器,例如:

logger = logging.getLogger(__name__)
# Add any custom handlers, formatters for this logger
myHandler = logging.StreamHandler()
myFormatter = logging.Formatter('%(myApp)s - %(message)s') # Note the myApp key here
myHandler.setFormatter(myFormatter)
logger.addHandler(myHandler)
logger.setLevel(logging.INFO)
请注意,我们是如何以以下格式添加一个新键的:myApp。然后从客户端创建一个LoggerAdapter,并为myApp指定一个带有自定义值的extradict:

logger = logging.LoggerAdapter(logger, extra={'myApp': 'Client'})
logger.info('All your base are belong to us')
这将打印:

Client - All your base are belong to us
Server - All your base are belong to us
类似地,您可以通过服务器按如下方式进行日志记录:

logger = logging.LoggerAdapter(logger, extra={'myApp': 'Server'})
logger.info('All your base are belong to us')
这将打印:

Client - All your base are belong to us
Server - All your base are belong to us

另一种方法是更新当前处理程序,使其具有新的格式。 这将向输出中添加pytest函数名:

@pytest.fixture(scope="function", autouse=True)
def setLoggerPrefix(request):
    ''' add the test name to the logging messages '''

    # Prepare the test name.
    testName = request.function.__name__[len("test_"):]

    logger = logging.getLogger()
    myFormatter = logging.Formatter('%(levelname)s:[' + testName + '] - %(message)s')

    # Set each logger to have this new format
    myHandler = logging.StreamHandler()
    myHandler.setFormatter(myFormatter)
    for handler in logger.handlers:
        handler.setFormatter(myHandler)
输出现在看起来像:

INFO:[validate_page] - <some message here>
INFO:[validate_page] - <some other message here>
PASSED                                                                   [ 14%]
------------------------------ live log teardown ------------------------------
INFO:[validate_all_pages] - <some teardown message here>

tests/application/test_users/test_create_users.py::test_create_users
------------------------------- live log setup --------------------------------
INFO:[create_users] - <some message here>
INFO:[create_users] - <some other message here>
..
INFO:[验证页面]-
信息:[验证页面]-
通过[14%]
------------------------------活原木拆卸------------------------------
信息:[验证所有页面]-
tests/application/test\u users/test\u create\u users.py::test\u create\u users
-------------------------------实时日志设置--------------------------------
信息:[创建用户]-
信息:[创建用户]-
..
使用日志适配器:

logger=PrefixLoggerAdapter(logger,dict(prefix='username'))
logger.info('hey')
#信息[用户名]嘿
这是一节课:

class PrefixLoggerAdapter(logging.LoggerAdapter):
“”“为每条消息添加前缀的记录器适配器”“”
def过程(self,msg:str,kwargs:dict)->(str,dict):
返回(f'[{self.extra[“昵称”]}]'+msg,kwargs)

我是否需要在本地为客户端记录器指定处理程序以应用格式化程序?这似乎阻止我全局设置处理程序(例如,应用程序决定日志是转到文件还是stdout)@Zulan:如果记录器已经有一个处理程序,那么您可以更改该处理程序的格式化程序。因此,您确实可以为所有记录器全局创建处理程序,然后稍后修改格式化程序。