Наблюдаемость
NOTE
Статус: Mixed — структурное логирование (
platform/observability.StartPhase/LogEvent) и Prometheus stack (ADR-0048) уже live. Дашборды, алерты и SLO остаются target. Правила маркировки — в50-processes/documentation-standard.md.
Политика мониторинга, логирования и трейсинга.
Трейсинг
- OpenTelemetry SDK во всех сервисах.
- Exporter: OTLP gRPC → collector → Tempo/Jaeger.
- Каждый внешний запрос создаёт span.
correlation_idпропагируется во всех событиях и HTTP-вызовах.- Минимум tracing: вход HTTP → use case → external call → DB.
Метрики
- Prometheus-compatible endpoint
/metrics. - Префикс метрик по сервису (
ingestion_,matcher_, …). - Обязательные метрики для каждого сервиса:
- RED (requests, errors, duration).
- Кастомные (см. README сервиса).
Логирование
- Structured JSON, stdout.
- Обязательные поля:
ts,level,service,trace_id,msg. - Для фазовых операций используется единый контракт
platform/observability.StartPhase. Обязательные поля события:event,event_type,state,outcome,duration_ms,operation,component,layer,job_id. Для supplier ingestion дополнительно:supplier,phase,credential_ref, счётчики фазы (item_count,price_count,stock_count,warehouse_count) и безопасные параметры стратегии (batch_size,max_items). Credentials и raw URL с query/token в логи не пишутся. - Для одиночных событий вне границ фазы используется
LogEvent(ctx, log, "event.name", attrs...)— тот же набор correlation-полей (request_id/trace_id/span_id/operation/component/layer/job_id/message_id/parent_operation) подтягивается автоматически изplatform/errors.Snapshot(ctx). Имена событий — стабильные dot-separated строки (ingestion.bulk.checkpoint), не free-form, чтобы Loki/Vector могли фильтровать без зависимости от текста. - Для долгих внутренних циклов пишутся progress-события
event="ingestion.bulk.progress"с тем жеtrace_id:phase,warehouse_ref,page,page_count,rows_seen. Это позволяет отличить зависание от штатной долгой пагинации. - Для внешних HTTP-вызовов поставщиков пишутся
event="ingestion.http.request.start"/event="ingestion.http.request.end". В лог попадаютsupplier,phase, безопасныйpath,page,batch_size,status,duration_ms, но не query string, session id, accessCode, login, password или token. - Чувствительные данные (credentials, customer PII) — редактируются.
- Уровень логирования — через env var, по умолчанию
info.
Быстрая трассировка ingestion
- Найти тик поставщика:
docker logs tracium-supplier-sync-1 2>&1 \
| jq -c 'select(.event=="ingestion.tick" and .supplier=="etm")'-
Взять
trace_idизingestion.tick.end. -
Посмотреть все фазы того же тика:
docker logs tracium-supplier-sync-1 2>&1 \
| jq -c 'select(.trace_id=="<trace_id>")'- Найти ошибочные фазы по всем поставщикам:
docker logs tracium-supplier-sync-1 2>&1 \
| jq -c 'select(.event=="ingestion.bulk.phase" and .state=="completed" and .outcome!="success")'- Посмотреть прогресс длинной фазы:
docker logs tracium-supplier-sync-1 2>&1 \
| jq -c 'select(.event=="ingestion.bulk.progress" and .trace_id=="<trace_id>")'- Для one-shot логов из
.cache/live-runs/*.jsonlполучить компактную таблицу фаз:
jq -rc '
select(.event=="ingestion.bulk_snapshot.tick.summary"
or (.event=="ingestion.bulk.phase" and .state=="completed"))
| [.time,.supplier,(.phase//"summary"),.outcome,.duration_ms,
(.item_count//""),(.price_count//""),(.stock_count//""),(.stock_complete//"")]
| @tsv
' .cache/live-runs/<run>.jsonl- Найти медленные или ошибочные supplier HTTP-вызовы:
docker logs tracium-supplier-sync-1 2>&1 \
| jq -c 'select(.event=="ingestion.http.request.end" and (.outcome!="success" or .duration_ms>30000))'Алертинг
- Grafana / Alertmanager.
- Базовые алерты:
- error_rate > 1% за 5 min на любом сервисе.
- p95 latency > threshold на HTTP endpoint.
- Kafka consumer lag > threshold.
- ES cluster status != green.
- PG connection pool exhaustion.
- Бизнес-алерты:
- rate_limit_hits на поставщике > threshold.
- session_refresh_failed.
- async_job_timeout.
- moderation_queue_size > threshold.
Наблюдаемость по пайплайнам
Базовые метрики RED обязательны для всех сервисов. Ниже — обязательный минимум дополнительных метрик и алертов по критическим путям.
Ingestion pipeline
Метрики:
ingestion_payload_fetched_total{supplier_id, credential_id, endpoint}— успешные/ошибочные fetch.ingestion_payload_size_bytes{supplier_id}— гистограмма.ingestion_normalization_duration_seconds{supplier_id, stage}— стадии fetch → parse → normalize → emit.ingestion_backlog_size{supplier_id, stage}— кол-во SKU в очереди на каждой стадии.ingestion_observations_emitted_total{supplier_id, scope}— observations записанные вoffer.observation.v1.ingestion_lag_seconds{supplier_id}—now() - last_observed_atдля топ-SKU данного поставщика.etm_credential_usage_ratio{credential_id}— % использованного rate budget (см.etm/rate-budget.md).
Алерты:
ingestion_lag_seconds{supplier_id} > 12 * 3600(12h) для топ-SKU.ingestion_backlog_size > 10 000для одного поставщика > 1 час.etm_credential_usage_ratio > 0.85за час.kafka_consumer_lag{group="normalizer"} > 10 0005 мин.session_refresh_failed_total > 3за 10 мин на одной credential.
Matching pipeline
Метрики:
matching_decisions_total{confidence}— exact / strong / probable / weak / unmatched.matching_decision_duration_seconds{strategy}— deterministic / heuristic / ml.matching_backlog_size— offers в очереди на матчинг.matching_orphan_pool_size— текущий размер orphan pool.matching_rematch_runs_total{trigger}— periodic / profile_changed / new_canonical.
Алерты:
matching_backlog_size > 5 000> 30 мин.matching_orphan_pool_size growth > 1000/day(рост быстрее ожидаемого).- Доля
weak/unmatched> 30% от decided/час — деградация качества.
Enrichment pipeline
Метрики:
enrichment_jobs_queued_total{type}/enrichment_jobs_completed_total{type, status}/enrichment_jobs_failed_total{type, reason}.enrichment_jobs_in_flight{type}— gauge.enrichment_job_duration_seconds{type}— гистограмма по типу job (discovery/refresh_observation/refresh_characteristics/…).enrichment_jobs_dedup_hits_total— сколько подключилось к pending job’у.llm_calls_total{provider, model, intent}/llm_tokens_used_total{provider, direction}.
Алерты:
enrichment_jobs_in_flight > 1000> 15 мин.- p95 длительности конкретного типа job выше 2× baseline (например, refresh_observation > 60s).
enrichment_jobs_failed_total{reason="timeout"}> 1% за час.
Visibility policy
Метрики (см. также 30-services/visibility/README.md):
visibility_evaluations_total{target_kind}.visibility_evaluation_duration_seconds{target_kind}.visibility_compile_duration_seconds.visibility_cache_hits_total/visibility_cache_misses_total.visibility_filtered_total{effect}.visibility_policy_compile_errors_total.
Алерты:
visibility_cache_miss_rate > 0.5за 5 мин — проблема инвалидации.visibility_evaluation_duration_seconds p95 > 50ms— performance regression (см. бюджет вdata-visibility-policy.md).visibility_policy_compile_errors_total > 0— некорректная policy в admin UI.
Event sourcing / outbox
Метрики:
event_store_writes_total{aggregate_type, event_type}.outbox_unpublished_count— gauge.outbox_lag_seconds—now() - min(enqueued_at) WHERE published_at IS NULL.outbox_publish_attempts_total{outcome}.event_store_archiver_runs_total{outcome}.
Алерты:
outbox_unpublished_count > 10 000> 5 мин.outbox_lag_seconds p95 > 5> 5 мин.outbox_publish_attempts_total{outcome="failed", attempts=">=5"} > 0.
ClickHouse projection (см. ADR-0019)
Метрики:
ch_ingestion_lag_seconds{topic}— kafka offset → видно в SELECT.ch_ingestion_errors_total{topic}— попадания в_errorstable.ch_query_duration_seconds{query_class}.
Алерты:
ch_ingestion_lag_seconds p95 > 30за 10 мин.ch_ingestion_errors_total > 0за час.
Дашборды
На момент Phase 0 — базовые:
- Service RED по каждому сервису.
- Kafka topic lag по группам + outbox lag.
- Storage health: PG / ES / CH / Redis.
- Ingestion overview: по поставщикам / credentials — fetch rate, lag, ошибки, использование rate budget.
- Matching quality: распределение уровней confidence, backlog, размер orphan pool.
- Visibility engine: cache hit rate, latency, количество отфильтрованных записей.
- Enrichment jobs: in-flight, success rate, latency по типам.
SLO
| Объект | SLO | Окно | Error budget |
|---|---|---|---|
GET /v1/products/{id} p95 latency | < 300 мс | 30 дней | 0.1% |
POST /v1/pricing p95 latency | < 300 мс | 30 дней | 0.1% |
POST /v1/estimates p95 latency (≤ 200 строк) | < 10 с | 30 дней | 0.5% |
| Доступность публичного API | ≥ 99.9% | 30 дней | 43 мин |
| Outbox publish lag p95 | < 1 с | 7 дней | — |
| Visibility evaluation overhead p95 | < 50 мс | 7 дней | — |
| Ingestion freshness (топ-SKU цена) | ≤ 6 ч | 7 дней | 1% SKU |
| Ingestion freshness (топ-SKU остаток) | ≤ 2 ч | 7 дней | 1% SKU |
Политика error budget: при пробое — заморозка фич, фокус на восстановлении. Эскалация в oncall.