编辑:我重新构建了问题并添加了标题,希望它更容易阅读
我正在尝试向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)
再次运行代码。这次根本没有打印到屏幕上的记录消息。对我而言,这意味着if not self.logger
方法中的__call__
循环出现了问题,即未创建记录器。
我不知道为什么......
答案 0 :(得分:0)
这是我学到的:
看起来使用basicConfig()
设置一些全局变量进行日志记录。更改日志记录级别似乎在全局范围内更改,而不仅仅是针对此调用。
将装饰器实现为类还是函数似乎都有所不同。虽然不完全确定,但我相信通过在self.setConfig
中实现__init__
,我更改了我装饰的所有函数的类。我从我找到的解决方案中推断出这一点,该解决方案将装饰器实现为函数:
这似乎有用(尽管我对事情的回归顺序感到有些困惑):
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]: