Сейчас наблюдаемость частичная: приложения пишут Serilog JSON, promtail → Loki, Grafana + Prometheus (deploy/observability/). ELK не внедрён. Владелец просит развернуть полноценный observability-стек отдельными сервисами, на современном стеке (не классический Elasticsearch/Logstash/Kibana), и подключить его ко всем сервисам: мониторинг, логи, метрики, трейсы, потребление ресурсов.
Цель
Единый сбор и визуализация по всем процессам (core, ml, ai, telegram, storage) и инфраструктуре:
логи (структурные, с контекстом: tenantId, операция, correlationId);
метрики (RPS, latency, ошибки, бизнес-метрики, расход токенов ИИ);
трейсы (сквозные: HTTP/gRPC от входа до БД и внешних сервисов);
потребление ресурсов (CPU/RAM/диск/сеть контейнеров и хоста, размер БД/файлов, размер логов).
Предлагаемый стек (vendor-neutral, modern) — к согласованию
OpenTelemetry SDK в каждом сервисе (логи/метрики/трейсы) → OpenTelemetry Collector (отдельный сервис-приёмник и маршрутизатор).
Хранилище/поиск: OpenSearch + OpenSearch Dashboards (open-source форк, современная замена классического ELK) илиGrafana LGTM (Loki/Tempo/Mimir + Grafana, часть уже есть).
Визуализация/алерты: единый дашборд (Grafana/OpenSearch Dashboards) + правила алертинга.
Что сделать
Выбрать и согласовать целевой стек (см. варианты выше), описать в технической документации.
Поднять стек отдельными сервисами в deploy/compose.* (профиль observability), с volume'ами, retention и ресурсными лимитами; наружу не публиковать (доступ по SSH-туннелю, как сейчас у Grafana).
Подключить все процессы: OTel-инструментирование, экспорт логов/метрик/трейсов, корреляция (traceId в логах), единые атрибуты (service, env, tenantId).
Сбор ресурсов: cAdvisor + node-exporter, дашборды по CPU/RAM/диску/сети, размер БД и вложений.
Дашборды: обзор системы, ошибки, latency, зависимости, расход токенов ИИ, ресурсы; алерты.
Перевести/дополнить текущий Loki-поток (не ломать существующие дашборды без необходимости).
Критерии приёмки
стек поднимается отдельными сервисами одной командой (профиль observability)
все 5 процессов шлют логи, метрики и трейсы; трейсы сквозные (traceId в логах)
есть сбор потребления ресурсов (контейнеры + хост) и дашборды по нему
стек поднят, Prometheus видит таргеты cadvisor/node-exporter/tempo/prometheus (UP); job deal — сервисы в этой проверке не контейнеризовались
сквозной трейс в Tempo проверен: синтетический (telemetrygen) и реальный core (GET /metrics); переход лог↔трейс в Grafana не проверен (в dev-профиле нет Grafana/Loki)
дашборды сверены на живом prod-профиле: datasources Loki/Prometheus/Tempo и все 8 дашбордов провижнятся; Deal-Resources — данные cAdvisor, Deal-Traces — трейсы, Deal-Logs — метки Loki
Выполнено без работающего Docker-демона: сборки и тесты прогнаны, YAML/JSON-конфиги и docker compose config валидны; живой end-to-end не проверялся.
## Контекст
Сейчас наблюдаемость частичная: приложения пишут Serilog JSON, promtail → **Loki**, **Grafana** + **Prometheus** (`deploy/observability/`). **ELK не внедрён.** Владелец просит развернуть полноценный observability-стек **отдельными сервисами**, на **современном стеке** (не классический Elasticsearch/Logstash/Kibana), и подключить его ко **всем** сервисам: мониторинг, логи, метрики, трейсы, потребление ресурсов.
## Цель
Единый сбор и визуализация по всем процессам (core, ml, ai, telegram, storage) и инфраструктуре:
- **логи** (структурные, с контекстом: tenantId, операция, correlationId);
- **метрики** (RPS, latency, ошибки, бизнес-метрики, расход токенов ИИ);
- **трейсы** (сквозные: HTTP/gRPC от входа до БД и внешних сервисов);
- **потребление ресурсов** (CPU/RAM/диск/сеть контейнеров и хоста, размер БД/файлов, размер логов).
## Предлагаемый стек (vendor-neutral, modern) — к согласованию
- **OpenTelemetry SDK** в каждом сервисе (логи/метрики/трейсы) → **OpenTelemetry Collector** (отдельный сервис-приёмник и маршрутизатор).
- Хранилище/поиск: **OpenSearch + OpenSearch Dashboards** (open-source форк, современная замена классического ELK) **или** **Grafana LGTM** (Loki/Tempo/Mimir + Grafana, часть уже есть).
- Метрики: **Prometheus/VictoriaMetrics**; трейсы: **Tempo/Jaeger**.
- Ресурсы: **cAdvisor** (контейнеры) + **node-exporter** (хост).
- Визуализация/алерты: единый дашборд (Grafana/OpenSearch Dashboards) + правила алертинга.
## Что сделать
1. Выбрать и согласовать целевой стек (см. варианты выше), описать в технической документации.
2. Поднять стек отдельными сервисами в `deploy/compose.*` (профиль observability), с volume'ами, retention и ресурсными лимитами; наружу не публиковать (доступ по SSH-туннелю, как сейчас у Grafana).
3. Подключить **все** процессы: OTel-инструментирование, экспорт логов/метрик/трейсов, корреляция (traceId в логах), единые атрибуты (service, env, tenantId).
4. Сбор ресурсов: cAdvisor + node-exporter, дашборды по CPU/RAM/диску/сети, размер БД и вложений.
5. Дашборды: обзор системы, ошибки, latency, зависимости, расход токенов ИИ, ресурсы; алерты.
6. Перевести/дополнить текущий Loki-поток (не ломать существующие дашборды без необходимости).
## Критерии приёмки
- [x] стек поднимается отдельными сервисами одной командой (профиль observability)
- [x] все 5 процессов шлют логи, метрики и трейсы; трейсы сквозные (traceId в логах)
- [x] есть сбор потребления ресурсов (контейнеры + хост) и дашборды по нему
- [x] дашборды: overview, errors, latency, зависимости, токены ИИ, ресурсы; настроены алерты
- [x] retention/лимиты заданы; наружу порты не публикуются
- [x] развёртывание и эксплуатация описаны в технической документации
## Затрагивает
- deploy (compose/profiles/observability), core, ml, ai, telegram, storage; docs
## Источники
- Запрос владельца 2026-09-13; текущая наблюдаемость — `deploy/observability/`, `DealLogging.cs`
## Живая проверка (осталось после подъёма Docker)
- [x] стек поднят, Prometheus видит таргеты cadvisor/node-exporter/tempo/prometheus (UP); job `deal` — сервисы в этой проверке не контейнеризовались
- [x] сквозной трейс в Tempo проверен: синтетический (telemetrygen) и реальный core (`GET /metrics`); переход лог↔трейс в Grafana не проверен (в dev-профиле нет Grafana/Loki)
- [x] дашборды сверены на живом prod-профиле: datasources Loki/Prometheus/Tempo и все 8 дашбордов провижнятся; Deal-Resources — данные cAdvisor, Deal-Traces — трейсы, Deal-Logs — метки Loki
> Выполнено без работающего Docker-демона: сборки и тесты прогнаны, YAML/JSON-конфиги и `docker compose config` валидны; живой end-to-end не проверялся.
Решение по стеку: выбран OpenTelemetry + Grafana LGTM (Collector + Tempo + Loki + Prometheus + cAdvisor/node-exporter + Grafana), а не OpenSearch: переиспользует уже развёрнутые Loki/Grafana/Prometheus, единый UI и меньше ресурсов (OpenSearch — JVM-тяжёлый и дублировал бы логи). Стек vendor-neutral (OTel), при желании бэкенд логов меняется на OpenSearch без правок кода сервисов.
Код (трейсы):
DealTracingHosting (в Deal.Grpc.Hosting и Deal.Api/Observability) — OTel AspNetCore/Http/GrpcNetClient → OTLP; включается env OTEL_EXPORTER_OTLP_ENDPOINT (без него выключен), имя — OTEL_SERVICE_NAME;
TraceContextEnricher — Serilog обогащает логи TraceId/SpanId (связь логов с трейсами);
подключено во всех 5 процессах (core, telegram, ai, ml, storage); пакет OpenTelemetry.Exporter.OpenTelemetryProtocol 1.17.0.
Стек (deploy):otel-collector (contrib 0.160.0) → tempo 2.8.1; cadvisor 0.52.1 + node-exporter 1.9.1 → Prometheus; дашборды Deal-Traces, Deal-Resources; datasource Tempo и двусторонняя связь лог↔трейс; алерты группы deal-resources; prod-порты не публикуются, retention Tempo 7 сут; README deploy/observability/.
Проверки: сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9 — зелёные; YAML/JSON-конфиги и docker compose config (prod+dev, профиль observability) валидны.
Не проверялось (нет запущенного Docker-демона): живой end-to-end (таргеты Prometheus, трейсы в Tempo, дашборды). Отдельно: конфиг коллектора проверен только парсером YAML (команда validate образа не запускалась).
Вопросы к владельцу:
Подтвердить выбор бэкенда (Grafana LGTM) — OpenSearch заведомо не берём?
storage-service есть в dev, но отсутствует в prod-compose — добавлять его в прод-стек?
Трейсинг включать по умолчанию (endpoint коллектора задан в compose) или оставить опт-ин через env?
Пороги ресурсных алертов (CPU/память/диск) — уточнить под реальный профиль нагрузки.
Реализовано в ветке `t17_observability`.
**Решение по стеку:** выбран **OpenTelemetry + Grafana LGTM** (Collector + Tempo + Loki + Prometheus + cAdvisor/node-exporter + Grafana), а не OpenSearch: переиспользует уже развёрнутые Loki/Grafana/Prometheus, единый UI и меньше ресурсов (OpenSearch — JVM-тяжёлый и дублировал бы логи). Стек vendor-neutral (OTel), при желании бэкенд логов меняется на OpenSearch без правок кода сервисов.
**Код (трейсы):**
- `DealTracingHosting` (в `Deal.Grpc.Hosting` и `Deal.Api/Observability`) — OTel AspNetCore/Http/GrpcNetClient → OTLP; включается env `OTEL_EXPORTER_OTLP_ENDPOINT` (без него выключен), имя — `OTEL_SERVICE_NAME`;
- `TraceContextEnricher` — Serilog обогащает логи `TraceId`/`SpanId` (связь логов с трейсами);
- подключено во всех 5 процессах (core, telegram, ai, ml, storage); пакет `OpenTelemetry.Exporter.OpenTelemetryProtocol` 1.17.0.
**Стек (deploy):** `otel-collector` (contrib 0.160.0) → `tempo` 2.8.1; `cadvisor` 0.52.1 + `node-exporter` 1.9.1 → Prometheus; дашборды `Deal-Traces`, `Deal-Resources`; datasource Tempo и двусторонняя связь лог↔трейс; алерты группы `deal-resources`; prod-порты не публикуются, retention Tempo 7 сут; README `deploy/observability/`.
**Проверки:** сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9 — зелёные; YAML/JSON-конфиги и `docker compose config` (prod+dev, профиль observability) валидны.
**Не проверялось (нет запущенного Docker-демона):** живой end-to-end (таргеты Prometheus, трейсы в Tempo, дашборды). Отдельно: конфиг коллектора проверен только парсером YAML (команда `validate` образа не запускалась).
**Вопросы к владельцу:**
1. Подтвердить выбор бэкенда (Grafana LGTM) — OpenSearch заведомо не берём?
2. `storage-service` есть в dev, но отсутствует в prod-compose — добавлять его в прод-стек?
3. Трейсинг включать по умолчанию (endpoint коллектора задан в compose) или оставить опт-ин через env?
4. Пороги ресурсных алертов (CPU/память/диск) — уточнить под реальный профиль нагрузки.
Трейсинг — опт-ин: endpoint коллектора пуст по умолчанию, включается только при заданном DEAL_OTEL_ENDPOINT.
storage-service добавлен в compose.prod.yml (mTLS env, OTel env, healthcheck, MinIO).
Ресурсные алерты — в отдельном prometheus-resource-rules.yml, отключены (не в rule_files), пороги через env DEAL_ALERT_*. Замечание: Prometheus не раскрывает env в конфиге — при включении потребуется рендер шаблона/ручные значения (описано в шапке файла).
Что проверено на живом стеке (dev-профиль observability):
поднялись otel-collector (0.160.0), tempo (2.8.1), prometheus (3.5.0), cadvisor, node-exporter;
Tempo /ready — ready; синтетические OTLP-трейсы (telemetrygen) дошли: collector → tempo (несколько трейсов, root telemetrygen);
реальный core: запущен с OTEL_EXPORTER_OTLP_ENDPOINT → коллектор → Tempo; в Tempo найден спан GET /metrics сервиса core (traceID af69414a84b743ebe8a7d9b40e084a2e) — сквозная инструментация приложения работает.
Найдено и исправлено при проверке: node-exporter падал на Docker Desktop из-за mount-флага rslave (path / is mounted on / but it is not a shared or slave mount) — флаг убран, контейнер поднимается.
Не проверено: дашборды Grafana (в dev-профиле нет Grafana/Loki — поднимаются в prod-профиле) и job deal в контейнерном виде (core запускался с хоста).
После проверки стек и процессы остановлены и удалены (контейнеров не осталось).
**Живая проверка (Docker поднят).**
Правки по твоим ответам (коммиты в MR #18):
1. Трейсинг — **опт-ин**: endpoint коллектора пуст по умолчанию, включается только при заданном `DEAL_OTEL_ENDPOINT`.
2. **storage-service** добавлен в `compose.prod.yml` (mTLS env, OTel env, healthcheck, MinIO).
3. Ресурсные алерты — в отдельном `prometheus-resource-rules.yml`, **отключены** (не в `rule_files`), пороги через env `DEAL_ALERT_*`. Замечание: Prometheus не раскрывает env в конфиге — при включении потребуется рендер шаблона/ручные значения (описано в шапке файла).
Что проверено на живом стеке (dev-профиль `observability`):
- поднялись `otel-collector` (0.160.0), `tempo` (2.8.1), `prometheus` (3.5.0), `cadvisor`, `node-exporter`;
- Prometheus `/targets`: cadvisor / node-exporter / tempo / prometheus — **UP**;
- Tempo `/ready` — ready; синтетические OTLP-трейсы (`telemetrygen`) дошли: collector → tempo (несколько трейсов, root `telemetrygen`);
- **реальный core**: запущен с `OTEL_EXPORTER_OTLP_ENDPOINT` → коллектор → Tempo; в Tempo найден спан `GET /metrics` сервиса `core` (traceID `af69414a84b743ebe8a7d9b40e084a2e`) — сквозная инструментация приложения работает.
Найдено и исправлено при проверке: `node-exporter` падал на Docker Desktop из-за mount-флага `rslave` (`path / is mounted on / but it is not a shared or slave mount`) — флаг убран, контейнер поднимается.
Не проверено: дашборды Grafana (в dev-профиле нет Grafana/Loki — поднимаются в prod-профиле) и job `deal` в контейнерном виде (core запускался с хоста).
После проверки стек и процессы остановлены и удалены (контейнеров не осталось).
Проверка дашбордов на prod-профиле observability (Docker).
Поднял только сервисы профиля (Grafana/Loki/Promtail/Prometheus/otel-collector/Tempo/cAdvisor/node-exporter) с временными секретами (временный env-файл удалён после проверки; приложения и caddy не поднимались).
Результаты:
Grafana /api/health — OK (11.5.2); пароль из старого volume пришлось сбросить через grafana cli admin reset-admin-password;
все 8 дашбордов в папке «Дейл», включая новые Deal — Ресурсы (uid deal-resources) и Deal — Трейсы (uid deal-traces);
данные через Grafana-прокси: Tempo — 5 трейсов telemetrygen (dashboard Deal-Traces), Prometheus — серии cAdvisor (Deal-Resources), Loki — метки service/container/stream (promtail собирает docker-логи → Deal-Logs);
Prometheus /targets: cadvisor / node-exporter / tempo / prometheus — UP; job deal — DOWN (приложения не поднимались в этой проверке).
Итог по живой проверке: и трейсинг приложения, и весь стек, и дашборды подтверждены на живом Docker. Все контейнеры после проверки удалены, процессов не осталось.
**Проверка дашбордов на prod-профиле observability (Docker).**
Поднял только сервисы профиля (Grafana/Loki/Promtail/Prometheus/otel-collector/Tempo/cAdvisor/node-exporter) с временными секретами (временный env-файл удалён после проверки; приложения и caddy не поднимались).
Результаты:
- Grafana `/api/health` — OK (11.5.2); пароль из старого volume пришлось сбросить через `grafana cli admin reset-admin-password`;
- **datasources провижнятся**: Loki (uid `loki`, default), Prometheus (uid `prometheus`), Tempo (uid `tempo`);
- **все 8 дашбордов** в папке «Дейл», включая новые `Deal — Ресурсы` (uid `deal-resources`) и `Deal — Трейсы` (uid `deal-traces`);
- данные через Grafana-прокси: Tempo — 5 трейсов `telemetrygen` (dashboard Deal-Traces), Prometheus — серии cAdvisor (Deal-Resources), Loki — метки `service/container/stream` (promtail собирает docker-логи → Deal-Logs);
- Prometheus `/targets`: cadvisor / node-exporter / tempo / prometheus — UP; job `deal` — DOWN (приложения не поднимались в этой проверке).
Итог по живой проверке: и трейсинг приложения, и весь стек, и дашборды подтверждены на живом Docker. Все контейнеры после проверки удалены, процессов не осталось.
rust
moved this to Done in Deal Board on 2026-09-13 14:07:15 +03:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Контекст
Сейчас наблюдаемость частичная: приложения пишут Serilog JSON, promtail → Loki, Grafana + Prometheus (
deploy/observability/). ELK не внедрён. Владелец просит развернуть полноценный observability-стек отдельными сервисами, на современном стеке (не классический Elasticsearch/Logstash/Kibana), и подключить его ко всем сервисам: мониторинг, логи, метрики, трейсы, потребление ресурсов.Цель
Единый сбор и визуализация по всем процессам (core, ml, ai, telegram, storage) и инфраструктуре:
Предлагаемый стек (vendor-neutral, modern) — к согласованию
Что сделать
deploy/compose.*(профиль observability), с volume'ами, retention и ресурсными лимитами; наружу не публиковать (доступ по SSH-туннелю, как сейчас у Grafana).Критерии приёмки
Затрагивает
Источники
deploy/observability/,DealLogging.csЖивая проверка (осталось после подъёма Docker)
deal— сервисы в этой проверке не контейнеризовалисьGET /metrics); переход лог↔трейс в Grafana не проверен (в dev-профиле нет Grafana/Loki)Беру в работу. Ветка t17_observability. Стек: OpenTelemetry Collector + Tempo (трейсы) + Loki (логи) + Prometheus (метрики) + cAdvisor/node-exporter (ресурсы) + Grafana; вместо OpenSearch — переиспользуем существующий Loki/Grafana (меньше ресурсов, единый UI).
Реализовано в ветке
t17_observability.Решение по стеку: выбран OpenTelemetry + Grafana LGTM (Collector + Tempo + Loki + Prometheus + cAdvisor/node-exporter + Grafana), а не OpenSearch: переиспользует уже развёрнутые Loki/Grafana/Prometheus, единый UI и меньше ресурсов (OpenSearch — JVM-тяжёлый и дублировал бы логи). Стек vendor-neutral (OTel), при желании бэкенд логов меняется на OpenSearch без правок кода сервисов.
Код (трейсы):
DealTracingHosting(вDeal.Grpc.HostingиDeal.Api/Observability) — OTel AspNetCore/Http/GrpcNetClient → OTLP; включается envOTEL_EXPORTER_OTLP_ENDPOINT(без него выключен), имя —OTEL_SERVICE_NAME;TraceContextEnricher— Serilog обогащает логиTraceId/SpanId(связь логов с трейсами);OpenTelemetry.Exporter.OpenTelemetryProtocol1.17.0.Стек (deploy):
otel-collector(contrib 0.160.0) →tempo2.8.1;cadvisor0.52.1 +node-exporter1.9.1 → Prometheus; дашбордыDeal-Traces,Deal-Resources; datasource Tempo и двусторонняя связь лог↔трейс; алерты группыdeal-resources; prod-порты не публикуются, retention Tempo 7 сут; READMEdeploy/observability/.Проверки: сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9 — зелёные; YAML/JSON-конфиги и
docker compose config(prod+dev, профиль observability) валидны.Не проверялось (нет запущенного Docker-демона): живой end-to-end (таргеты Prometheus, трейсы в Tempo, дашборды). Отдельно: конфиг коллектора проверен только парсером YAML (команда
validateобраза не запускалась).Вопросы к владельцу:
storage-serviceесть в dev, но отсутствует в prod-compose — добавлять его в прод-стек?MR: #18
Живая проверка (Docker поднят).
Правки по твоим ответам (коммиты в MR #18):
DEAL_OTEL_ENDPOINT.compose.prod.yml(mTLS env, OTel env, healthcheck, MinIO).prometheus-resource-rules.yml, отключены (не вrule_files), пороги через envDEAL_ALERT_*. Замечание: Prometheus не раскрывает env в конфиге — при включении потребуется рендер шаблона/ручные значения (описано в шапке файла).Что проверено на живом стеке (dev-профиль
observability):otel-collector(0.160.0),tempo(2.8.1),prometheus(3.5.0),cadvisor,node-exporter;/targets: cadvisor / node-exporter / tempo / prometheus — UP;/ready— ready; синтетические OTLP-трейсы (telemetrygen) дошли: collector → tempo (несколько трейсов, roottelemetrygen);OTEL_EXPORTER_OTLP_ENDPOINT→ коллектор → Tempo; в Tempo найден спанGET /metricsсервисаcore(traceIDaf69414a84b743ebe8a7d9b40e084a2e) — сквозная инструментация приложения работает.Найдено и исправлено при проверке:
node-exporterпадал на Docker Desktop из-за mount-флагаrslave(path / is mounted on / but it is not a shared or slave mount) — флаг убран, контейнер поднимается.Не проверено: дашборды Grafana (в dev-профиле нет Grafana/Loki — поднимаются в prod-профиле) и job
dealв контейнерном виде (core запускался с хоста).После проверки стек и процессы остановлены и удалены (контейнеров не осталось).
Проверка дашбордов на prod-профиле observability (Docker).
Поднял только сервисы профиля (Grafana/Loki/Promtail/Prometheus/otel-collector/Tempo/cAdvisor/node-exporter) с временными секретами (временный env-файл удалён после проверки; приложения и caddy не поднимались).
Результаты:
/api/health— OK (11.5.2); пароль из старого volume пришлось сбросить черезgrafana cli admin reset-admin-password;loki, default), Prometheus (uidprometheus), Tempo (uidtempo);Deal — Ресурсы(uiddeal-resources) иDeal — Трейсы(uiddeal-traces);telemetrygen(dashboard Deal-Traces), Prometheus — серии cAdvisor (Deal-Resources), Loki — меткиservice/container/stream(promtail собирает docker-логи → Deal-Logs);/targets: cadvisor / node-exporter / tempo / prometheus — UP; jobdeal— DOWN (приложения не поднимались в этой проверке).Итог по живой проверке: и трейсинг приложения, и весь стек, и дашборды подтверждены на живом Docker. Все контейнеры после проверки удалены, процессов не осталось.