feat: Prometheus-метрики GET /metrics + ленивый ISO-8601-парсер для backoff
Build LLM Proxy / Build and push (release) Successful in 40s
Build LLM Proxy / Build and push (release) Successful in 40s
- GET /metrics (Prometheus text 0.0.4): llm_proxy_requests_total{model,upstream,provider,result}
(ok/4xx/429/402/5xx/net_err/cancelled), llm_proxy_upstream_inflight,
llm_proxy_upstream_fail_streak, llm_proxy_upstream_cooling_seconds
- учёт исходов в handleChat (каждая фейловер-попытка — отдельно)
- parseIsoDuration: PnM≈n×30d, PnY≈n×365d (kotlin.time Duration.parse не принимает Y/M)
- remainingSeconds округляет остаток вверх (открытое окно ≥1s)
- доки (CONFIG.md/README/TESTING) + тесты (MetricsTest, BackoffTest)
This commit is contained in:
@@ -297,10 +297,11 @@ providers:
|
||||
(`all upstreams cooling, retry in Ns`) с заголовком `Retry-After: N`
|
||||
(секунд до выхода первого апстрима из отката).
|
||||
|
||||
Значение — ISO-8601-длительность (формат, в котором сериализуется
|
||||
`kotlin.time.Duration`): `PT30M` (30 минут), `PT1H15M`, `P1D` (сутки),
|
||||
`P1M` (месяц). Некорректное значение — предупреждение в лог и поле
|
||||
просто игнорируется.
|
||||
Значение — ISO-8601-длительность: `PT30M` (30 минут), `PT1H15M`, `P1D` (сутки),
|
||||
`P1M` (месяц), `P1Y` (год). Годы/месяцы укорачиваются приближённо
|
||||
(1 год ≈ 365d, 1 месяц ≈ 30d) — kotlin.time `Duration.parse` не принимает
|
||||
Y/M (у них нет фиксированной длины), конфиг-парсер прокси расширяет формат.
|
||||
Некорректное значение — предупреждение в лог и поле просто игнорируется.
|
||||
|
||||
```yaml
|
||||
providers:
|
||||
@@ -318,6 +319,29 @@ upstreams:
|
||||
При старте выводится, что настроено:
|
||||
`[llm-proxy] backoff: upstreams=routerai-gpt4o=PT15M providers=routerai=P1M`.
|
||||
|
||||
### Prometheus-метрики (`/metrics`)
|
||||
|
||||
Прокси отдаёт pull-метрики в Prometheus text-формате по `GET /metrics`
|
||||
(`text/plain; version=0.0.4`), без авторизации (внутренний контур).
|
||||
Достаточно включить скрейп в Prometheus/VictoriaMetrics — и в Grafana можно
|
||||
вести дашборды использования по провайдерам/моделям и алерты на деградацию.
|
||||
|
||||
| Метрика | Тип | Смысл |
|
||||
|---|---|---|
|
||||
| `llm_proxy_requests_total{model, upstream, provider, result}` | counter | chat-запросы по исходу. `result`: `ok` — успех, `4xx` — ошибка запроса, `429`/`402`/`5xx` — исход с апстрима (каждая фейловер-попытка учитывается отдельно), `net_err` — сетевая ошибка/таймаут, `cancelled` — клиент отвалился посреди стрима |
|
||||
| `llm_proxy_upstream_inflight{upstream, provider}` | gauge | занятые слоты апстрима прямо сейчас (конкурентность) |
|
||||
| `llm_proxy_upstream_fail_streak{upstream, provider}` | gauge | счётчик сбоев подряд (backoff): сколько раз подряд упал |
|
||||
| `llm_proxy_upstream_cooling_seconds{upstream, provider}` | gauge | сколько секунд апстрим ещё в backoff-откате (0 = жив) |
|
||||
|
||||
Метки: `model` — витринное имя модели, `upstream`/`provider` — внутренние id из конфига.
|
||||
Метрики live в памяти: при рестарте прокси сбрасываются (серить их будет Prometheus).
|
||||
|
||||
Примеры для Grafana:
|
||||
- оборот по виртуальным моделям: `sum(rate(llm_proxy_requests_total[5m])) by (model)`;
|
||||
- оборот по провайдерам: `sum(rate(llm_proxy_requests_total[5m])) by (provider)`;
|
||||
- «провайдер умер»: `llm_proxy_upstream_cooling_seconds > 0` дольше N минут — алерт;
|
||||
- доля ошибок провайдера: `sum(rate(llm_proxy_requests_total{result=~"4xx|429|402|5xx|net_err"}[10m])) by (provider) / sum(rate(llm_proxy_requests_total[10m])) by (provider)`.
|
||||
|
||||
### Пример сборки тела (многослойный `patch`)
|
||||
|
||||
Берём модель `my-gpt` (из примера выше), маршрут уходит на апстрим
|
||||
|
||||
Reference in New Issue
Block a user