Наблюдаемость
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. У каждой строки минимум:
| Поле | Значение |
|---|---|
level | trace / debug / info / warn / error / fatal |
time | Unix 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_results | 0 хитов. | indexId, query |
search.result_clicked | Click-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_failed | Webhook вернул 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-эндпоинты
| Endpoint | Auth | Возвращает |
|---|---|---|
GET /api/v1/health | Нет | { "status": "ok" } (200), когда API-gateway жив. |
GET /api/v1/health/region | Нет | Снимок доступности кластеров по регионам. |
GET /api/orpc/searchIndex.getHealth | Bearer (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 мы пока не отдаём. Поддерживаемый путь:
- Воркер с вашей стороны опрашивает
searchIndex.getHealth. - Метрики в свой стек с консистентными тегами (
orgId,indexId,region). - Алерт по порогам из Мониторинга.
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стабильно. - Только лог (без будилки) при росте
latencyMsp95 на статичную дельту — дисперсия там в основном про сеть.
Частые ошибки
- Не пропагировать request id. Без него склейка ваших и наших логов в инцидент — дорогая (брутфорс по org id + минута).
- Алерты на каждое событие. PostHog — для анализа, не для алертов. Алерты — на метрики; анализ — на события.
- Webhook как observability. Webhook — нотификация, не источник истины. Retry — да, транзакционность — нет.
См. также
- Мониторинг — четыре сигнала
- Статус и инциденты — наша сторона
- Аудит — длинная история admin-действий
Мониторинг
Сигналы, на которые стоит смотреть при работе AACsearch в проде, и как завести их в свой observability.
Производительность, SLA, кэширование и масштабирование
Как AACsearch масштабируется, где находятся слои кэша, какой SLA по тарифам и какие рычаги доступны, если задержка или throughput становятся узким местом.