-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathmiddleware.py
More file actions
91 lines (73 loc) · 3.03 KB
/
middleware.py
File metadata and controls
91 lines (73 loc) · 3.03 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import logging
import re
import time
import typing
import urllib
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from dockerflow.logging import get_or_generate_request_id, request_id_context
from . import views
def extract_request_id(request):
"""Extract request ID from request."""
rid = get_or_generate_request_id(
request.headers,
header_name=getattr(settings, "DOCKERFLOW_REQUEST_ID_HEADER_NAME", None),
)
request_id_context.set(rid)
request._id = rid # Used in tests.
class DockerflowMiddleware(MiddlewareMixin):
"""
Emits a request.summary type log entry for every request.
https://github.com/mozilla-services/Dockerflow/blob/main/docs/mozlog.md
"""
viewpatterns: typing.ClassVar = [
(re.compile(r"/__version__/?$"), views.version),
(re.compile(r"/__heartbeat__/?$"), views.heartbeat),
(re.compile(r"/__lbheartbeat__/?$"), views.lbheartbeat),
(re.compile(r"/__error__/?$"), views.error),
]
def __init__(self, get_response=None, *args, **kwargs):
super(DockerflowMiddleware, self).__init__(
get_response=get_response, *args, **kwargs
)
self.summary_logger = logging.getLogger("request.summary")
def process_request(self, request):
for pattern, view in self.viewpatterns:
if pattern.match(request.path_info):
return view(request)
extract_request_id(request)
request._start_timestamp = time.time()
return None
def _build_extra_meta(self, request):
out = {
"errno": 0,
"agent": request.META.get("HTTP_USER_AGENT", ""),
"lang": request.META.get("HTTP_ACCEPT_LANGUAGE", ""),
"method": request.method,
"path": request.path,
}
if getattr(settings, "DOCKERFLOW_SUMMARY_LOG_QUERYSTRING", False):
out["querystring"] = urllib.parse.unquote(
request.META.get("QUERY_STRING", "")
)
# HACK: It's possible some other middleware has replaced the request we
# modified earlier, so be sure to check for existence of these
# attributes before trying to use them.
if hasattr(request, "user"):
out["uid"] = request.user.is_authenticated and request.user.pk or ""
out["rid"] = request_id_context.get()
if hasattr(request, "_start_timestamp"):
# Duration of request, in milliseconds.
out["t"] = int(1000 * (time.time() - request._start_timestamp))
return out
def process_response(self, request, response):
if not getattr(request, "_has_exception", False):
extra = self._build_extra_meta(request)
self.summary_logger.info("", extra=extra)
return response
def process_exception(self, request, exception):
extra = self._build_extra_meta(request)
extra["errno"] = 500
self.summary_logger.error(str(exception), extra=extra)
request._has_exception = True
return None