作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我可以创建一个命名的子记录器,以便该记录器输出的所有日志都标有它的名称。我可以在我的函数/类/任何东西中专门使用该记录器。
但是,如果该代码调用另一个模块中的函数,该模块仅使用日志记录模块函数(即根记录器的代理)来使用日志记录,我如何确保这些日志消息通过相同的记录器(或至少以相同的方式登录)?
例如:
主要.py
import logging
import other
def do_stuff(logger):
logger.info("doing stuff")
other.do_more_stuff()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("stuff")
do_stuff(logger)
其他.py
import logging
def do_more_stuff():
logging.info("doing other stuff")
输出:
$ python main.py
INFO:stuff:doing stuff
INFO:root:doing other stuff
我希望能够使两个日志行都被标记为名称“stuff”,并且我希望能够只更改 main.py 来做到这一点。
如何在不更改该模块的情况下使 other.py 中的日志记录调用使用不同的记录器?
最佳答案
这是我想出的解决方案:
使用线程本地数据存储上下文信息,并在根记录器处理程序上使用过滤器在发出之前将此信息添加到 LogRecords。
context = threading.local()
context.name = None
class ContextFilter(logging.Filter):
def filter(self, record):
if context.name is not None:
record.name = "%s.%s" % (context.name, record.name)
return True
这对我来说很好,因为我使用记录器名称来指示记录此消息时正在执行的任务。
然后我可以使用上下文管理器或装饰器使来自特定代码段的日志记录看起来好像是从特定的子记录器记录的。
@contextlib.contextmanager
def logname(name):
old_name = context.name
if old_name is None:
context.name = name
else:
context.name = "%s.%s" % (old_name, name)
try:
yield
finally:
context.name = old_name
def as_logname(name):
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
with logname(name):
return f(*args, **kwargs)
return wrapper
return decorator
那么,我可以这样做:
with logname("stuff"):
logging.info("I'm doing stuff!")
do_more_stuff()
或:
@as_logname("things")
def do_things():
logging.info("Starting to do things")
do_more_stuff()
关键是 do_more_stuff()
所做的任何日志记录都将被记录,就好像它是用“stuff”或“things”子记录器记录的一样,而无需更改 do_more_stuff()
完全没有。
如果您要在不同的子记录器上使用不同的处理程序,此解决方案就会出现问题。
关于python - 如何让日志记录模块函数使用不同的记录器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17949244/
我是一名优秀的程序员,十分优秀!