Отличная статья, спасибо! Была бы она написана и попалась бы мне на глаза пару недель назад, когда пришлось разбираться с подобным в рамках рабоче работе... 🥲
Хотел бы отметить несколько моментов, которые можно сделать иначе (потенциально более эффективно).
Middleware для автоматического сбора. Вместо того, чтобы заниматься вот этим
# Нормализация пути: /api/activities/12345 → /api/activities/{id}
path = request.url.path
if path.startswith('/api/'):
parts = path.split('/')
if len(parts) > 3 and parts[3].isdigit():
parts[3] = '{id}'
path = '/'.join(parts)
К сожалению, в документации есть небольшой нюанс: поскольку мы маунтим приложение, то путь у него будет рутовый, то есть /metrics/, и на /metrics можно попасть только с редиректом, но Prometheus при скрейпинге метрик по редиректам не ходит. )) Ему нужен (по умолчанию) строго путь /metrics. Фиксится так (проблема и её решение уже описаны в issue (https://github.com/prometheus/client_python/issues/1016) в репозитории prometheus-client):
import re
from prometheus_client import make_asgi_app
from starlette.routing import Mount
# create app
route = Mount("/metrics", make_asgi_app())
route.path_regex = re.compile('^/metrics(?P<path>.*)$')
app.routes.append(route)
Отличная статья, спасибо! Была бы она написана и попалась бы мне на глаза пару недель назад, когда пришлось разбираться с подобным в рамках рабоче работе... 🥲
Хотел бы отметить несколько моментов, которые можно сделать иначе (потенциально более эффективно).
Middleware для автоматического сбора. Вместо того, чтобы заниматься вот этим
можно сделать так (основано на ответе на Stackoverflow (https://stackoverflow.com/a/74262037)):
Только важно получать значение после вызова
call_next(request), иначе ключаrouteне будет.2. Endpoint для метрик.
Согласно документации
prometheus-client(https://prometheus.github.io/client_python/exporting/http/fastapi-gunicorn/), вместо кастомногоможно сделать так:
К сожалению, в документации есть небольшой нюанс: поскольку мы маунтим приложение, то путь у него будет рутовый, то есть
/metrics/, и на/metricsможно попасть только с редиректом, но Prometheus при скрейпинге метрик по редиректам не ходит. )) Ему нужен (по умолчанию) строго путь/metrics. Фиксится так (проблема и её решение уже описаны в issue (https://github.com/prometheus/client_python/issues/1016) в репозиторииprometheus-client):