All checks were successful
CI / backend-tests (pull_request) Successful in 17m59s
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 12s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m18s
CI Trade-In / backend-tests (pull_request) Successful in 5m59s
Владелец попросил вывести продукт в Графану — до этого там были только
технические панели (запросы/латентность/память). Список счётчиков взят из
реально пишущихся событий, а не выдуман:
Мера (tradein-mvp/backend/app/observability/metrics.py):
- mera_estimates_total{outcome=ok|insufficient_data} — POST /estimate,
зеркалит user_events.event_type=estimate_request (294 строки в БД),
insufficient_data — не ошибка, а исход без аналогов.
- mera_address_suggestions_total{found=yes|no} — GET /geocode/suggest,
своего user_events-события у ручки не было.
- mera_reports_exported_total (без лейблов) — GET /estimate/{id}/pdf.
- mera_leads_total (без лейблов) — POST /trade-in/lead.
- mera_support_messages_total{channel=web|anon} — POST /support/messages
и /support/anon/messages, счётчик после успешной доставки в Telegram.
- mera_logins_total{result=success|failed} — рядом с user_events
login_success/login_failed в auth.py (97/453 строк в БД).
Птица (backend/app/observability/metrics.py):
- sitefinder_reports_exported_total{format} — GET .../forecast/export
(md/json/tg/docx/pptx/pdf) и POST .../best-layouts/pdf.
Метки везде — фиксированный литерал из места вызова (outcome/found/channel/
result/format), никогда username/адрес/estimate_id/кадастровый номер —
это ровно то, что взрывает кардинальность ряда у Prometheus.
Дашборд ops/metrics/grafana/dashboards/product.json ("Продуктовые метрики",
uid gendesign-product) — воронка Меры (оценки/подсказки/лиды/отчёты/входы/
поддержка) + экспорт форматов Птицы, часовые increase()-панели без
стекирования (на соседней панели оно уже давало ложную тревогу, PR #3474).
Provisioning тот же, что у apps.json — сканирует директорию, отдельного
конфига не нужно.
ops/metrics/alloy/alloy-apps.alloy проверен: у job "apps" нет relabel-
фильтра по __name__ (в отличие от cadvisor) — новые счётчики уходят в
remote_write как есть, правки не потребовалось.
Refs #3471
161 lines
8.7 KiB
JSON
161 lines
8.7 KiB
JSON
{
|
||
"uid": "gendesign-product",
|
||
"title": "Продуктовые метрики",
|
||
"description": "Числа бизнеса, а не процесса: сколько людей реально что-то сделали в «Мере» и «Птице» (#3471). Источник — те же счётчики Prometheus, что и на дашборде «Приложения», только считают не HTTP-статусы, а продуктовые события (оценка, лид, отчёт, вход, обращение в поддержку). Часовое окно нарочно грубое: при текущем трафике (сотни событий в сутки) минутные всплески — шум, а не сигнал.",
|
||
"tags": ["gendesign", "product"],
|
||
"timezone": "browser",
|
||
"editable": false,
|
||
"schemaVersion": 39,
|
||
"refresh": "5m",
|
||
"time": { "from": "now-24h", "to": "now" },
|
||
"panels": [
|
||
{ "type": "row", "title": "Мера — воронка продукта", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 } },
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Оценок в час, по исходу",
|
||
"description": "insufficient_data — не ошибка: аналогов рядом с адресом не нашлось, расчёт прошёл штатно. Тревожиться стоит, если эта линия начинает расти быстрее ok — значит покрытие рынка проседает, а не то, что сломался расчёт.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 1 },
|
||
"targets": [
|
||
{
|
||
"refId": "A",
|
||
"expr": "sum by (outcome) (increase(mera_estimates_total[1h]))",
|
||
"legendFormat": "{{outcome}}"
|
||
}
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": [
|
||
{ "matcher": { "id": "byName", "options": "insufficient_data" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] },
|
||
{ "matcher": { "id": "byName", "options": "ok" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }
|
||
]
|
||
}
|
||
},
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Подсказки адреса в час, нашёлся ли результат",
|
||
"description": "found=no — человек напечатал адрес, а автокомплит ничего не предложил: либо адреса нет в базе, либо он вне зоны покрытия. Устойчивый рост этой линии — повод расширять покрытие, а не баг одного запроса.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 1 },
|
||
"targets": [
|
||
{
|
||
"refId": "A",
|
||
"expr": "sum by (found) (increase(mera_address_suggestions_total[1h]))",
|
||
"legendFormat": "найден: {{found}}"
|
||
}
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": [
|
||
{ "matcher": { "id": "byRegexp", "options": ".*no.*" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] }
|
||
]
|
||
}
|
||
},
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Лиды и скачанные отчёты в час",
|
||
"description": "Лид — заявка с телефоном после оценки, отчёт — скачанный PDF по оценке. Оба редкие: сверяйте с недельным окном (кнопка времени вверху), часовой провал сам по себе ни о чём не говорит при таком трафике.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 9 },
|
||
"targets": [
|
||
{ "refId": "A", "expr": "increase(mera_leads_total[1h])", "legendFormat": "лиды" },
|
||
{ "refId": "B", "expr": "increase(mera_reports_exported_total[1h])", "legendFormat": "отчёты" }
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": []
|
||
}
|
||
},
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Входы в час, по исходу",
|
||
"description": "Устойчивый рост failed при ровном success — либо перебор паролей, либо сломался клиент (истёкшая сессия, старый билд фронта). При подозрении на перебор смотрите заодно панель «Отказы авторизации и лимитера» на дашборде «Приложения» — там 401/429 по HTTP.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 9 },
|
||
"targets": [
|
||
{
|
||
"refId": "A",
|
||
"expr": "sum by (result) (increase(mera_logins_total[1h]))",
|
||
"legendFormat": "{{result}}"
|
||
}
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": [
|
||
{ "matcher": { "id": "byName", "options": "failed" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } } ] },
|
||
{ "matcher": { "id": "byName", "options": "success" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }
|
||
]
|
||
}
|
||
},
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Обращения в поддержку в час, по каналу",
|
||
"description": "anon — обращения с экрана входа, без логина (типично «не могу войти»), web — уже залогиненные пользователи. Всплеск anon без роста web — обычно означает баг именно в форме/процессе входа, а не общий рост нагрузки на поддержку.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 17 },
|
||
"targets": [
|
||
{
|
||
"refId": "A",
|
||
"expr": "sum by (channel) (increase(mera_support_messages_total[1h]))",
|
||
"legendFormat": "{{channel}}"
|
||
}
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": [
|
||
{ "matcher": { "id": "byName", "options": "anon" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] }
|
||
]
|
||
}
|
||
},
|
||
|
||
{ "type": "row", "title": "Птица — экспорт отчётов", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 25 } },
|
||
|
||
{
|
||
"type": "timeseries",
|
||
"title": "Экспортов отчётов по участку в час, по формату",
|
||
"description": "Формат — то, что реально скачали: md/json/docx/pptx/pdf/tg-сводка §22-форсайта плюс best_layouts_pdf (ТЗ на проектирование). Провал всех форматов разом при живом трафике на дашборде «Приложения» значит, что сломан сам экспорт, а не рендер одного конкретного формата.",
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 26 },
|
||
"targets": [
|
||
{
|
||
"refId": "A",
|
||
"expr": "sum by (format) (increase(sitefinder_reports_exported_total[1h]))",
|
||
"legendFormat": "{{format}}"
|
||
}
|
||
],
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "short",
|
||
"min": 0,
|
||
"custom": { "fillOpacity": 8, "stacking": { "mode": "none" }, "showPoints": "never", "lineWidth": 2 }
|
||
},
|
||
"overrides": []
|
||
}
|
||
}
|
||
]
|
||
}
|