Monitoring & Maintenance
Learn how to monitor and maintain Django applications in production for reliability and performance. This is a foundational concept in Python web development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Python/Django experience. Take your time with each section and practice the examples
Production Monitoring
Monitoring and maintaining Django applications in production is essential for ensuring reliability and performance.. This is an essential concept that every Python/Django developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Monitoring Tools & Practices
# Django Debug Toolbar (for development)
INSTALLED_APPS = [
# ...
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ... other middleware
]
INTERNAL_IPS = [
'127.0.0.1',
]
# Custom management commands
# management/commands/check_site_health.py
from django.core.management.base import BaseCommand
from django.core.cache import cache
from django.db import connection
class Command(BaseCommand):
help = 'Check site health and performance'
def handle(self, *args, **options):
# Check database connection
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
self.stdout.write(self.style.SUCCESS('Database: OK'))
except Exception as e:
self.stdout.write(self.style.ERROR(f'Database: ERROR - {e}'))
# Check cache
try:
cache.set('health_check', 'ok', 10)
if cache.get('health_check') == 'ok':
self.stdout.write(self.style.SUCCESS('Cache: OK'))
else:
self.stdout.write(self.style.ERROR('Cache: ERROR'))
except Exception as e:
self.stdout.write(self.style.ERROR(f'Cache: ERROR - {e}'))
# Error tracking with Sentry
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn="your-sentry-dsn",
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True
)
# Custom logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/var/log/django/app.log',
'formatter': 'verbose',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['file', 'console'],
'level': 'INFO',
'propagate': True,
},
'myapp': {
'handlers': ['file', 'console'],
'level': 'DEBUG',
'propagate': True,
},
},
}
# Performance monitoring
from django.core.cache import cache
import time
def performance_monitor(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
cache_key = f'performance_{func.__name__}'
# Store performance metrics
cache.set(cache_key, execution_time, 3600)
return result
return wrapper
# Database backup
# management/commands/backup_db.py
from django.core.management.base import BaseCommand
from django.conf import settings
import subprocess
import os
class Command(BaseCommand):
help = 'Backup database'
def handle(self, *args, **options):
db_settings = settings.DATABASES['default']
if db_settings['ENGINE'] == 'django.db.backends.postgresql':
# PostgreSQL backup
backup_file = f'backup_{timezone.now().strftime("%Y%m%d_%H%M%S")}.sql'
subprocess.run([
'pg_dump',
'-h', db_settings['HOST'],
'-U', db_settings['USER'],
'-d', db_settings['NAME'],
'-f', backup_file
])
self.stdout.write(self.style.SUCCESS(f'Backup created: {backup_file}'))
# Health check endpoint
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET"])
def health_check(request):
try:
# Check database
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
# Check cache
cache.set('health_check', 'ok', 10)
cache_ok = cache.get('health_check') == 'ok'
if cache_ok:
return JsonResponse({
'status': 'healthy',
'database': 'ok',
'cache': 'ok'
})
else:
return JsonResponse({
'status': 'unhealthy',
'cache': 'error'
}, status=500)
except Exception as e:
return JsonResponse({
'status': 'unhealthy',
'error': str(e)
}, status=500)