← Назад к вопросам
Как мониторить работоспособность приложения?
2.0 Middle🔥 201 комментариев
#DevOps и инфраструктура#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как мониторить работоспособность приложения?
Мониторинг — это не просто красивые графики. Это система раннего предупреждения, которая ловит проблемы ДО того, как их заметят пользователи. Рассмотрю комплексный подход.
1. Health Check Endpoints
Основа всего мониторинга — простой endpoint, который проверяет работоспособность:
from fastapi import FastAPI
from datetime import datetime
import asyncio
import psutil
app = FastAPI()
@app.get("/health")
async def health_check():
"""Простой health check"""
return {"status": "ok", "timestamp": datetime.utcnow().isoformat()}
@app.get("/health/deep")
async def deep_health_check():
"""Проверка всех зависимостей"""
checks = {
"database": await check_database(),
"redis": await check_redis(),
"disk_usage": psutil.disk_usage("/").percent,
"memory_usage": psutil.virtual_memory().percent,
"cpu_usage": psutil.cpu_percent(interval=1),
}
all_ok = all(v for k, v in checks.items() if k != "disk_usage")
return {
"status": "healthy" if all_ok else "degraded",
"timestamp": datetime.utcnow().isoformat(),
"checks": checks
}
async def check_database():
try:
# Пинг БД
await db.execute("SELECT 1")
return True
except Exception:
return False
async def check_redis():
try:
await redis.ping()
return True
except Exception:
return False
2. Prometheus для метрик
Структурированный сбор метрик:
from prometheus_client import Counter, Histogram, Gauge
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
from fastapi.responses import Response
import time
# Определяем метрики
http_requests_total = Counter(
"http_requests_total",
"Total HTTP requests",
["method", "endpoint", "status"]
)
http_request_duration = Histogram(
"http_request_duration_seconds",
"HTTP request duration in seconds",
["method", "endpoint"]
)
active_users = Gauge(
"active_users_total",
"Number of active users"
)
db_query_duration = Histogram(
"db_query_duration_seconds",
"Database query duration",
["query_type"]
)
# Middleware для отслеживания запросов
@app.middleware("http")
async def track_requests(request, call_next):
start = time.time()
response = await call_next(request)
duration = time.time() - start
http_requests_total.labels(
method=request.method,
endpoint=request.url.path,
status=response.status_code
).inc()
http_request_duration.labels(
method=request.method,
endpoint=request.url.path
).observe(duration)
return response
# Endpoint для Prometheus
@app.get("/metrics")
async def metrics():
return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
3. Логирование с трассировкой
import logging
import json
from uuid import uuid4
class RequestIdFilter(logging.Filter):
def filter(self, record):
record.request_id = getattr(record, "request_id", "")
return True
# Middleware для добавления request ID
@app.middleware("http")
async def add_request_id(request, call_next):
request_id = request.headers.get("X-Request-ID", str(uuid4()))
response = await call_next(request)
response.headers["X-Request-ID"] = request_id
return response
# JSON логирование
logger = logging.getLogger(__name__)
logger.addFilter(RequestIdFilter())
@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
logger.info(
"Fetching user",
extra={
"user_id": user_id,
"timestamp": datetime.utcnow().isoformat()
}
)
return {"id": user_id, "name": "John"}
4. Grafana Dashboard
Конфигурация для визуализации:
{
"dashboard": {
"title": "API Monitoring",
"panels": [
{
"title": "Request Rate",
"targets": [
{
"expr": "rate(http_requests_total[5m])"
}
]
},
{
"title": "Response Time (p95)",
"targets": [
{
"expr": "histogram_quantile(0.95, http_request_duration_seconds)"
}
]
},
{
"title": "Error Rate",
"targets": [
{
"expr": "rate(http_requests_total{status=~\"5..\"}[5m])"
}
]
},
{
"title": "Database Queries",
"targets": [
{
"expr": "rate(db_query_duration_seconds_total[5m])"
}
]
}
]
}
}
5. Alerting Rules (Prometheus)
# alert-rules.yml
groups:
- name: api-alerts
rules:
# Высокая rate ошибок
- alert: HighErrorRate
expr: (rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])) > 0.05
for: 5m
annotations:
summary: "High error rate detected"
description: "Error rate is {{ $value | humanizePercentage }} over last 5 minutes"
# Медленные запросы
- alert: SlowApiResponse
expr: histogram_quantile(0.95, http_request_duration_seconds) > 1
for: 5m
annotations:
summary: "API response time is slow"
# БД недоступна
- alert: DatabaseDown
expr: db_health == 0
for: 1m
annotations:
summary: "Database is unavailable"
# Высокая используемость памяти
- alert: HighMemoryUsage
expr: process_resident_memory_bytes > 1000000000
for: 10m
annotations:
summary: "Memory usage is {{ $value | humanize }}B"
# Высокая нагрузка на диск
- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.2
for: 5m
annotations:
summary: "Less than 20% disk space available"
6. Distributed Tracing (Jaeger)
from opentelemetry import trace
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Инициализация Jaeger
jaeger_exporter = JaegerExporter(
agent_host_name="localhost",
agent_port=6831,
)
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(jaeger_exporter)
)
tracer = trace.get_tracer(__name__)
# Использование
@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
with tracer.start_as_current_span("get_user") as span:
span.set_attribute("user.id", user_id)
with tracer.start_as_current_span("db_query"):
user = await db.query(User).filter(User.id == user_id).first()
with tracer.start_as_current_span("serialize_response"):
return user.to_dict()
7. Uptimerobot/Pingdom для external monitoring
# Регулярно проверяет эндпоинт
curl -s https://api.example.com/health | jq .
# Можно настроить на UptimeRobot.com
# Будет отправлять уведомления, если сервис недоступен
8. Логирование в ELK Stack
import logging
from pythonjsonlogger import jsonlogger
from elastic_transport import Transport
# Отправка логов в Elasticsearch
handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter()
handler.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)
# Использование
logger.info(
"API call",
extra={
"service": "api",
"endpoint": "/api/users",
"method": "GET",
"status_code": 200,
"duration_ms": 145,
"user_id": 12345
}
)
9. Сценарий реагирования на алерты
# На основе алертов из Prometheus/Alertmanager
def handle_high_error_rate():
"""
1. Отправить уведомление в Slack
2. Создать incident в PagerDuty
3. Собрать логи за последний час
4. Проверить состояние БД
"""
pass
def handle_database_down():
"""
1. Немедленный алерт в Slack/SMS
2. Попытка переключиться на replica
3. Уменьшить нагрузку (circuit breaker)
4. Вызвать DBA на-duty
"""
pass
10. Docker Compose для локального мониторинга
version: "3.8"
services:
app:
build: .
ports:
- "8000:8000"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3000:3000"
depends_on:
- prometheus
jaeger:
image: jaegertracing/all-in-one
ports:
- "6831:6831/udp"
- "16686:16686"
Чек-лист мониторинга
- Health checks — простой и глубокий
- Метрики — Prometheus для всех важных операций
- Логирование — структурированное и централизованное
- Alerting — автоматические уведомления при проблемах
- Трассировка — Jaeger для debug распределённых запросов
- Dashboards — Grafana для визуализации
- SLA мониторинг — отслеживание uptime
- Capacity planning — прогнозирование роста нагрузки
Хороший мониторинг экономит часы на отладку в production и сохраняет нервы при инцидентах.