Django middlewares to monitor your application with Prometheus.io
—
Export Prometheus metrics through Django views or standalone HTTP servers, with support for multiprocess environments and flexible deployment configurations.
Export Prometheus metrics as a standard Django HTTP response, integrating with Django's URL routing and middleware stack.
def ExportToDjangoView(request):
"""
Exports /metrics as a Django view.
You can use django_prometheus.urls to map /metrics to this view.
Handles multiprocess environments automatically.
Parameters:
- request: Django HttpRequest object
Returns:
HttpResponse with Prometheus metrics data and appropriate content type
"""Run dedicated HTTP servers for metrics export, independent of Django's application server.
def SetupPrometheusEndpointOnPort(port: int, addr: str = ""):
"""
Exports Prometheus metrics on HTTPServer running in its own thread.
The server runs on the given port and listens on all interfaces by default.
This HTTPServer is fully independent of Django and its stack, providing
metrics even if Django becomes unresponsive.
Cannot be used when Django's autoreloader is active (development mode).
Parameters:
- port: int, port number to serve metrics on
- addr: str, address to bind to (default: "" for all interfaces)
Raises:
AssertionError: When called with Django autoreloader active
"""
def SetupPrometheusEndpointOnPortRange(port_range, addr: str = ""):
"""
Like SetupPrometheusEndpointOnPort, but tries several ports.
Useful for WSGI applications with multiple processes where each
worker needs its own metrics port for Prometheus scraping.
Parameters:
- port_range: iterable, ports to try (e.g., range(8001, 8010))
- addr: str, address to bind to (default: "" for all interfaces)
Returns:
int or None: Port number chosen, or None if no port available
Raises:
AssertionError: When called with Django autoreloader active
"""
def SetupPrometheusExportsFromConfig():
"""
Exports metrics based on Django settings configuration.
Automatically called by DjangoPrometheusConfig.ready().
Reads PROMETHEUS_METRICS_EXPORT_* settings and configures appropriate export method.
"""class PrometheusEndpointServer(threading.Thread):
"""
A thread class that holds an HTTP server and makes it serve_forever().
Used internally by port-based export functions.
"""
def __init__(self, httpd, *args, **kwargs):
"""
Initialize server thread.
Parameters:
- httpd: HTTPServer instance to run
- *args, **kwargs: Arguments passed to Thread.__init__
"""
def run(self):
"""Run the HTTP server forever in this thread."""Configure metrics export through Django settings:
# settings.py
# Export metrics on a dedicated port (standalone HTTP server)
PROMETHEUS_METRICS_EXPORT_PORT = 8001
# Or export on a range of ports (for multiprocess deployments)
PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8001, 8010)
# Bind to specific address (default: all interfaces)
PROMETHEUS_METRICS_EXPORT_ADDRESS = "127.0.0.1"
# Custom metric namespace
PROMETHEUS_METRIC_NAMESPACE = "myapp"
# Custom latency buckets
PROMETHEUS_LATENCY_BUCKETS = (0.1, 0.5, 1.0, 2.5, 5.0, 10.0, float('inf'))Include metrics endpoint in Django URL configuration:
# urls.py
from django.urls import path, include
urlpatterns = [
# Include django-prometheus URLs (provides /metrics endpoint)
path('', include('django_prometheus.urls')),
# Or manually configure the endpoint
path('metrics', ExportToDjangoView, name='prometheus-metrics'),
# Your application URLs
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')),
]# urls.py
from django.urls import path, include
urlpatterns = [
path('', include('django_prometheus.urls')), # Adds /metrics endpoint
# ... other URLs
]
# The /metrics endpoint will be available at http://your-site.com/metrics
# and will return Prometheus-formatted metrics# settings.py
PROMETHEUS_METRICS_EXPORT_PORT = 8001
# apps.py or any Django app configuration
from django_prometheus.exports import SetupPrometheusEndpointOnPort
class MyAppConfig(AppConfig):
def ready(self):
# Metrics will be available on http://localhost:8001/metrics
# This happens automatically via DjangoPrometheusConfig.ready()
pass# settings.py for WSGI deployment with multiple workers
PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8001, 8010)
# Each worker process will grab an available port in the range
# Prometheus can scrape all ports:
# - job_name: 'django-app'
# static_configs:
# - targets: ['localhost:8001', 'localhost:8002', 'localhost:8003']from django_prometheus.exports import SetupPrometheusEndpointOnPort, SetupPrometheusEndpointOnPortRange
# Manual port setup
def setup_metrics():
try:
SetupPrometheusEndpointOnPort(9090)
print("Metrics available on http://localhost:9090/metrics")
except AssertionError as e:
print(f"Cannot setup metrics server: {e}")
# Multi-port setup
def setup_metrics_multiprocess():
port = SetupPrometheusEndpointOnPortRange(range(9090, 9100))
if port:
print(f"Metrics available on http://localhost:{port}/metrics")
else:
print("No available ports for metrics server")from django.http import HttpResponse
from django_prometheus.exports import ExportToDjangoView
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def custom_metrics_view(request):
"""Custom metrics endpoint with additional logic."""
if not request.user.is_authenticated:
return HttpResponse("Unauthorized", status=401)
# Add custom logic before metrics export
# ... logging, authentication, etc.
return ExportToDjangoView(request)
# urls.py
urlpatterns = [
path('admin/metrics', custom_metrics_view, name='admin-metrics'),
]Django-prometheus automatically detects multiprocess environments:
import os
# Set by gunicorn, uWSGI, or other WSGI servers
os.environ['PROMETHEUS_MULTIPROC_DIR'] = '/tmp/prometheus_metrics'
# Alternative environment variable
os.environ['prometheus_multiproc_dir'] = '/tmp/prometheus_metrics'# When multiprocess directory is set, metrics are aggregated across processes
from prometheus_client import multiprocess, CollectorRegistry
# This happens automatically in ExportToDjangoView
if "PROMETHEUS_MULTIPROC_DIR" in os.environ:
registry = CollectorRegistry()
multiprocess.MultiProcessCollector(registry)
else:
registry = prometheus_client.REGISTRY# settings.py
PROMETHEUS_METRICS_EXPORT_PORT = 8001
# Metrics available at http://localhost:8001/metrics
# Also available through Django at http://localhost:8000/metrics# Start gunicorn with multiple workers
gunicorn --workers 4 --bind 0.0.0.0:8000 myproject.wsgi
# With multiprocess metrics
export PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus_metrics
mkdir -p $PROMETHEUS_MULTIPROC_DIR
gunicorn --workers 4 --bind 0.0.0.0:8000 myproject.wsgi# Dockerfile
EXPOSE 8000 8001
ENV PROMETHEUS_METRICS_EXPORT_PORT=8001
# Metrics will be available on port 8001
# Application on port 8000# deployment.yaml
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8001"
prometheus.io/path: "/metrics"
spec:
containers:
- name: django-app
ports:
- containerPort: 8000 # Django app
- containerPort: 8001 # Metrics
env:
- name: PROMETHEUS_METRICS_EXPORT_PORT
value: "8001"# Django autoreloader conflict
AssertionError: The thread-based exporter can't be safely used when django's autoreloader is active
# Solution: Use --noreload in development or use URL exporter
python manage.py runserver --noreload
# Or use URL-based export instead of port-based export# When port is already in use
OSError: [Errno 48] Address already in use
# Solution: Use port range instead of fixed port
PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8001, 8010)Install with Tessl CLI
npx tessl i tessl/pypi-django-prometheus