Skip to content

Commit 340a76c

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 46f6053 commit 340a76c

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

django_prometheus/exports.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,16 @@
1919
logger = logging.getLogger(__name__)
2020

2121

22-
def SetupPrometheusEndpointOnPort(port, addr=""):
22+
def GetRegistry():
23+
if "prometheus_multiproc_dir" in os.environ:
24+
registry = prometheus_client.CollectorRegistry()
25+
multiprocess.MultiProcessCollector(registry)
26+
else:
27+
registry = prometheus_client.REGISTRY
28+
return registry
29+
30+
31+
def SetupPrometheusEndpointOnPort(registry, port, addr=""):
2332
"""Exports Prometheus metrics on an HTTPServer running in its own thread.
2433
2534
The server runs on the given port and is by default listenning on
@@ -43,7 +52,7 @@ def SetupPrometheusEndpointOnPort(port, addr=""):
4352
"autoreloader is active. Use the URL exporter, or start django "
4453
"with --noreload. See documentation/exports.md."
4554
)
46-
prometheus_client.start_http_server(port, addr=addr)
55+
prometheus_client.start_http_server(port, addr=addr, registry=registry)
4756

4857

4958
class PrometheusEndpointServer(threading.Thread):
@@ -57,7 +66,7 @@ def run(self):
5766
self.httpd.serve_forever()
5867

5968

60-
def SetupPrometheusEndpointOnPortRange(port_range, addr=""):
69+
def SetupPrometheusEndpointOnPortRange(registry, port_range, addr=""):
6170
"""Like SetupPrometheusEndpointOnPort, but tries several ports.
6271
6372
This is useful when you're running Django as a WSGI application
@@ -83,8 +92,10 @@ def SetupPrometheusEndpointOnPortRange(port_range, addr=""):
8392
"with --noreload. See documentation/exports.md."
8493
)
8594
for port in port_range:
95+
handler = prometheus_client.MetricsHandler
96+
handler.registry = registry
8697
try:
87-
httpd = HTTPServer((addr, port), prometheus_client.MetricsHandler)
98+
httpd = HTTPServer((addr, port), handler)
8899
except OSError:
89100
# Python 2 raises socket.error, in Python 3 socket.error is an
90101
# alias for OSError
@@ -105,22 +116,19 @@ def SetupPrometheusExportsFromConfig():
105116
port = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT", None)
106117
port_range = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT_RANGE", None)
107118
addr = getattr(settings, "PROMETHEUS_METRICS_EXPORT_ADDRESS", "")
119+
registry = GetRegistry()
108120
if port_range:
109-
SetupPrometheusEndpointOnPortRange(port_range, addr)
121+
SetupPrometheusEndpointOnPortRange(registry, port_range, addr)
110122
elif port:
111-
SetupPrometheusEndpointOnPort(port, addr)
123+
SetupPrometheusEndpointOnPort(registry, port, addr)
112124

113125

114126
def ExportToDjangoView(request):
115127
"""Exports /metrics as a Django view.
116128
117129
You can use django_prometheus.urls to map /metrics to this view.
118130
"""
119-
if "prometheus_multiproc_dir" in os.environ:
120-
registry = prometheus_client.CollectorRegistry()
121-
multiprocess.MultiProcessCollector(registry)
122-
else:
123-
registry = prometheus_client.REGISTRY
131+
registry = GetRegistry()
124132
metrics_page = prometheus_client.generate_latest(registry)
125133
return HttpResponse(
126134
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)