Custom Prometheus Metrics
Django Hurricane includes an integrated Prometheus metrics exporter running directly inside its gateway and probe application. Beyond the built-in system metrics (request counts, latency averages, and queue lengths), Hurricane provides a declarative framework for defining and exporting custom application and business metrics.
The 5 Metric Primitives
Hurricane provides five base metric primitives in hurricane.metrics:
| Metric Class | Type | When to Use | Update Mechanism |
|---|---|---|---|
CounterMetric | Counter | Events that only increase (e.g. signups, failed logins, orders placed). | MyCounter.increment(amount=1) |
StoredMetric | Gauge | Values that fluctuate over time (e.g. active users, cache size, worker count). | MyGauge.set(value) |
CalculatedMetric | Gauge / Computed | Values computed on-demand when /metrics is scraped (e.g. DB counts). | Computes inside get_value(*args) |
AverageMetric | Summary / Average | Running arithmetic mean updated per request (e.g. basket value, cart size). | MyAverage.add_value(val) |
ObservedMetric | Histogram | Latency distributions and percentile buckets (e.g. payment gateway latency). | MyHistogram.observe(val) |
Developing Custom Metrics: Step-by-Step
1. Define Metrics in Your Application
Create a metrics.py file inside your Django app:
from prometheus_client import Histogram
from hurricane.metrics import (
AverageMetric,
CalculatedMetric,
CounterMetric,
ObservedMetric,
StoredMetric,
)
from hurricane.metrics.registry import registry
from myapp.models import Order
# 1. Counter: Tracks completed checkouts
class CheckoutCounterMetric(CounterMetric):
code = "ecommerce_checkouts_total"
description = "Total number of completed checkout operations"
# 2. Stored Metric: Gauge of active connected users
class ActiveSessionsMetric(StoredMetric):
code = "ecommerce_active_sessions"
description = "Current number of active authenticated user sessions"
# 3. Calculated Metric: Computes pending orders directly on scrape
class PendingOrdersMetric(CalculatedMetric):
code = "ecommerce_pending_orders_count"
description = "Number of orders currently in pending status"
@classmethod
def get_value(cls, *args):
# Executes automatically only when Prometheus scrapes /metrics
return Order.objects.filter(status="pending").count()
# 4. Average Metric: Running moving average of order values
class AverageOrderValueMetric(AverageMetric):
code = "ecommerce_order_value_average_dollars"
description = "Average transaction dollar amount per completed order"
# 5. Observed Metric: Latency histogram for external payment gateway
class PaymentGatewayLatencyMetric(ObservedMetric):
code = "ecommerce_payment_gateway_latency_seconds"
description = "Latency distribution of third-party payment provider calls"
prometheus = Histogram(
"ecommerce_payment_gateway_latency_seconds",
"Payment gateway latency in seconds",
buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0),
)
# Register all custom metrics with Hurricane's registry
registry.register(CheckoutCounterMetric)
registry.register(ActiveSessionsMetric)
registry.register(PendingOrdersMetric)
registry.register(AverageOrderValueMetric)
registry.register(PaymentGatewayLatencyMetric)
2. Updating Metrics in Views and Services
Call your metrics directly within your Django views, services, or background workers:
import time
from django.http import JsonResponse
from myapp.metrics import (
AverageOrderValueMetric,
CheckoutCounterMetric,
PaymentGatewayLatencyMetric,
)
from myapp.services import charge_payment_provider
def checkout_view(request):
order_total = float(request.POST.get("total", 0.0))
# Time external payment provider call
start_time = time.perf_counter()
charge_payment_provider(order_total)
duration = time.perf_counter() - start_time
# Record metrics
CheckoutCounterMetric.increment()
AverageOrderValueMetric.add_value(order_total)
PaymentGatewayLatencyMetric.observe(duration)
return JsonResponse({"status": "success"})
3. Hooking into Django Signals
Update stored metrics dynamically upon model changes using Django signals:
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver
from myapp.metrics import ActiveSessionsMetric
# Maintain active session count
_active_users = 0
@receiver(user_logged_in)
def on_user_logged_in(sender, request, user, **kwargs):
global _active_users
_active_users += 1
ActiveSessionsMetric.set(_active_users)
@receiver(user_logged_out)
def on_user_logged_out(sender, request, user, **kwargs):
global _active_users
_active_users = max(0, _active_users - 1)
ActiveSessionsMetric.set(_active_users)
Prometheus Scrape Verification
Once registered, your metrics appear automatically on the /metrics endpoint:
curl -s http://127.0.0.1:8001/metrics | grep ecommerce
Output:
# HELP ecommerce_checkouts_total Total number of completed checkout operations
# TYPE ecommerce_checkouts_total counter
ecommerce_checkouts_total 42.0
# HELP ecommerce_active_sessions Current number of active authenticated user sessions
# TYPE ecommerce_active_sessions gauge
ecommerce_active_sessions 18.0
# HELP ecommerce_pending_orders_count Number of orders currently in pending status
# TYPE ecommerce_pending_orders_count gauge
ecommerce_pending_orders_count 3.0
# HELP ecommerce_order_value_average_dollars Average transaction dollar amount per completed order
# TYPE ecommerce_order_value_average_dollars gauge
ecommerce_order_value_average_dollars 64.50
# HELP ecommerce_payment_gateway_latency_seconds Payment gateway latency in seconds
# TYPE ecommerce_payment_gateway_latency_seconds histogram
ecommerce_payment_gateway_latency_seconds_bucket{le="0.1"} 35.0
ecommerce_payment_gateway_latency_seconds_bucket{le="0.5"} 41.0
ecommerce_payment_gateway_latency_seconds_bucket{le="1.0"} 42.0
ecommerce_payment_gateway_latency_seconds_bucket{le="+Inf"} 42.0
ecommerce_payment_gateway_latency_seconds_count 42.0
ecommerce_payment_gateway_latency_seconds_sum 4.82
Prometheus Kubernetes Scrape Configuration
To collect metrics in a Kubernetes cluster, configure Prometheus to scrape the dedicated probe port (8001):
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: django-hurricane-monitor
labels:
release: prometheus-stack
spec:
selector:
matchLabels:
app: django-app
podMetricsEndpoints:
- port: probes
path: /metrics
interval: 15s
scrapeTimeout: 10s
