【问题标题】:Logging decorator with basicConfig settings as arguments使用 basicConfig 设置作为参数的日志装饰器
【发布时间】:2014-04-23 09:26:35
【问题描述】:

编辑:我重组了问题并添加了标题,希望它更容易阅读

问题

我正在尝试向python decorator library 中的日志装饰器添加一些功能。

我想添加的选项之一是能够通过提供字典作为输入来设置日志记录级别。但是,无论我设置什么级别,它总是返回相同的结果。


失败的测试

运行下面的设置代码后,我正在通过运行以下命令对其进行测试:

@log_with(setConfig={'level':logging.INFO})
def c(msg):
    print(msg)

c('OMG!!')

返回:

INFO:__main__:Running c


DEBUG:__main__:The following arguments have been received:# <-- This should not be here
('OMG!!',)

The following keyword arguments have been received:
{}


INFO:__main__:Returning c
OMG!!

如果这很重要,我正在以可移植、非注册的方式使用 WinPython 2.7.6。在 qtconsole 中测试失败


设置代码

import functools, logging


log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

class log_with(object):
    '''Logging decorator that allows you to log with a
specific logger or set one up on the go.
'''

    def __init__(self,logger=None,funcentry='Running {}',funcexit='Returning {}',setConfig=None):

        self.logger        = logger
        self.ENTRY_MESSAGE = funcentry
        self.EXIT_MESSAGE  = funcexit
        self.setConfig     = setConfig


    def __call__(self, func):
        '''Returns a wrapper that wraps func.
The wrapper will log the entry and exit points of the function
with specified level.
'''
        # set logger if it was not set earlier
        if not self.logger:
            self.logger = logging.getLogger(func.__module__)
            logging.basicConfig(**self.setConfig)

        @functools.wraps(func)
        def wrapper(*args, **kwds):
            self.logger.info(self.ENTRY_MESSAGE.format(func.__name__)+'\n\n')
            self.logger.debug("The following arguments have been received:\n{}\n\nThe following keyword arguments have been received:\n{}\n\n".format(args,kwds))
            try:
                f_result = func(*args, **kwds)
                self.logger.info(self.EXIT_MESSAGE.format(func.__name__))
                return f_result
            except Exception:
                self.logger.exception("An exception was raised:\n\n")
        return wrapper

我的想法和尝试过的事情

重置所有处理程序

我试图通过删除所有可能存在的处理程序来修改装饰器中的 if not self.logger 循环,即

....
if not self.logger:
    for handler in logging.root.handlers[:]:
        logging.root.removeHandler(handler)
....

基于this SO answer,但这也不起作用,即输出保持不变。

我不懂装饰器和/或日志模块!

我删除了

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

然后再次运行代码。这次根本没有将日志消息打印到屏幕上。对我来说,这意味着 __call__ 方法中的 if not self.logger 循环有问题,即未创建记录器。

我不知道为什么.....

【问题讨论】:

  • 似乎__call__ 函数中的记录器没有正确创建...当我删除初始log=logging.getLogger(..) 时,装饰器不起作用,即根本没有打印日志调用。 .. ???

标签: python logging decorator


【解决方案1】:

这是我学到的:

  1. 看起来使用basicConfig() 设置了一些用于日志记录的全局变量。更改日志记录级别似乎会全局更改它,而不仅仅是针对此调用。

  2. 将装饰器实现为类还是函数似乎有所不同。虽然不完全确定,但我相信通过在__init__ 中实现我的self.setConfig,我改变了我装饰的所有函数的类。我从找到的解决方案中扣除了这一点,将装饰器实现为函数:

这似乎可行(尽管我对返回东西的顺序有点困惑):

def log_with_func(funcentry='Running {}',funcexit='Returning {}',setConfig=None):
    ENTRY_MESSAGE = funcentry
    EXIT_MESSAGE  = funcexit
    def func(f):
        @functools.wraps(f)
        def wrapper(*args, **kwds):
            for handler in logging.root.handlers[:]:
                logging.root.removeHandler(handler)
            logger = logging.getLogger(__name__)
            if setConfig:
                logging.basicConfig(**setConfig)
            else:
                logging.basicConfig(level=logging.INFO)
            logger.info(ENTRY_MESSAGE.format(f.__name__)+'\n\n')
            logger.debug("The following arguments have been received:\n{}\n\nThe following keyword arguments have been received:\n{}\n\n".format(args,kwds))
            try:
                f_result = f(*args, **kwds)
                logger.info(EXIT_MESSAGE.format(f.__name__))
                return f_result
            except Exception:
                logger.exception("An exception was raised:\n\n")
        return wrapper
    return func

应用它看起来像这样:

In [24]: @log_with_func()
    ...: def aa(msg):
    ...:     print(msg + 'from a')
    ...:     

In [25]: @log_with_func(setConfig={'level':logging.DEBUG})
    ...: def bb(msg):
    ...:     print(msg + 'from b')
    ...:     

In [26]: print(aa('OMG!!!'))
    ...: print(bb('OMG!!!'))
    ...: print(aa('OMG!!!'))
    ...: 
INFO:__main__:Running aa


INFO:__main__:Returning aa
INFO:__main__:Running bb


DEBUG:__main__:The following arguments have been received:
('OMG!!!',)

The following keyword arguments have been received:
{}


INFO:__main__:Returning bb
INFO:__main__:Running aa


INFO:__main__:Returning aa
OMG!!!from a
None
OMG!!!from b
None
OMG!!!from a
None

In [27]: 

【讨论】:

    猜你喜欢
    • 2015-12-17
    • 2012-08-22
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    • 2016-11-18
    • 2011-10-23
    • 2016-07-27
    • 2015-12-01
    相关资源
    最近更新 更多