Перейти к основному содержимому

Наблюдаемость

Три опоры: структурные логи с сквозным идентификатором, метрики Prometheus и журнал аудита. Решения — ADR-0010, ADR-0011, ADR-0012, ADR-0013.

Структурные логи и correlation-id​

  • StructuredLoggerService (core/observability) пишет одну JSON-строку на событие в stdout и подключён глобально; уровень задаёт LOG_LEVEL (error|warn|log|debug|verbose), по умолчанию — по NODE_ENV.
  • Correlation-id живёт в AsyncLocalStorage (correlation.store.ts). traceIdMiddleware берёт входящий X-Request-Id (допустимы [A-Za-z0-9._-]{1,128}) либо генерирует UUID и возвращает его в заголовке ответа; id автоматически попадает во все логи запроса.
  • Воркеры исполняют каждую джобу в собственном контексте (correlation.run('job-<очередь>-<id>', …)), поэтому логи фоновых задач и cron-тиков трассируются так же, как HTTP.
  • LoggingInterceptor пишет access-лог каждого HTTP-запроса.
  • Маскирование секретов (redact.ts): значения ключей password, token, secret, authorization, cookie, apiKey и подобных заменяются (регистр и разделители не важны). Контент промптов и ответов LLM в логи не попадает.
  • События сообщений следуют конвенции домен.событие key=value, например rnp.recompute.enqueued account=… days=…, repricer.schedules.registered count=….

Метрики Prometheus​

Эндпоинт GET /metrics (core/metrics, @willsoto/nestjs-prometheus):

МетрикаТипЧто показывает
optima_http_request_duration_secondshistogramдлительность HTTP по method, route (шаблон маршрута), status_code
optima_queue_jobsgaugeчисло джоб очереди по состояниям (queue, state)
optima_queue_job_duration_msgaugeперцентили длительности последних завершённых джоб очереди
optima_db_pool_connectionsgaugeсоединения пула PostgreSQL по состояниям
optima_reaggregate_jobs_total, optima_reaggregate_duration_mscounter / histogramпересчёт дневных агрегатов по domain
optima_rnp_sync_runs_total, optima_rnp_sync_rows_totalcounterпрогоны и строки синков РНП (sync = ads/sections/finance/merge)
optima_catalog_sync_runs_total, optima_catalog_sync_rows_totalcounterсинхронизация каталога
optima_digitization_feed_sync_*counter / histogramсинк фидов оцифровки по ярусам (tier)

Плюс стандартные процессные метрики prom-client (в тестах отключены). Метки не содержат идентификаторов пользователей. В production /metrics закрыт HTTP Basic (METRICS_USER + METRICS_PASSWORD); без этих переменных эндпоинт отдаёт 404 — Prometheus настраивается на basic-auth в scrape-конфиге.

Наблюдаемость очередей​

  • QueueDiscoveryService автоматически находит все очереди BullMQ, зарегистрированные через BullModule.registerQueue (перечень — Фоновые задачи).
  • Bull Board — /admin/queues: просмотр, повтор и удаление джоб. Dev — открыт; в production — HTTP Basic при заданных QUEUE_BOARD_USER и QUEUE_BOARD_PASSWORD, иначе не монтируется (в лог пишется предупреждение).
  • Неудачные джобы не удаляются (removeOnFail: false), успешные хранятся 24 часа или до 1000 штук.

Health-проверки​

ЭндпоинтНазначение
GET /healthreadiness: проверка PostgreSQL и Redis; в production — только { status, timestamp }, детали уходят в лог
GET /health/liveliveness процесса
GET /versionверсия приложения и git-SHA сборки (GIT_SHA)

Журнал аудита​

Модуль modules/audit-log (таблица audit_logs, записи иммутабельны):

  • поля: тип и id актора (user, system, agent), action, entityType/entityId, outcome (success|failure), before/after/metadata (JSONB), correlationId — по нему запись связывается с логами;
  • два пути фиксации: декоратор @Audit({ action, entityType }) с AuditInterceptor и явный AuditService.record(); секреты маскируются, а сбой аудита не ломает бизнес-операцию;
  • пишут аудит: аутентификация (вход, блокировки, reuse refresh, отзыв сессий), кабинеты WB, цены и репрайсер, автобиддер, автоответы, бухгалтерия, A/B-тесты, действия ИИ-агента (ai-agent.action.*);
  • чтение — GET /audit-logs, только роль admin, с фильтрами и пагинацией; в интерфейсе — «Администрирование → Журнал аудита» (описание).

Практики безопасности, связанные с логами и метриками, — Безопасность.