Django 的日志机制-4

进阶

其实,如果只是为了排错方便,记录一些日志,自定义类基本可以满足要求。但如果要记录访问系统的所有请求日志,那就无能为力了,因为不可能手动在每个接口代码加日志,也没必要。

这个时候,很自然就能想到 Django 中间件了。

Django 中间件

定义中间件类,包括 Filters 代码和 middleware 代码,在本地app文件夹中创建目录:middlewares,目录下创建文件 LogMiddleware.py :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from django.utils.deprecation import MiddlewareMixin
import threading
import logging
import json
import socket

local = threading.local()

class RequestLogFilter(logging.Filter):
"""
日志过滤器
"""

def filter(self, record):
record.sip = getattr(local, 'sip', 'none')
record.dip = getattr(local, 'dip', 'none')
record.body = getattr(local, 'body', 'none')
record.path = getattr(local, 'path', 'none')
record.method = getattr(local, 'method', 'none')
record.username = getattr(local, 'username', 'none')
record.status_code = getattr(local, 'status_code', 'none')
record.reason_phrase = getattr(local, 'reason_phrase', 'none')

return True

class RequestLogMiddleware(MiddlewareMixin):
"""
将request的信息记录在当前的请求线程上。
"""

def __init__(self, get_response=None):
self.get_response = get_response
self.apiLogger = logging.getLogger('web.log')

def __call__(self, request):

try:
body = json.loads(request.body)
except Exception:
body = dict()

if request.method == 'GET':
body.update(dict(request.GET))
else:
body.update(dict(request.POST))

local.body = body
local.path = request.path
local.method = request.method
local.username = request.user
local.sip = request.META.get('REMOTE_ADDR', '')
local.dip = socket.gethostbyname(socket.gethostname())

response = self.get_response(request)
local.status_code = response.status_code
local.reason_phrase = response.reason_phrase
self.apiLogger.info('system-auto')

return response

设置文件配置

**setting.py** 文件的最后,加上以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
## 设置log文件的目录
LOGS_DIR = BASE_DIR / 'log'

LOGGING = {
# 版本
'version': 1,
# 是否禁止默认配置的记录器
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '{"time": "%(asctime)s", "level": "%(levelname)s", "method": "%(method)s", "username": "%(username)s", "sip": "%(sip)s", "dip": "%(dip)s", "path": "%(path)s", "status_code": "%(status_code)s", "reason_phrase": "%(reason_phrase)s", "func": "%(module)s.%(funcName)s:%(lineno)d", "message": "%(message)s"}',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
# 过滤器, 其中xxxapp为项目app
'filters': {
'request_info': {'()': 'xxxapp.middlewares.LogMiddleware.RequestLogFilter'},
},
'handlers': {
# 标准输出
'console': {
'level': 'ERROR',
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
# 自定义 handlers,输出到文件
'restful_api': {
'level': 'DEBUG',
# 时间滚动切分
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join(LOGS_DIR, 'web-log.log'),
'formatter': 'standard',
# 调用过滤器
'filters': ['request_info'],
# 每天凌晨切分
'when': 'MIDNIGHT',
# 保存 30 天
'backupCount': 30,
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'ERROR',
'propagate': False
},
'web.log': {
'handlers': ['restful_api'],
'level': 'INFO',
# 此记录器处理过的消息就不再让 django 记录器再次处理了
'propagate': False
},
}
}

总结

通过这种方式,只要过 Django 的请求就都会有日志,不管是 web 还是 Django admin。具体记录哪些字段可以根据项目需要进行获取和配置。

如果需要在视图中使用log,用下面语句即可:

1
2
3
import logging
log = logging.getLogger('middleware')
log.debug("......")

相关链接:
Django 的日志机制-1
Django 的日志机制-2
Django 的日志机制-3

请我喝杯咖啡吧~

支付宝
微信