AACsearch
Эксплуатация

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

Request ID, структурированные логи, события аналитики и корреляция с вашим error tracker-ом.

Observability

Мониторинг — четыре сигнала, на которые смотреть. Observability — подповерхностное: request id через границы систем, конвенции логирования, таксономия событий, как пазлы стыкуются.

Эта страница нужна, если AACsearch встраивается в более крупную систему с собственным request-tracing, error-tracking и event-пайплайнами.

Request ID

Каждому запросу к публичному API ставится x-request-id в ответ. Значение также пишется:

  • В строку audit log (в details.requestId, где применимо).
  • В структурированные серверные логи (middleware requestContext выставляет requestId, orgId, indexId).
  • В записи доставки webhook-ов.
  • В breadcrumbs Sentry (когда Sentry включён у нас).

Пропагируйте этот ID через свои системы. Снимайте из заголовка ответа, пишите в логи приложения, кладите в extra своего error-tracker-а. При эскалации саппорту это значение моментально склеивает ваши логи с нашими.

Можно прислать свой request id — задать x-request-id на запросе. Используем ваш, если непустой и ≤ 128 символов; в ответе увидите то же значение. Самый простой способ протащить один id через мульти-сервисный запрос.

Конвенции логирования

pino для структурного логирования на сервере, через @repo/logs. У каждой строки минимум:

ПолеЗначение
leveltrace / debug / info / warn / error / fatal
timeUnix ms.
requestIdЕсли вызов в контексте запроса.
orgIdВерифицированная организация (после auth-gate).
indexIdГде применимо.
msgКороткий, парсимый summary.

В трейсе плюс err.name, err.message, sampled err.stack. Тела запросов по умолчанию не логируем — это утечка payload документов.

При self-hosted (когда станет доступен — см. Dedicated cluster) — те же конвенции. Уровень — env LOG_LEVEL, дефолт info.

Таксономия событий аналитики

AACsearch пишет аналитические события — полезны и продукту, и эксплуатации.

СобытиеКогдаЗаметные свойства
search.executedКаждый успешный публичный поиск.indexId, query, hits, latencyMs
search.zero_results0 хитов.indexId, query
search.result_clickedClick-through через events endpoint.indexId, documentId, position
search.rate_limitedОтказ на rate-limit-gate.keyId, limit
ingest.bulk_upsertУспешный flush буфера для батча.indexId, count
ingest.bulk_upsert_failedПадение flush буфера для батча.indexId, count, errorClass
index.reindex_startedСтарт реиндекса.indexId, fromVersion, toVersion
index.reindex_completedРеиндекс успешен; алиас переключён.indexId, toVersion, durationMs
index.reindex_failedРеиндекс прерван.indexId, toVersion, errorClass
webhook.delivery_failedWebhook вернул non-2xx.endpoint, attempt, statusCode

Доступ — searchAnalytics.list (данные дашборда), searchAnalytics.export (NDJSON). Retention: 30 дней для высокообъёмных, 365 для index.*.

Для продуктовой аналитики разведён PostHog на события дашборда. Свой ключ PostHog ставьте в приложении; дашборд AACsearch ходит в наш — потоки не смешиваются.

Корреляция с Sentry

Если у вас Sentry, рекомендуем:

import * as Sentry from "@sentry/nextjs";

try {
	const res = await fetch(url, { headers });
	if (!res.ok) {
		const requestId = res.headers.get("x-request-id");
		throw new Error(`search failed: ${res.status} (requestId=${requestId})`);
	}
} catch (err) {
	Sentry.captureException(err, {
		tags: { component: "aacsearch", requestId },
		extra: { url, status: res?.status },
	});
	throw err;
}

Тег requestId → поиск в Sentry по request id возвращает все события вашей стороны по этому запросу. Когда форвардите ссылку саппорту, мы сопоставляем с нашим серверным логом по тому же id.

Ваш Sentry-поток мы не подсасываем. Корреляция — через общий request id, а не общую инфраструктуру.

Health-эндпоинты

EndpointAuthВозвращает
GET /api/v1/healthНет{ "status": "ok" } (200), когда API-gateway жив.
GET /api/v1/health/regionНетСнимок доступности кластеров по регионам.
GET /api/orpc/searchIndex.getHealthBearer (admin)drift / lag / error rate по индексу.

Не-аутентифицированные — rate-limit-exempt. Гоняйте их под probes; не аутентифицированные — съест rate-budget.

Webhook-доставка как observability

Если включены outbound webhook-и, дашборд доставки — сам observability-surface:

  • Последние 1 000 попыток на endpoint.
  • Перцентили latency.
  • Dead-letter (упало 24 часа retry).

Растущая очередь dead-letter — endpoint медленный или 5xx. Если webhook-и — для system-of-record, также опрашивайте те же данные раз в сутки. Webhook — best-effort с retry, не замена reconciliation-цикла.

Дашборды и алерты

Готовые Grafana/Datadog дашборды как self-serve мы пока не отдаём. Поддерживаемый путь:

  1. Воркер с вашей стороны опрашивает searchIndex.getHealth.
  2. Метрики в свой стек с консистентными тегами (orgId, indexId, region).
  3. Алерт по порогам из Мониторинга.

Reference-воркер по запросу — пишите на support@aacsearch.com, пришлём tarball.

Severity в вашем observability

Наша публичная severity-модель — Статус и инциденты. При сшивании алертов на своей стороне:

  • Будите человека (аналог P1) при aacsearch.index.docCountDrift > 0.05 стабильно 5 минут или aacsearch.index.ingestLagSeconds > 600 стабильно.
  • Откройте тикет (P2/P3) при errorRate > 0.01 стабильно или rate_limited > 0 стабильно.
  • Только лог (без будилки) при росте latencyMs p95 на статичную дельту — дисперсия там в основном про сеть.

Частые ошибки

  • Не пропагировать request id. Без него склейка ваших и наших логов в инцидент — дорогая (брутфорс по org id + минута).
  • Алерты на каждое событие. PostHog — для анализа, не для алертов. Алерты — на метрики; анализ — на события.
  • Webhook как observability. Webhook — нотификация, не источник истины. Retry — да, транзакционность — нет.

См. также

On this page