Building a Real-Time SIP Dashboard with dSIPRouter and Grafana
Monitoring your SIP infrastructure in real-time isn't a luxury—it's a necessity. When calls drop or quality degrades, you need to know immediately, not when customers start complaining. This tutorial walks you through building a production-ready monitoring stack using dSIPRouter's Prometheus metrics, Grafana dashboards, and intelligent alerting.
What We're Building
By the end of this tutorial, you'll have:
- Prometheus scraping metrics from dSIPRouter every 15 seconds
- Grafana displaying real-time dashboards for call volume, registration status, and trunk health
- Alerts that notify you via Slack/email when things go wrong
Prerequisites
- dSIPRouter installed and running (v0.74+)
- Docker and Docker Compose (for Prometheus/Grafana)
- Basic familiarity with SIP concepts
- 15-20 minutes of focused time
Part 1: Enabling Prometheus Metrics in dSIPRouter
Step 1: Configure the Metrics Endpoint
dSIPRouter exposes Prometheus-compatible metrics on a dedicated endpoint. First, enable it in your configuration:
# Edit dSIPRouter settings
cd /etc/dsiprouter/gui
nano settings.py
Find and update these settings:
# Prometheus metrics configuration
PROMETHEUS_ENABLED = True
PROMETHEUS_PORT = 9090
PROMETHEUS_METRICS_PATH = '/metrics'
Restart dSIPRouter to apply changes:
dsiprouter restart
Step 2: Verify Metrics Are Exposed
Test that metrics are accessible:
curl http://localhost:9090/metrics
You should see output like:
# HELP dsip_active_calls Current number of active calls
# TYPE dsip_active_calls gauge
dsip_active_calls 12
# HELP dsip_registrations_total Total SIP registrations
# TYPE dsip_registrations_total counter
dsip_registrations_total{status="success"} 1547
dsip_registrations_total{status="failed"} 23
# HELP dsip_trunk_utilization Percentage of trunk capacity in use
# TYPE dsip_trunk_utilization gauge
dsip_trunk_utilization{trunk="carrier_a"} 0.45
dsip_trunk_utilization{trunk="carrier_b"} 0.72
Part 2: Setting Up Prometheus
Step 1: Create the Docker Compose Stack
Create a directory for your monitoring stack:
mkdir -p ~/dsip-monitoring && cd ~/dsip-monitoring
Create docker-compose.yml:
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9091:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./alert-rules.yml:/etc/prometheus/alert-rules.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
restart: unless-stopped
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=your_secure_password
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
restart: unless-stopped
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
Step 2: Configure Prometheus Scraping
Create prometheus.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- "alert-rules.yml"
scrape_configs:
- job_name: 'dsiprouter'
static_configs:
- targets: ['host.docker.internal:9090'] # Use your dSIPRouter IP
metrics_path: /metrics
scrape_interval: 15s
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
Note: Replace host.docker.internal with your dSIPRouter server's IP if running on a different host.
Step 3: Launch the Stack
docker-compose up -d
Verify everything is running:
docker-compose ps
Part 3: Building Grafana Dashboards
Step 1: Access Grafana
Open http://your-server:3000 in your browser. Log in with:
- Username: admin
- Password: (the one you set in docker-compose.yml)
Step 2: Add Prometheus Data Source
- Navigate to Configuration → Data Sources
- Click Add data source
- Select Prometheus
- Set URL to
http://prometheus:9091 - Click Save & Test
Step 3: Create the SIP Dashboard
Click Create → Dashboard, then add these panels:
Panel 1: Active Calls (Stat)
dsip_active_calls
Settings:
- Visualization: Stat
- Color mode: Value
- Thresholds: 0 (green), 50 (yellow), 100 (red)
Panel 2: Call Volume Over Time (Time Series)
rate(dsip_calls_total[5m]) * 60
This shows calls per minute, smoothed over 5-minute windows.
Panel 3: Registration Success Rate (Gauge)
sum(rate(dsip_registrations_total{status="success"}[5m])) /
sum(rate(dsip_registrations_total[5m])) * 100
Settings:
- Visualization: Gauge
- Min: 0, Max: 100
- Thresholds: 95 (green), 90 (yellow), below (red)
Panel 4: Trunk Utilization (Bar Gauge)
dsip_trunk_utilization * 100
Settings:
- Visualization: Bar gauge
- Orientation: Horizontal
- Thresholds: 70 (green), 85 (yellow), 95 (red)
Panel 5: Call Quality (MOS Score)
avg(dsip_call_quality_mos)
Settings:
- Visualization: Gauge
- Min: 1, Max: 5
- Thresholds: 4.0 (green), 3.5 (yellow), below (red)
Panel 6: Failed Registrations (Time Series)
rate(dsip_registrations_total{status="failed"}[5m]) * 60
Settings:
- Visualization: Time series
- Color: Red
- Fill opacity: 20
Step 4: Save Your Dashboard
Click Save dashboard (disk icon), name it "dSIPRouter SIP Monitoring", and save.
Part 4: Creating Intelligent Alerts
Alert Rules Configuration
Create alert-rules.yml in your monitoring directory:
groups:
- name: dsiprouter_alerts
interval: 30s
rules:
# Call Quality Degradation
- alert: CallQualityDegraded
expr: avg(dsip_call_quality_mos) < 3.5
for: 2m
labels:
severity: warning
annotations:
summary: "Call quality below acceptable threshold"
description: "Average MOS score is {{ $value | printf \"%.2f\" }} (threshold: 3.5)"
- alert: CallQualityCritical
expr: avg(dsip_call_quality_mos) < 3.0
for: 1m
labels:
severity: critical
annotations:
summary: "CRITICAL: Severe call quality degradation"
description: "Average MOS score dropped to {{ $value | printf \"%.2f\" }}"
# Registration Failures
- alert: HighRegistrationFailures
expr: |
sum(rate(dsip_registrations_total{status="failed"}[5m])) /
sum(rate(dsip_registrations_total[5m])) * 100 > 5
for: 3m
labels:
severity: warning
annotations:
summary: "Registration failure rate elevated"
description: "{{ $value | printf \"%.1f\" }}% of registrations failing"
- alert: RegistrationFailureSpike
expr: |
sum(rate(dsip_registrations_total{status="failed"}[5m])) /
sum(rate(dsip_registrations_total[5m])) * 100 > 15
for: 1m
labels:
severity: critical
annotations:
summary: "CRITICAL: Registration failure spike detected"
description: "{{ $value | printf \"%.1f\" }}% of registrations failing"
# Trunk Utilization
- alert: TrunkHighUtilization
expr: dsip_trunk_utilization > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Trunk utilization high on {{ $labels.trunk }}"
description: "Trunk {{ $labels.trunk }} at {{ $value | printf \"%.0f\" }}% capacity"
- alert: TrunkNearCapacity
expr: dsip_trunk_utilization > 0.95
for: 2m
labels:
severity: critical
annotations:
summary: "CRITICAL: Trunk {{ $labels.trunk }} near capacity"
description: "Trunk at {{ $value | printf \"%.0f\" }}% - calls may be rejected"
# System Health
- alert: dSIPRouterDown
expr: up{job="dsiprouter"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "CRITICAL: dSIPRouter is unreachable"
description: "Prometheus cannot scrape dSIPRouter metrics"
Configure Alert Notifications
Create alertmanager.yml for Slack notifications:
global:
slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
route:
group_by: ['alertname']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'slack-notifications'
routes:
- match:
severity: critical
receiver: 'slack-critical'
repeat_interval: 30m
receivers:
- name: 'slack-notifications'
slack_configs:
- channel: '#sip-monitoring'
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}'
send_resolved: true
- name: 'slack-critical'
slack_configs:
- channel: '#sip-critical'
title: '🚨 {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}'
send_resolved: true
Restart the stack to apply alert configuration:
docker-compose restart
Part 5: Production Considerations
Security Hardening
- Secure the metrics endpoint with authentication:
# In dSIPRouter settings.py
PROMETHEUS_AUTH_ENABLED = True
PROMETHEUS_AUTH_USER = 'metrics'
PROMETHEUS_AUTH_PASSWORD = 'your_secure_password'
Update prometheus.yml:
scrape_configs:
- job_name: 'dsiprouter'
basic_auth:
username: 'metrics'
password: 'your_secure_password'
-
Use HTTPS for Grafana in production (configure reverse proxy with SSL)
-
Restrict network access to monitoring ports using firewall rules
High Availability
For production deployments, consider:
- Running Prometheus with remote storage (Thanos, Cortex)
- Setting up Grafana with a PostgreSQL backend for dashboard persistence
- Using Alertmanager in cluster mode for HA alerting
Useful Additional Metrics
Extend your monitoring with these queries:
# Calls per carrier
sum by (carrier) (rate(dsip_calls_total[5m]))
# Average call duration
avg(dsip_call_duration_seconds)
# SIP response codes
sum by (code) (rate(dsip_sip_responses_total[5m]))
# Endpoint registration count
count(dsip_endpoint_registered == 1)
Wrapping Up
You now have a production-grade monitoring stack that:
✅ Scrapes real-time metrics from dSIPRouter every 15 seconds
✅ Visualizes call volume, quality, and trunk utilization
✅ Alerts you immediately when problems occur
✅ Stores 30 days of historical data for trend analysis
This setup transforms reactive firefighting into proactive monitoring. You'll catch registration storms before they cascade, spot quality degradation as it starts, and know exactly when it's time to add trunk capacity.
Next steps:
- Customize alert thresholds based on your traffic patterns
- Add business-hours-aware alerting
- Create executive dashboards showing daily/weekly call statistics
- Integrate with your incident management platform (PagerDuty, Opsgenie)
Questions or running into issues? Drop by the dSIPRouter community—we're happy to help you fine-tune your monitoring setup.