05. Observability-стек локально
Как работать с Prometheus / Grafana / Loki / Tempo в локальном docker-
compose: куда заходить, какие базовые запросы, как связать три
сигнала. Reference по инструментации — в
../conventions/observability.
Полный debugging flow production-инцидента — там же в разделе
«Debugging production issue».
Содержание
- Доступ
- Grafana
- Prometheus
- Loki
- Tempo
- Связка трёх сигналов
- Типовые сценарии
- pprof
- Troubleshooting самого стека
- См. также
Доступ
Все компоненты поднимаются docker compose up в сервис-репо
(см. 03-local-stack):
| Компонент | URL | Login |
|---|---|---|
| Grafana | http://localhost:3000 | admin / admin (при первом входе смена) |
| Prometheus | http://localhost:9090 | — |
| Loki | http://localhost:3100 | — (через Grafana) |
| Tempo | http://localhost:3200 | — (через Grafana) |
| pprof (сервис) | http://localhost:<service-port>/debug/pprof/ | BasicAuth из .env |
Datasource’ы в Grafana уже настроены в compose-конфиге: Prometheus
как default, Loki и Tempo как дополнительные. Проверить — Grafana →
Connections → Data sources.
Grafana
Дашборды per-сервис
Открой Grafana → Dashboards. Там предзаливаются типовые dashboard’ы:
- HTTP API — RPS, latency p50/p95/p99, error rate per route.
- Kafka — lag, publish/consume rate, DLQ size.
- Runtime — goroutines, heap, GC, FD count.
- Outbox — unpublished rows, forwarder lag (если сервис использует outbox).
Если dashboard’а нет — создай через Import из infra-репо или
собери «с нуля» (Add new panel → выбираешь metric).
Explore
Compass icon слева → Explore. Это interactive query UI, быстрее
дашборда, когда копаешь конкретный запрос.
- Data source dropdown вверху — Prometheus / Loki / Tempo.
- Split view (кнопка справа) — два запроса рядом, например, logs + traces одного запроса.
Дата-пикер
Стандартно — Last 15m, Last 1h, Last 24h. Для инцидентов —
точные границы (Custom range → окно инцидента ±10 минут).
Prometheus
UI
http://localhost:9090 — graph, alerts, targets, rules.
- Status → Targets — все ли scrape-endpoint’ы отвечают зелёным?
Красный таргет = сервис не доступен /
/metricsне отвечает / wrong port. - Graph — вводишь PromQL, получаешь график + table.
- Alerts — какие alert-rule’ы сейчас
firingилиpending.
Базовые PromQL-запросы
Rate запросов за 5 минут:
rate(http_requests_total{service="review"}[5m])Error rate:
sum(rate(http_requests_total{service="review",code=~"5.."}[5m]))
/ sum(rate(http_requests_total{service="review"}[5m]))p99 latency:
histogram_quantile(0.99,
sum by (le, route) (
rate(http_request_duration_seconds_bucket{service="review"}[5m])
)
)Top-5 endpoint’ов по ошибкам:
topk(5,
sum by (route) (rate(http_requests_total{code=~"5.."}[5m]))
)Goroutines:
go_goroutines{service="review"}Kafka lag:
kafka_consumer_lag{service="notification"}Outbox:
outbox_unpublished_rows{service="review"}Подробнее — ../conventions/observability
и ../conventions/slo-and-budget.
Интерпретация графиков
- Плоский
0— метрика не экспонируется. Проверь/metricsвручную:curl http://localhost:<port>/metrics | grep <metric>. - Плоский
NaN— делитель нулевой. Обычно: error rate при 0 RPS. - Пилообразный график — counter пересобран (pod рестарт). Используй
rate, он сглаживает. - Лестница — точная фиксация между scrape-интервалами. Ничего
страшного,
rate[5m]размажет.
Loki
Loki — log aggregation, доступ через Grafana Explore → Loki datasource.
LogQL: основные запросы
Все логи сервиса:
{service="review"}Логи одного request’а по correlation:
{service="review"} | json | correlation_id="01HZ3G..."Только errors:
{service="review"} | json | level="error"Error с подстрокой в message:
{service="review"} |= "deadline" | json | level="error"Группировка ошибок за окно (top error-messages):
topk(10,
sum by (msg) (
count_over_time({service="review"} |= "ERROR" | json [5m])
)
)Grafana Explore → «Explain query» объясняет план выполнения и рекомендует индексы.
Особенности
- Поиск идёт по label’ам → всегда начинай с
{service="..."}. - Фильтр
|= "..."— поиск подстроки в теле. | json— парсит JSON-поля как структурные.- Ретенция — 7 дней локально.
Подробнее — ../how-to/read-logs.
Tempo
Tempo — distributed tracing, доступ через Grafana Explore → Tempo datasource.
Поиск trace
Варианты ввода:
-
TraceID — если знаешь, вводишь в «Trace ID» поле. Быстрее всего.
-
TraceQL — язык запросов:
{ resource.service.name = "review" && name = "POST /v1/reviews" }Найдёт trace’ы handler’а
POST /v1/reviews. -
Фильтры в UI — service name, span name, min duration — для случаев «покажи медленные запросы к review».
Чтение waterfall
Trace = дерево span’ов. В Grafana видишь:
- Horizontal bar — длительность span’а.
- Nested — parent/child span’ы (HTTP-handler → service → pgx → Kafka-publish).
- Logs (справа при клике на span) — span events,
errorесли был. - Node graph — топология сервисов, через какие прошёл запрос.
Типичный debugging: открыть trace проблемного запроса → найти самый длинный span → понять, где время проводится (SQL / внешний HTTP / Kafka).
Retention
Локально — 24 часа. В prod — зависит от Tempo-tier, обычно 7 дней.
Подробнее — ../how-to/read-traces.
Связка трёх сигналов
Через общий trace_id и correlation_id можно прыгать между
системами:
- Prometheus alert сработал → ссылка «runbook» в alert → соответствующий troubleshooting/runbook.
- Grafana Dashboard → аномалия на графике → клик на точку → «View logs in Loki» / «View traces in Tempo» (если включены derived links в datasource).
- Tempo trace → в span’е есть лог event → клик → Loki с тем же
trace_id. - Loki лог → содержит
trace_id→ клик в Grafana → Tempo.
Derived links настраиваются в Grafana → Connections → Data sources → Loki / Tempo → Derived fields / Trace to logs.
Типовые сценарии
«5xx на endpoint’е»
- Grafana → Review Dashboard → panel «Error rate by route»: где именно?
- Explore → Loki:
{service="review"} | json | level="error"за 15 минут до пика. - В логе находим
request_id,trace_id. - Explore → Tempo → вставить trace_id → waterfall. Какой span упал?
- Если SQL —
db-slow-query. Если внешний HTTP —retry-and-circuit-breaker. Если panic — smoke test и фикс.
«Latency выросла»
- Dashboard → panel p99 latency per route: какой route?
- Explore → Prometheus:
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket{route="/v1/reviews"}[5m])) - Tempo → выбрать медленный trace в окне.
- Какой span дольше обычного? (pgx / HTTP / Redis).
- Troubleshooting по конкретному span’у.
«Consumer лаг растёт»
- Dashboard → panel
kafka_consumer_lag→ какой topic/group. - Prometheus:
Упал до 0 — consumer стоит; колеблется — rebalance.
rate(messages_processed_total{group="notification-on-review"}[5m]) - Loki:
{service="notification"} | json | level="error"— что в логах? ../troubleshooting/kafka-consumer-stuckили../troubleshooting/kafka-rebalancing.
«Память растёт»
- Dashboard runtime → panel
heap_inuse+go_goroutines. - Если растёт — см.
../troubleshooting/memory-leak.
pprof
Локально pprof открыт без auth (за loopback):
# heap snapshot
go tool pprof -http=:8080 http://localhost:<port>/debug/pprof/heap
# goroutine текстом
curl -s 'http://localhost:<port>/debug/pprof/goroutine?debug=1' | less
# CPU profile (30 секунд сбора)
go tool pprof -http=:8081 http://localhost:<port>/debug/pprof/profile?seconds=30Подробнее — ../how-to/profile-service и
../troubleshooting/memory-leak.
Troubleshooting самого стека
Grafana показывает «no data»
- Сервис не экспортирует метрику:
curl http://localhost:<port>/metrics | grep <metric_name>. - Prometheus не скрейпит: Status → Targets → твой сервис «DOWN»?
- Неправильный PromQL: синтаксис, label’ы.
Tempo не показывает trace’ы
OTEL_EXPORTER_OTLP_ENDPOINTне указывает на Tempo:docker compose logs <service> | grep otel.- Tempo не поднялся:
docker compose ps tempo→ healthy? SampleRateв конфиге слишком маленький (1%): подними до 100% локально.
Loki не видит логи
- Сервис пишет в stdout? (Правильно.) JSON-format? (Правильно.)
- Promtail (log-shipper) работает?
docker compose ps promtail/docker compose logs promtail.
Графики «трудно читать» — нет цветов / делений
Grafana 10+ default-theme иногда кривой. Settings → Preferences → Theme
→ Dark / Light, Refresh dashboard.
См. также
../conventions/observability— три сигнала, correlation, OpenTelemetry setup.../conventions/slo-and-budget— как определять SLO и alert-rule’ы.../how-to/read-logs— LogQL шпаргалка.../how-to/read-traces— Tempo workflow.../how-to/profile-service— pprof guide.../how-to/add-metric-and-alert— как добавить новую метрику и alert.03-local-stack— как поднять стек локально.