Состояние и журналы

> Кратко. Живость API показывает /health: базы городов, Redis и схема баз в одном ответе. Код ответа всегда 200, поэтому смотреть надо на поле status. Подробности пишутся в журнал каждого процесса API и в журналы служб. Кто что делал — в журнале действий.

Читаю как

Адреса проверки

Адрес Вход Что показывает
GET /health, /api/health не нужен status (ok / degraded), база, Redis, схема базы, число маршрутов, флаги сервера
GET /city/<код>/health не нужен То же по одному городу (API на несколько городов)
GET /api/v1/auth/config не нужен Флаги входа и записи, город, включён ли ИИ
GET /metrics токен METRICS_TOKEN Метрики Prometheus. Без METRICS_TOKEN — 404
GET /api/v1/ai/status любой вход Включён ли помощник, модель, причина, если выключен
GET /api/v1/water/status любой вход Отвечает ли движок водопровода, версия WNTR
martin GET /health на 127.0.0.1 Живость martin
движок водопровода GET /health на 127.0.0.1 Версия WNTR

Ответ /health

{
  "status": "ok",
  "database": {"ok": true, "latency_ms": 15.0, "error": null},
  "redis": {"ok": true, "latency_ms": 0.0, "error": null, "note": null},
  "city_schema": {"status": "ok", "checked_at": "…", "missing": [], "applied": [], "error": null, "recreated": 0},
  "routes": 517,
  "russian_names_initialized": true,
  "flags": {"auth_disabled": false, "dev_login_enabled": false, "strict_auth": true,
            "mutations_enabled": true, "topology_mutations_enabled": true}
}

Пример — стенд документации на копии Алматы; флаги показаны как на сервере с включённым входом.

  • status — degraded, если не отвечает база любого города, Redis или доводка схемы базы закончилась ошибкой (city_schema.status = "error"). HTTP-код при этом остаётся 200. Внешний сторож и скрипты выкатки должны проверять поле status, а не только код.
  • Без префикса города в режиме нескольких городов database.cities и city_schema.cities показывают каждый город отдельно.
  • city_schema.recreated — сколько раз с запуска процесса база была пересоздана десктопом (переконвертация).
  • routes — число маршрутов. Меньше 80 — веб показывает «На сервере устаревший API».
  • /health открыт без входа. В ответ попадают тексты ошибок подключения к базе и Redis, а в них бывает имя или адрес сервера. Наружу через nginx его лучше не публиковать.

Метрики Prometheus

/metrics с заголовком Authorization: Bearer <METRICS_TOKEN>:

Метрика Что
tgid_http_requests_total{method,route,status} Запросы по шаблону маршрута и коду
tgid_http_request_duration_seconds{method,route} Время ответа
tgid_db_pool_connections{city,state} Соединения пула базы города
tgid_city_schema_ok{city,status}, tgid_city_schema_missing{city} Схема базы на месте; сколько пунктов недостаёт
tgid_city_db_recreated{city} Переконвертации базы с запуска процесса
tgid_celery_queue_up, tgid_celery_queue_length Доступна ли очередь; сколько задач ждут воркера (сумма очередей городов)
tgid_info{city,database} Город и база процесса

Для нескольких процессов uvicorn задайте PROMETHEUS_MULTIPROC_DIR — общий каталог, очищаемый перед стартом службы. Без него каждый процесс отдаёт только свои счётчики. Нет пакета prometheus-client — API работает, а /metrics выключен; в журнале предупреждение «Метрики /metrics выключены».

Журналы

Журнал Где Что в нём Ротация
Журнал процесса API logs/app.log в каталоге API; второй процесс из того же каталога — app-2.log и так далее Всё с уровня DEBUG: ошибки маршрутов, доводка схемы, вебхуки, сторож цикла. В строке — номер процесса 1 МБ × 5 файлов
Вывод службы API <logs>\<служба>.out.log / .err.log Строки доступа uvicorn (метод, полный адрес с параметрами, код), ошибки запуска, трассировки NSSM, по 10 МБ
Вывод воркера <logs>\tgid-worker-…err.log Ход задач Celery, ошибки расчётов NSSM, по 10 МБ
Протокол расчёта база города, calculation_protocol Сообщения движка; окно «Протокол» CALC_PROTOCOL_KEEP_DAYS (365 дней)
Журнал действий UsersDB, activity_log Кто, когда, что, откуда, с каким итогом ACTIVITY_LOG_DAYS (730 дней)
История правок база города, audit_log Что именно изменилось в данных —

Журналы служб на Windows пишутся в кодировке консоли (cp1251). Их читают, например, через iconv -f cp1251.

Строки доступа uvicorn содержат адрес запроса с параметрами. Значения token, access_token, password и key (ключ ArcGIS, ключ встраиваемой карты) в них заменяются на *** — так же, как в журнале действий. Остальные параметры пишутся как есть, поэтому журналы служб всё равно храните с ограниченным доступом.

Журнал действий в окне — Журнал действий; история правок — История правок.

Сторож цикла событий

Если процесс API перестал отвечать дольше LOOP_STALL_S (по умолчанию 5 с), в журнал процесса пишется «Цикл событий не отвечает» со стеком потока и сроком ближайшего таймера:

  • стек в коде приложения — цикл занят синхронной работой;
  • стек в select() при просроченном таймере — цикл «уснул». Сторож будит его, и в журнале появляется «цикл снова отвечает».

Пока цикл стоит, записи идут не чаще раза в 30 с. LOOP_STALL_S=0 выключает сторожа.

Что проверять снаружи

Внешний сторож — например, задача планировщика или Prometheus. На проде эту работу делает отдельная служба, которая не входит в репозитории. Что стоит проверять:

  • /health каждого города: status == "ok";
  • страницу веба каждого города и её entry-скрипт _nuxt/… — оба 200;
  • что службы API, воркеров, веба и martin запущены;
  • длину очередей tgid.<город> в Redis: растёт и не убывает — воркеры стоят;
  • место на дисках баз, журналов и резервных копий;
  • новые строки ERROR в журналах служб;
  • итог резервного копирования last-backup.json — Резервные копии.

«API недоступен» и другие баннеры веба

Веб запрашивает /health при загрузке и показывает полосу под шапкой:

Полоса Причина Что делать
Красная, «API недоступен» или текст ошибки сети /health не ответил Ниже по порядку
Жёлтая, текст про Redis redis.ok = false Запустить Redis; проверить REDIS_ADDR, REDIS_DB
Жёлтая, «На сервере устаревший API (N маршрутов)» меньше 80 маршрутов Не тот процесс отвечает на адресе API; выкатить API

Если API недоступен, проверьте по порядку:

  1. Служба API запущена? Если нет — причина в <служба>.err.log. Частые причины: ошибка в TGID_CITY_DBS, STRICT_AUTH=true при небезопасных настройках («STRICT_AUTH=true forbids…» или «STRICT_AUTH=true requires AUTH_REQUIRED_GET=true»), нет каталога FILES_DIR, база недоступна при старте.
  2. Отвечает ли http://127.0.0.1:<порт>/health на самом сервере? Да, а снаружи нет — ищите причину в nginx: proxy_pass города, upstream API, nginx -t.
  3. Ответ degraded — смотрите database.error, redis.error, city_schema.error.
  4. API отвечает медленно или «зависает» — ищите в logs/app*.log записи сторожа цикла. Проверьте pg_stat_activity: длинные запросы, idle in transaction, исчерпанный пул (DB_POOL_MAX_SIZE).
  5. Расчёты стоят «в очереди» — работают ли воркеры, слушают ли они очередь города (tgid.<код>), растёт ли tgid_celery_queue_length.

Для разработчика

  • /health — routers/core.py, метрики — observability.py, журнал процесса — app_logging.py (свой файл на процесс по замку logs/app[-N].lock: общий файл на Windows не ротируется), сторож — utils/loop_watchdog.py.
  • Баннер веба — layouts/default.vue и refreshApiHealth в services/api/http.ts.
Хотите увидеть эту функцию на своих данных?Покажем ТГИД на демонстрации и ответим на вопросы инженеров.
Запросить демо