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 ClassTypeWhen to UseUpdate Mechanism
CounterMetricCounterEvents that only increase (e.g. signups, failed logins, orders placed).MyCounter.increment(amount=1)
StoredMetricGaugeValues that fluctuate over time (e.g. active users, cache size, worker count).MyGauge.set(value)
CalculatedMetricGauge / ComputedValues computed on-demand when /metrics is scraped (e.g. DB counts).Computes inside get_value(*args)
AverageMetricSummary / AverageRunning arithmetic mean updated per request (e.g. basket value, cart size).MyAverage.add_value(val)
ObservedMetricHistogramLatency 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:

myapp/metrics.py
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:

myapp/views.py
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:

myapp/signals.py
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):

prometheus-podmonitor.yaml
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