Skip to content

Commit fdbbc6b

Browse files
authored
Merge pull request #179 from asherf/labels3
Link metrics to middleware isntances.
2 parents bbc1360 + d65bb88 commit fdbbc6b

File tree

1 file changed

+194
-138
lines changed

1 file changed

+194
-138
lines changed

django_prometheus/middleware.py

Lines changed: 194 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -3,143 +3,191 @@
33
from django.utils.deprecation import MiddlewareMixin
44
from django_prometheus.utils import PowersOf, Time, TimeSince
55

6-
requests_total = Counter(
7-
"django_http_requests_before_middlewares_total",
8-
"Total count of requests before middlewares run.",
9-
)
10-
responses_total = Counter(
11-
"django_http_responses_before_middlewares_total",
12-
"Total count of responses before middlewares run.",
13-
)
14-
requests_latency_before = Histogram(
15-
"django_http_requests_latency_including_middlewares_seconds",
16-
(
17-
"Histogram of requests processing time (including middleware "
18-
"processing time)."
19-
),
20-
)
21-
requests_unknown_latency_before = Counter(
22-
"django_http_requests_unknown_latency_including_middlewares_total",
23-
(
24-
"Count of requests for which the latency was unknown (when computing "
25-
"django_http_requests_latency_including_middlewares_seconds)."
26-
),
27-
)
286

7+
def _register_metric(cls, name, documentation, labelnames=tuple(), **kwargs):
8+
return cls(name, documentation, labelnames=labelnames, **kwargs)
299

30-
class PrometheusBeforeMiddleware(MiddlewareMixin):
3110

11+
class Metrics:
12+
_instance = None
13+
14+
@classmethod
15+
def get_instance(cls):
16+
if not cls._instance:
17+
cls._instance = cls()
18+
return cls._instance
19+
20+
def __init__(self, *args, **kwargs):
21+
self.register()
22+
23+
def register(self):
24+
self.requests_total = _register_metric(
25+
Counter,
26+
"django_http_requests_before_middlewares_total",
27+
"Total count of requests before middlewares run.",
28+
)
29+
self.responses_total = _register_metric(
30+
Counter,
31+
"django_http_responses_before_middlewares_total",
32+
"Total count of responses before middlewares run.",
33+
)
34+
self.requests_latency_before = _register_metric(
35+
Histogram,
36+
"django_http_requests_latency_including_middlewares_seconds",
37+
(
38+
"Histogram of requests processing time (including middleware "
39+
"processing time)."
40+
),
41+
)
42+
self.requests_unknown_latency_before = _register_metric(
43+
Counter,
44+
"django_http_requests_unknown_latency_including_middlewares_total",
45+
(
46+
"Count of requests for which the latency was unknown (when computing "
47+
"django_http_requests_latency_including_middlewares_seconds)."
48+
),
49+
)
50+
self.requests_latency_by_view_method = _register_metric(
51+
Histogram,
52+
"django_http_requests_latency_seconds_by_view_method",
53+
"Histogram of request processing time labelled by view.",
54+
["view", "method"],
55+
buckets=(
56+
0.01,
57+
0.025,
58+
0.05,
59+
0.075,
60+
0.1,
61+
0.25,
62+
0.5,
63+
0.75,
64+
1.0,
65+
2.5,
66+
5.0,
67+
7.5,
68+
10.0,
69+
25.0,
70+
50.0,
71+
75.0,
72+
float("inf"),
73+
),
74+
)
75+
self.requests_unknown_latency = _register_metric(
76+
Counter,
77+
"django_http_requests_unknown_latency_total",
78+
"Count of requests for which the latency was unknown.",
79+
)
80+
# Set in process_request
81+
self.requests_ajax = _register_metric(
82+
Counter, "django_http_ajax_requests_total", "Count of AJAX requests."
83+
)
84+
self.requests_by_method = _register_metric(
85+
Counter,
86+
"django_http_requests_total_by_method",
87+
"Count of requests by method.",
88+
["method"],
89+
)
90+
self.requests_by_transport = _register_metric(
91+
Counter,
92+
"django_http_requests_total_by_transport",
93+
"Count of requests by transport.",
94+
["transport"],
95+
)
96+
# Set in process_view
97+
self.requests_by_view_transport_method = _register_metric(
98+
Counter,
99+
"django_http_requests_total_by_view_transport_method",
100+
"Count of requests by view, transport, method.",
101+
["view", "transport", "method"],
102+
)
103+
self.requests_body_bytes = _register_metric(
104+
Histogram,
105+
"django_http_requests_body_total_bytes",
106+
"Histogram of requests by body size.",
107+
buckets=PowersOf(2, 30),
108+
)
109+
# Set in process_template_response
110+
self.responses_by_templatename = _register_metric(
111+
Counter,
112+
"django_http_responses_total_by_templatename",
113+
"Count of responses by template name.",
114+
["templatename"],
115+
)
116+
# Set in process_response
117+
self.responses_by_status = _register_metric(
118+
Counter,
119+
"django_http_responses_total_by_status",
120+
"Count of responses by status.",
121+
["status"],
122+
)
123+
self.responses_by_status_view_method = _register_metric(
124+
Counter,
125+
"django_http_responses_total_by_status_view_method",
126+
"Count of responses by status, view, method.",
127+
["status", "view", "method"],
128+
)
129+
self.responses_body_bytes = _register_metric(
130+
Histogram,
131+
"django_http_responses_body_total_bytes",
132+
"Histogram of responses by body size.",
133+
buckets=PowersOf(2, 30),
134+
)
135+
self.responses_by_charset = _register_metric(
136+
Counter,
137+
"django_http_responses_total_by_charset",
138+
"Count of responses by charset.",
139+
["charset"],
140+
)
141+
self.responses_streaming = _register_metric(
142+
Counter,
143+
"django_http_responses_streaming_total",
144+
"Count of streaming responses.",
145+
)
146+
# Set in process_exception
147+
self.exceptions_by_type = _register_metric(
148+
Counter,
149+
"django_http_exceptions_total_by_type",
150+
"Count of exceptions by object type.",
151+
["type"],
152+
)
153+
self.exceptions_by_view = _register_metric(
154+
Counter,
155+
"django_http_exceptions_total_by_view",
156+
"Count of exceptions by view.",
157+
["view_name"],
158+
)
159+
160+
161+
class PrometheusBeforeMiddleware(MiddlewareMixin):
32162
"""Monitoring middleware that should run before other middlewares."""
33163

164+
def __init__(self, get_response=None):
165+
super(PrometheusBeforeMiddleware, self).__init__(get_response)
166+
self.metrics = Metrics.get_instance()
167+
34168
def process_request(self, request):
35-
requests_total.inc()
169+
self.metrics.requests_total.inc()
36170
request.prometheus_before_middleware_event = Time()
37171

38172
def process_response(self, request, response):
39-
responses_total.inc()
173+
self.metrics.responses_total.inc()
40174
if hasattr(request, "prometheus_before_middleware_event"):
41-
requests_latency_before.observe(
175+
self.metrics.requests_latency_before.observe(
42176
TimeSince(request.prometheus_before_middleware_event)
43177
)
44178
else:
45-
requests_unknown_latency_before.inc()
179+
self.metrics.requests_unknown_latency_before.inc()
46180
return response
47181

48182

49-
requests_latency_by_view_method = Histogram(
50-
"django_http_requests_latency_seconds_by_view_method",
51-
"Histogram of request processing time labelled by view.",
52-
["view", "method"],
53-
buckets=(
54-
0.01,
55-
0.025,
56-
0.05,
57-
0.075,
58-
0.1,
59-
0.25,
60-
0.5,
61-
0.75,
62-
1.0,
63-
2.5,
64-
5.0,
65-
7.5,
66-
10.0,
67-
25.0,
68-
50.0,
69-
75.0,
70-
float("inf"),
71-
),
72-
)
73-
requests_unknown_latency = Counter(
74-
"django_http_requests_unknown_latency_total",
75-
"Count of requests for which the latency was unknown.",
76-
)
77-
# Set in process_request
78-
ajax_requests = Counter("django_http_ajax_requests_total", "Count of AJAX requests.")
79-
requests_by_method = Counter(
80-
"django_http_requests_total_by_method", "Count of requests by method.", ["method"]
81-
)
82-
requests_by_transport = Counter(
83-
"django_http_requests_total_by_transport",
84-
"Count of requests by transport.",
85-
["transport"],
86-
)
87-
# Set in process_view
88-
requests_by_view_transport_method = Counter(
89-
"django_http_requests_total_by_view_transport_method",
90-
"Count of requests by view, transport, method.",
91-
["view", "transport", "method"],
92-
)
93-
requests_body_bytes = Histogram(
94-
"django_http_requests_body_total_bytes",
95-
"Histogram of requests by body size.",
96-
buckets=PowersOf(2, 30),
97-
)
98-
# Set in process_template_response
99-
responses_by_templatename = Counter(
100-
"django_http_responses_total_by_templatename",
101-
"Count of responses by template name.",
102-
["templatename"],
103-
)
104-
# Set in process_response
105-
responses_by_status = Counter(
106-
"django_http_responses_total_by_status", "Count of responses by status.", ["status"]
107-
)
108-
responses_by_status_view_method = Counter(
109-
"django_http_responses_total_by_status_view_method",
110-
"Count of responses by status, view, method.",
111-
["status", "view", "method"],
112-
)
113-
responses_body_bytes = Histogram(
114-
"django_http_responses_body_total_bytes",
115-
"Histogram of responses by body size.",
116-
buckets=PowersOf(2, 30),
117-
)
118-
responses_by_charset = Counter(
119-
"django_http_responses_total_by_charset",
120-
"Count of responses by charset.",
121-
["charset"],
122-
)
123-
responses_streaming = Counter(
124-
"django_http_responses_streaming_total", "Count of streaming responses."
125-
)
126-
# Set in process_exception
127-
exceptions_by_type = Counter(
128-
"django_http_exceptions_total_by_type",
129-
"Count of exceptions by object type.",
130-
["type"],
131-
)
132-
exceptions_by_view = Counter(
133-
"django_http_exceptions_total_by_view",
134-
"Count of exceptions by view.",
135-
["view_name"],
136-
)
137-
138-
139183
class PrometheusAfterMiddleware(MiddlewareMixin):
140184

141185
"""Monitoring middleware that should run after other middlewares."""
142186

187+
def __init__(self, get_response=None):
188+
super(PrometheusAfterMiddleware, self).__init__(get_response)
189+
self.metrics = Metrics.get_instance()
190+
143191
def _transport(self, request):
144192
return "https" if request.is_secure() else "http"
145193

@@ -162,12 +210,12 @@ def _method(self, request):
162210
def process_request(self, request):
163211
transport = self._transport(request)
164212
method = self._method(request)
165-
requests_by_method.labels(method).inc()
166-
requests_by_transport.labels(transport).inc()
213+
self.metrics.requests_by_method.labels(method=method).inc()
214+
self.metrics.requests_by_transport.labels(transport=transport).inc()
167215
if request.is_ajax():
168-
ajax_requests.inc()
216+
self.metrics.requests_ajax.inc()
169217
content_length = int(request.META.get("CONTENT_LENGTH") or 0)
170-
requests_body_bytes.observe(content_length)
218+
self.metrics.requests_body_bytes.observe(content_length)
171219
request.prometheus_after_middleware_event = Time()
172220

173221
def _get_view_name(self, request):
@@ -183,41 +231,49 @@ def process_view(self, request, view_func, *view_args, **view_kwargs):
183231
method = self._method(request)
184232
if hasattr(request, "resolver_match"):
185233
name = request.resolver_match.view_name or "<unnamed view>"
186-
requests_by_view_transport_method.labels(name, transport, method).inc()
234+
self.metrics.requests_by_view_transport_method.labels(
235+
view=name, transport=transport, method=method
236+
).inc()
187237

188238
def process_template_response(self, request, response):
189239
if hasattr(response, "template_name"):
190-
responses_by_templatename.labels(str(response.template_name)).inc()
240+
self.metrics.responses_by_templatename.labels(
241+
templatename=str(response.template_name)
242+
).inc()
191243
return response
192244

193245
def process_response(self, request, response):
194246
method = self._method(request)
195247
name = self._get_view_name(request)
196-
197-
responses_by_status.labels(str(response.status_code)).inc()
198-
responses_by_status_view_method.labels(response.status_code, name, method).inc()
248+
status = str(response.status_code)
249+
self.metrics.responses_by_status.labels(status=status).inc()
250+
self.metrics.responses_by_status_view_method.labels(
251+
status=status, view=name, method=method
252+
).inc()
199253
if hasattr(response, "charset"):
200-
responses_by_charset.labels(str(response.charset)).inc()
254+
self.metrics.responses_by_charset.labels(
255+
charset=str(response.charset)
256+
).inc()
201257
if hasattr(response, "streaming") and response.streaming:
202-
responses_streaming.inc()
258+
self.metrics.responses_streaming.inc()
203259
if hasattr(response, "content"):
204-
responses_body_bytes.observe(len(response.content))
260+
self.metrics.responses_body_bytes.observe(len(response.content))
205261
if hasattr(request, "prometheus_after_middleware_event"):
206-
requests_latency_by_view_method.labels(
207-
view=name, method=request.method
262+
self.metrics.requests_latency_by_view_method.labels(
263+
view=self._get_view_name(request), method=request.method
208264
).observe(TimeSince(request.prometheus_after_middleware_event))
209265
else:
210-
requests_unknown_latency.inc()
266+
self.metrics.requests_unknown_latency.inc()
211267
return response
212268

213269
def process_exception(self, request, exception):
214-
name = self._get_view_name(request)
215-
exceptions_by_type.labels(type(exception).__name__).inc()
270+
self.metrics.exceptions_by_type.labels(type=type(exception).__name__).inc()
216271
if hasattr(request, "resolver_match"):
217-
exceptions_by_view.labels(name).inc()
272+
name = request.resolver_match.view_name or "<unnamed view>"
273+
self.metrics.exceptions_by_view.labels(view_name=name).inc()
218274
if hasattr(request, "prometheus_after_middleware_event"):
219-
requests_latency_by_view_method.labels(
220-
view=name, method=request.method
275+
self.metrics.requests_latency_by_view_method.labels(
276+
view=self._get_view_name(request), method=request.method
221277
).observe(TimeSince(request.prometheus_after_middleware_event))
222278
else:
223-
requests_unknown_latency.inc()
279+
self.metrics.requests_unknown_latency.inc()

0 commit comments

Comments
 (0)