没有子类的最基本的日志记录处理程序

时间:2019-12-13 00:42:53

标签: python python-3.x logging

在继承logging.Handler的同时,我可以通过执行以下操作来创建自定义处理程序:

import requests
import logging

class RequestsHandler(logging.Handler):
    def emit(self, record):
        res = requests.get('http://google.com')
        print (res, record)

handler = RequestsHandler()
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.warning('ok!')
# <Response [200]> <LogRecord: __main__, 30, <stdin>, 1, "ok!">

如果最简单的RequestHandler是基类而不是子类logging.Handler,那将是最简单的{{1}}(需要什么方法?)?

2 个答案:

答案 0 :(得分:1)

查看Logger.log的来源会将我带到Logger.callHandlers,它仅在处理程序上调用handle。因此,如果您将假处理程序直接注入到记录器实例中,那么这可能是您所需的最低要求。

如果您想与记录模块的其余部分真正实现保证兼容性,则唯一可以做的就是浏览该模块的源代码以了解其工作原理。 The documentation是一个很好的起点,但这并没有深入到内部。

如果您只是想为一个小用例编写一个虚拟处理程序,则可以跳过很多步骤而逃脱;尝试一下,看看失败的地方,并以此为基础。

否则,除了进入源代码之外,您别无选择(尽管尝试并查看中断)也是找到开始阅读的好方法)。

快速浏览the class' source会告诉我,该类中唯一的陷阱与模块对其对象的内部管理有关; Handler.__init__将处理程序放入全局处理程序列表中,模块可以在任何地方使用该列表。但是除此之外,该类非常简单。应该不难阅读。

答案 1 :(得分:1)

通常,您可以通过使用包装函数覆盖__getattribue__方法来找出要从外部访问类的哪些属性 如果调用者的类与当前类不同,则将被访问的属性的名称添加到集合中:

import logging
import sys

class MyHandler(logging.Handler):
    def emit(self, record):
        pass

def show_attribute(self, name):
    caller_locals = sys._getframe(1).f_locals
    if ('self' not in caller_locals or
            object.__getattribute__(caller_locals['self'], '__class__') is not
            object.__getattribute__(self, '__class__')):
        attributes.add(name)
    return original_getattribute(self, name)
attributes = set()

original_getattribute = MyHandler.__getattribute__
MyHandler.__getattribute__ = show_attribute

这样:

handler = MyHandler()
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.warning('ok!')    
print(attributes)

输出:

{'handle', 'level'}

演示:https://repl.it/@blhsing/UtterSoupyCollaborativesoftware

从上面的结果中可以看到,handlelevel是基本日志记录处理程序唯一需要的属性。换句话说,@ jirassimok是正确的,因为handleHandler类的唯一在外部调用的方法,但是也需要实现level属性,因为它是也可以直接在Logger.callHandlers方法中访问:

if record.levelno >= hdlr.level:

其中level属性必须是整数,如果要处理所有日志记录级别的记录,则应为0

因此,Handler类的最小实现应类似于:

class MyHandler:
    def __init__(self):
        self.level = 0

    def handle(self, record):
        print(record.msg)

这样:

handler = MyHandler()
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.warning('ok!')

输出:

ok!