Skip to content

Commit 779b7ef

Browse files
committed
Fix use of dedicated listeners with multiprocess
Extract the code to select the registry used for the exporter from the Django view and provide the registry as a parameter to clients for deciated listeners as well.
1 parent 49d0e4f commit 779b7ef

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

django_prometheus/exports.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,19 @@
1818
logger = logging.getLogger(__name__)
1919

2020

21-
def SetupPrometheusEndpointOnPort(port, addr=""):
21+
def GetRegistry():
22+
if (
23+
"PROMETHEUS_MULTIPROC_DIR" in os.environ
24+
or "prometheus_multiproc_dir" in os.environ
25+
):
26+
registry = prometheus_client.CollectorRegistry()
27+
multiprocess.MultiProcessCollector(registry)
28+
else:
29+
registry = prometheus_client.REGISTRY
30+
return registry
31+
32+
33+
def SetupPrometheusEndpointOnPort(registry, port, addr=""):
2234
"""Exports Prometheus metrics on an HTTPServer running in its own thread.
2335
2436
The server runs on the given port and is by default listenning on
@@ -42,7 +54,7 @@ def SetupPrometheusEndpointOnPort(port, addr=""):
4254
"autoreloader is active. Use the URL exporter, or start django "
4355
"with --noreload. See documentation/exports.md."
4456
)
45-
prometheus_client.start_http_server(port, addr=addr)
57+
prometheus_client.start_http_server(port, addr=addr, registry=registry)
4658

4759

4860
class PrometheusEndpointServer(threading.Thread):
@@ -56,7 +68,7 @@ def run(self):
5668
self.httpd.serve_forever()
5769

5870

59-
def SetupPrometheusEndpointOnPortRange(port_range, addr=""):
71+
def SetupPrometheusEndpointOnPortRange(registry, port_range, addr=""):
6072
"""Like SetupPrometheusEndpointOnPort, but tries several ports.
6173
6274
This is useful when you're running Django as a WSGI application
@@ -82,8 +94,10 @@ def SetupPrometheusEndpointOnPortRange(port_range, addr=""):
8294
"with --noreload. See documentation/exports.md."
8395
)
8496
for port in port_range:
97+
handler = prometheus_client.MetricsHandler
98+
handler.registry = registry
8599
try:
86-
httpd = HTTPServer((addr, port), prometheus_client.MetricsHandler)
100+
httpd = HTTPServer((addr, port), handler)
87101
except OSError:
88102
# Python 2 raises socket.error, in Python 3 socket.error is an
89103
# alias for OSError
@@ -104,25 +118,19 @@ def SetupPrometheusExportsFromConfig():
104118
port = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT", None)
105119
port_range = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT_RANGE", None)
106120
addr = getattr(settings, "PROMETHEUS_METRICS_EXPORT_ADDRESS", "")
121+
registry = GetRegistry()
107122
if port_range:
108-
SetupPrometheusEndpointOnPortRange(port_range, addr)
123+
SetupPrometheusEndpointOnPortRange(registry, port_range, addr)
109124
elif port:
110-
SetupPrometheusEndpointOnPort(port, addr)
125+
SetupPrometheusEndpointOnPort(registry, port, addr)
111126

112127

113128
def ExportToDjangoView(request):
114129
"""Exports /metrics as a Django view.
115130
116131
You can use django_prometheus.urls to map /metrics to this view.
117132
"""
118-
if (
119-
"PROMETHEUS_MULTIPROC_DIR" in os.environ
120-
or "prometheus_multiproc_dir" in os.environ
121-
):
122-
registry = prometheus_client.CollectorRegistry()
123-
multiprocess.MultiProcessCollector(registry)
124-
else:
125-
registry = prometheus_client.REGISTRY
133+
registry = GetRegistry()
126134
metrics_page = prometheus_client.generate_latest(registry)
127135
return HttpResponse(
128136
metrics_page, content_type=prometheus_client.CONTENT_TYPE_LATEST

django_prometheus/tests/test_exports.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import socket
33
from unittest.mock import ANY, MagicMock, call, patch
44

5+
from prometheus_client import REGISTRY
6+
57
from django_prometheus.exports import SetupPrometheusEndpointOnPortRange
68

79

@@ -10,7 +12,7 @@ def test_port_range_available(httpserver_mock):
1012
"""Test port range setup with an available port."""
1113
httpserver_mock.side_effect = [socket.error, MagicMock()]
1214
port_range = [8000, 8001]
13-
port_chosen = SetupPrometheusEndpointOnPortRange(port_range)
15+
port_chosen = SetupPrometheusEndpointOnPortRange(REGISTRY, port_range)
1416
assert port_chosen in port_range
1517

1618
expected_calls = [call(("", 8000), ANY), call(("", 8001), ANY)]
@@ -22,7 +24,7 @@ def test_port_range_unavailable(httpserver_mock):
2224
"""Test port range setup with no available ports."""
2325
httpserver_mock.side_effect = [socket.error, socket.error]
2426
port_range = [8000, 8001]
25-
port_chosen = SetupPrometheusEndpointOnPortRange(port_range)
27+
port_chosen = SetupPrometheusEndpointOnPortRange(REGISTRY, port_range)
2628

2729
expected_calls = [call(("", 8000), ANY), call(("", 8001), ANY)]
2830
assert httpserver_mock.mock_calls == expected_calls

0 commit comments

Comments
 (0)