官方文档中有两种方式,适配器(Adapter)和过滤器(filter)。具体地址在文末。
第一种,使用适配器。
使用LoggerAdapter 类,重写它的process方法,将上下文信息添加到日志的输出中。我理解就是,专为logger自定义输出日志而写的类,接收logger和extra。在process方法里,按照自己的想法把message信息格式化。并返回message和kw。
?博客1的例子非常详细,同时也指出了当时我按照例子写后发现不妥的地方。就是loggerAdapter已经不是原来的logger,尽管同样可以error,info。但是在不同的地方去获取logger时,取到的还是原来的。这和我预想的不一致,如果原来的代码已经大量使用,这时就不适合在改动了。
from logging import LoggerAdapter
import logging
logger = logging.getLogger(__name__)
class SesssionLoggerAdapter(LoggerAdapter):
def process(self, msg, kwargs):
if 'session' not in self.extra or self.extra['session'] is None:
return msg, kwargs
session = self.extra['session']
if hasattr(session, 'request_id'):
msg += ', request_id({})'.format(session.request_id)
if 'extra' not in kwargs:
kwargs["extra"] = self.extra
else:
kwargs['extra'].update(self.extra)
return super().process(msg, kwargs)
class Session():
def __init__(self):
super().__init__()
@property
def request_id(self):
return self._request_id
@request_id.setter
def request_id(self, request_id):
self._request_id = request_id
session = Session()
logger.warning('abc')
# 这里尽管覆盖了原logger,但是只在这里覆盖,其它地方获取logger = logging.getLogger(__name__)结果并没有用。
logger = SesssionLoggerAdapter(logger, {'session': session})
session.request_id = '0'
logger.warning('hello world')
session.request_id = '1'
logger.warning('hello world')
https://segmentfault.com/a/1190000022506342
第二种,就是使用过滤器。
按道理,看名字,过滤器不应该修改message内容信息的,只能说,用filter过滤器这个词不太合适。还是看官方文档。继承logging.Filter类,重写filter方法,然后给logger添加自己重写的过滤器即可。在重写的过滤器里重新组织message。不过官方文档给的例子,写的太复杂了,最后一行,我还以为必须要每个log时要手动改。
import logging
from random import choice
class ContextFilter(logging.Filter):
"""
This is a filter which injects contextual information into the log.
Rather than use actual contextual information, we just use random
data in this demo.
"""
USERS = ['jim', 'fred', 'sheila']
IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1']
def filter(self, record):
record.ip = choice(ContextFilter.IPS)
record.user = choice(ContextFilter.USERS)
return True
if __name__ == '__main__':
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s')
a1 = logging.getLogger('a.b.c')
a2 = logging.getLogger('d.e.f')
f = ContextFilter()
a1.addFilter(f)
a2.addFilter(f)
a1.debug('A debug message')
a1.info('An info message with %s', 'some parameters')
for x in range(10):
lvl = choice(levels)
lvlname = logging.getLevelName(lvl)
a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')
官方文档下filter下的例子就很简单,就是在filter里重新组织message,最后返回true就行。这里就和上面的适配器不一样了,这里修改的就是原本的logger,这样,原本的代码就不用动。官网是使用dict来配置logger的,我们不管怎么配置,拿到logger后添加filter即可,如下直接添加filter的代码片段。
import logging
import logging.config
import sys
class MyFilter(logging.Filter):
def __init__(self, param=None):
self.param = param
def filter(self, record):
if self.param is None:
allow = True
else:
allow = self.param not in record.msg
if allow:
record.msg = 'changed: ' + record.msg
return allow
LOGGING = {
'version': 1,
'filters': {
'myfilter': {
'()': MyFilter,
'param': 'noshow',
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'filters': ['myfilter']
}
},
'root': {
'level': 'DEBUG',
'handlers': ['console']
},
}
if __name__ == '__main__':
logging.config.dictConfig(LOGGING)
logging.debug('hello')
logging.debug('hello - noshow')
直接添加filter的代码片段:
import logging
logger = logging.getLogger("arview")
class MyFilter(logging.Filter):
def __init__(self, param=None):
self.param = param
def filter(self, record):
if self.param is None:
allow = True
else:
allow = self.param not in record.msg
if allow:
request_id = "-"
if hasattr(request, "requestId"):
request_id = getattr(request, "requestId")
record.msg = ',request_id({}),'.format(request_id) + record.msg
return allow
user_id_filter = MyFilter()
logger.addFilter(user_id_filter)
当然还有一种方法,在每次log时传入extra,但是大部分情况下,不适合这种方式,还是希望每次log时自动加入上下文信息。具体可见博客2。
参考资料:
官方文档:
日志操作手册 — Python 3.7.13 文档
博客1:
https://segmentfault.com/a/1190000022506342
博客2:
Python 日志输出中添加上下文信息 - 月缺一格 - 博客园
|