Django middlewares to monitor your application with Prometheus.io
—
Track applied and unapplied Django migrations across database connections to monitor deployment and migration status. Provides visibility into database schema state and migration progress.
Functions to track and export Django migration status as Prometheus metrics.
def ExportMigrations():
"""
Exports counts of unapplied migrations.
This is meant to be called during app startup, ideally by
django_prometheus.apps.AppConfig.ready().
Iterates through all database connections and exports migration
counts for each database alias.
"""
def ExportMigrationsForDatabase(alias: str, executor):
"""
Exports migration counts for a specific database.
Parameters:
- alias: str, database connection alias name (e.g., 'default', 'analytics')
- executor: Django MigrationExecutor instance for the database connection
"""class DjangoPrometheusConfig(AppConfig):
"""Django app configuration that automatically sets up monitoring."""
def ready(self):
"""
Initializes Prometheus exports when Django apps are ready.
Automatically calls ExportMigrations() if migration export is enabled
via PROMETHEUS_EXPORT_MIGRATIONS setting.
"""django_migrations_unapplied_total: Gauge showing count of unapplied migrations by database connectiondjango_migrations_applied_total: Gauge showing count of applied migrations by database connectionBoth metrics include the connection label indicating the database alias.
Enable migration monitoring in Django settings:
# settings.py
# Enable migration monitoring (disabled by default)
PROMETHEUS_EXPORT_MIGRATIONS = True
# Custom metric namespace (optional)
PROMETHEUS_METRIC_NAMESPACE = "myapp"
# Multiple database configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_db',
# ... connection settings
},
'analytics': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'analytics_db',
# ... connection settings
}
}Migration monitoring is automatically enabled when django_prometheus is in INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
'django_prometheus', # Must be in INSTALLED_APPS
# ... other apps
]
# Migration monitoring happens automatically in AppConfig.ready()# settings.py
INSTALLED_APPS = ['django_prometheus', ...]
PROMETHEUS_EXPORT_MIGRATIONS = True
# Migration metrics will be automatically exported when Django starts
# Available at /metrics endpoint or configured export port# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_app',
},
'user_data': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'user_database',
},
'cache_db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/tmp/cache.db',
}
}
PROMETHEUS_EXPORT_MIGRATIONS = True
# Each database will have separate migration metrics:
# django_migrations_applied_total{connection="default"}
# django_migrations_applied_total{connection="user_data"}
# django_migrations_applied_total{connection="cache_db"}from django_prometheus.migrations import ExportMigrations, ExportMigrationsForDatabase
from django.db import connections
from django.db.migrations.executor import MigrationExecutor
# Manual export for all databases
ExportMigrations()
# Manual export for specific database
connection = connections['default']
executor = MigrationExecutor(connection)
ExportMigrationsForDatabase('default', executor)from django.apps import AppConfig
from django_prometheus.migrations import ExportMigrations
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
# Custom logic before migration export
if self.should_export_migrations():
ExportMigrations()
def should_export_migrations(self):
"""Custom logic to determine if migrations should be exported."""
return os.environ.get('EXPORT_MIGRATIONS', 'false').lower() == 'true'# Example metric values:
# django_migrations_applied_total{connection="default"} 42
# django_migrations_unapplied_total{connection="default"} 3
# This means:
# - 42 migrations have been applied to the 'default' database
# - 3 migrations are pending application
# - Total migrations defined: 45 (42 + 3)Use migration metrics to monitor deployment status:
# Alerting rules for migration status:
# - Alert if unapplied_migrations > 0 after deployment
# - Alert if applied_migrations decreases (rollback scenario)
# - Monitor migration counts across different environmentsThe monitoring system uses Django's migration framework internally:
from django.db.migrations.executor import MigrationExecutor
from django.db.migrations.loader import MigrationLoader
# Migration planning (done internally)
executor = MigrationExecutor(connection)
plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
# Applied migrations count
applied_count = len(executor.loader.applied_migrations)
# Unapplied migrations count
unapplied_count = len(plan)# The system analyzes the complete migration graph
loader = MigrationLoader(connection)
# All defined migrations
all_migrations = loader.graph.nodes
# Applied migrations (from django_migrations table)
applied_migrations = loader.applied_migrations
# Unapplied migrations (calculated difference)
unapplied_migrations = set(all_migrations) - applied_migrations# Graceful handling of database connection problems
from django.db.backends.dummy.base import DatabaseWrapper
# If DATABASES = {} (no database configured)
if isinstance(connections["default"], DatabaseWrapper):
# Skip migration export - no real database configured
return
# Connection-specific error handling
for alias in connections.databases:
try:
executor = MigrationExecutor(connections[alias])
ExportMigrationsForDatabase(alias, executor)
except Exception as e:
# Log error but don't crash application startup
logger.warning(f"Could not export migrations for {alias}: {e}")# Handle migration loading errors gracefully
try:
loader = MigrationLoader(connection)
applied_migrations = loader.applied_migrations
except Exception as e:
# Set metrics to -1 to indicate error state
applied_migrations.labels(connection=alias).set(-1)
unapplied_migrations.labels(connection=alias).set(-1)Install with Tessl CLI
npx tessl i tessl/pypi-django-prometheus