Commit graph

1 commit

Author SHA1 Message Date
nns 824ef8279c feat(observability): Prometheus метрики /metrics + бизнес-счётчики (P1-17)
prometheus-net.AspNetCore@8.2.1 + EF Core DbCommandInterceptor.

Endpoint: GET /metrics (text exposition, без auth — типичная практика;
на prod закроем nginx allow private-network).

Стандартные метрики (через UseHttpMetrics):
- http_requests_received_total (code/method/controller/action)
- http_request_duration_seconds (histogram, p50/p95/p99 SLO)
- process_cpu_seconds_total / dotnet_total_memory_bytes / GC counters

Кастомные бизнес-метрики (AppMetrics):
- food_market_documents_posted_total{type} — все типы документов
- food_market_sales_posted_total — alias по retail-sale (явно в SLO)
- food_market_supplies_posted_total — alias по supply
- food_market_documents_error_total{type, reason} — ошибки проведения
  с разбивкой по причине (serialization=40001, insufficient_stock,
  number_conflict, validation, other)
- food_market_db_query_duration_seconds{kind} — гистограмма SQL через
  DbMetricsInterceptor (kind=query для SELECT, command для CUD)

Tenant-меток в кастомных метриках НЕТ сознательно: на multi-tenant хосте
раздуло бы cardinality. Per-org разрез — через /api/reports/*.

Counters добавлены в:
- SuppliesController.Post (success + serialization-error)
- RetailSalesController.Post (success)
- PosController.CreateAndPostSaleAsync (success + number_conflict)

docs/observability.md — scrape-конфиг prometheus.yml, образец Grafana
dashboard (4 ряда: Health/Business/Database/Runtime), prometheus rules
с alert'ами (HighErrorRate, DbSerializationContention, NoSalesIn30Min).

Тесты: 3 интеграционных (endpoint доступен и возвращает text/plain с
встроенными метриками; sales counter инкрементится после Post; db_query
гистограмма накапливается).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 12:20:01 +05:00