Skip to content

Commit cfefbd0

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 e967088 commit cfefbd0

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

django_prometheus/exports.py

Lines changed: 22 additions & 11 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
@@ -102,21 +116,18 @@ def SetupPrometheusExportsFromConfig():
102116
port = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT", None)
103117
port_range = getattr(settings, "PROMETHEUS_METRICS_EXPORT_PORT_RANGE", None)
104118
addr = getattr(settings, "PROMETHEUS_METRICS_EXPORT_ADDRESS", "")
119+
registry = GetRegistry()
105120
if port_range:
106-
SetupPrometheusEndpointOnPortRange(port_range, addr)
121+
SetupPrometheusEndpointOnPortRange(registry, port_range, addr)
107122
elif port:
108-
SetupPrometheusEndpointOnPort(port, addr)
123+
SetupPrometheusEndpointOnPort(registry, port, addr)
109124

110125

111126
def ExportToDjangoView(request):
112127
"""Exports /metrics as a Django view.
113128
114129
You can use django_prometheus.urls to map /metrics to this view.
115130
"""
116-
if "PROMETHEUS_MULTIPROC_DIR" in os.environ or "prometheus_multiproc_dir" in os.environ:
117-
registry = prometheus_client.CollectorRegistry()
118-
multiprocess.MultiProcessCollector(registry)
119-
else:
120-
registry = prometheus_client.REGISTRY
131+
registry = GetRegistry()
121132
metrics_page = prometheus_client.generate_latest(registry)
122133
return HttpResponse(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)