问题:
- 1、日志输出在控制台
- 2、从输出的日志中并不能确定具体是哪一个接口出现的问题
改进:
- 1、将日志保存在文件中,方便我们定期检查哪些接口问题存在问题
- 2、修改日志格式,将当前的url拼接在日志格式中,便于我们定位问题
格式:
Potential n+1 query detected on `<model>.<field>`
输出:
2021-11-29 11:20:24,515;WARNING;notifiers.py:40;Potential n+1 query detected on `OutboundOrder.created_by`
结果:
创建nplusone.py
1、重新定义日志格式
将当前接口的url拼接在日志格式上
class LazyLoadMessage2(Message2):
label = 'n_plus_one'
formatter = '{url}:Potential n+1 query detected on `{model}.{field}`'
class EagerLoadMessage2(Message2):
label = 'unused_eager_load'
formatter = '{url}:Potential unnecessary eager load detected on `{model}.{field}`'
2、重写Message
将url拼接在日志中
class Message2(Message):
def __init__(self, model, field, url):
self.url = url
super(Message2, self).__init__(model, field)
@property
def message(self):
return self.formatter.format(
label=self.label,
model=self.model.__name__,
field=self.field,
url=self.url
)
3、重写监听函数
setup方法新增request参数,handle_lazy中将当前接口路径传给对应的Message
class LazyListener2(LazyListener):
def setup(self, **kwargs):
self.request = kwargs.get('request', None)
super(LazyListener2, self).setup()
def handle_lazy(self, caller, args=None, kwargs=None, context=None, ret=None,
parser=None):
model, instance, field = parser(args, kwargs, context)
if instance in self.loaded and instance not in self.ignore:
url = self.request.path if self.request else ''
message = LazyLoadMessage2(model, field, url)
self.parent.notify(message)
class EagerListener2(EagerListener):
def setup(self, **kwargs):
self.request = kwargs.get('request', None)
super(EagerListener2, self).setup()
def log_eager(self):
self.tracker.prune([each for each in self.touched if each])
for model, field in self.tracker.unused:
url = self.request.path if self.request else ''
message = EagerLoadMessage2(model, field, url)
self.parent.notify(message)
listeners2 = {
'lazy_load': LazyListener2,
'eager_load': EagerListener2,
}
4、重写中间件NPlusOneMiddleware
这里我们只需要将process_request方法中的listeners.listeners改成我们上面重写的listeners2
class NPlusOneMiddleware2(NPlusOneMiddleware):
def process_request(self, request):
self.load_config()
self.listeners[request] = self.listeners.get(request, {})
for name, listener_type in six.iteritems(listeners2):
self.listeners[request][name] = listener_type(self)
self.listeners[request][name].setup(request=request)
5、修改settings
重新导入中间件和日志输出
MIDDLEWARE = (
'common.nplusone.NPlusOneMiddleware2',
...
)
LOGGING = {
...
'handlers': {
...
'nplusone': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': LOG_DIR / 'nplusone.log',
'formatter': 'standard'
}
},
'loggers': {
...
'nplusone': {
'handlers': ['nplusone'],
'level': 'WARN',
},
}
}