fix(tradein/devops): логи в journald — переживают пересоздание контейнера (#2741) #2758

Merged
bot-backend merged 1 commit from fix/2741-log-retention into main 2026-08-06 21:24:58 +00:00
Collaborator

Проблема

json-file пишет в /var/lib/docker/containers/<id>/ — каталог удаляется вместе с контейнером. Деплоев ~20/сутки, скрейперы работают ночью, разбор идёт утром → окно жизни лога почти никогда не покрывает интересное. За 05-06.08 это трижды сорвало разбор: #2695 (1600 отказов Авито), #2698 (503 домовой оценки), #2676 (падения сайдкара).

Что сделано

Одна строка в общем anchor'е x-logging — все 6 сервисов tradein переходят на journald:

  • запись уходит в /var/log/journal на хосте и переживает docker rm;
  • история адресуется по времени (--since/--until), а не «сколько осталось от последнего рестарта»;
  • потолок — общий journald SystemMaxUse (дефолт 4G), а не 60 МБ на сервис, обнуляемые каждым деплоем (это и был второй пункт #2715: 60 МБ при флуде прокручиваются за минуты).

Замеры на проде (2026-08-06)

/var/log/journal 2.3G за 103 дня (~22 МБ/сутки системных), persistent
потолок journald SystemMaxUse дефолт = 4G (сам вытесняет старейшее, дисковый риск нулевой)
объём tradein единицы-десятки МБ/сутки: 5.8k карточек за 24ч по scrape_runs, ~153 Б/строку
текущий json-file tradein-postgres 04.07 прокрутил 40 МБ за 6 часов (два ротированных файла по 20 МБ) — 60-МБ потолок реально выбирается за часы

Проверено ДО правки (прод, throwaway-контейнер)

docker run --rm --log-driver=journald --log-opt tag=ponytail-preflight alpine ...
# контейнер удалён (--rm), запись читается:
journalctl -t ponytail-preflight        → journald-preflight-<ts>
journalctl CONTAINER_NAME=...           → та же строка

Опровергнутая предпосылка

Голый journalctl под deploy-юзером не работает: gendesign состоит в docker, но не в adm/systemd-journal, а sudo просит пароль → выдаёт «No entries». Поэтому в комментарии записан рабочий однострочник через docker-группу и разовая команда владельцу (usermod -aG adm gendesign) — до неё правка всё равно не регрессия: docker logs <c> работает ровно как раньше (демон читает журнал сам).

Что НЕ сделано (осознанно)

  • Уровень логирования не трогал (п.3 issue). LoggingIntegration(level=INFO, event_level=ERROR) в main.py/scheduler_main.py/tgbot_main.py — поштучные warning в GlitchTip не попадают. Поднять до WARNING = 1600 событий за прогон → это отдельная задача с квотами и семплингом, и это правка app-кода, не infra.
  • Основной gendesign-стек не трогал — у него logging: вообще нет (дефолт json-file без потолка, gendesign-postgres-1 = 155 МБ), но это другой деплой-пайплайн и другой blast radius.

Test plan

  • docker compose -f docker-compose.prod.yml config -q — OK
  • journald-драйвер проверен на проде до мержа (см. выше)
  • после деплоя: все 6 контейнеров Up, планировщик жив (scrape_runs пополняется), запись, сделанная ДО пересоздания, читается ПОСЛЕ него

Refs #2741, #2715

## Проблема `json-file` пишет в `/var/lib/docker/containers/<id>/` — каталог удаляется вместе с контейнером. Деплоев ~20/сутки, скрейперы работают ночью, разбор идёт утром → окно жизни лога почти никогда не покрывает интересное. За 05-06.08 это трижды сорвало разбор: #2695 (1600 отказов Авито), #2698 (503 домовой оценки), #2676 (падения сайдкара). ## Что сделано Одна строка в общем anchor'е `x-logging` — все 6 сервисов tradein переходят на `journald`: - запись уходит в `/var/log/journal` **на хосте** и переживает `docker rm`; - история адресуется по времени (`--since/--until`), а не «сколько осталось от последнего рестарта»; - потолок — общий journald `SystemMaxUse` (дефолт 4G), а не 60 МБ на сервис, обнуляемые каждым деплоем (это и был второй пункт #2715: 60 МБ при флуде прокручиваются за минуты). ## Замеры на проде (2026-08-06) | | | |---|---| | `/var/log/journal` | 2.3G за 103 дня (~22 МБ/сутки системных), persistent | | потолок journald | `SystemMaxUse` дефолт = 4G (сам вытесняет старейшее, дисковый риск нулевой) | | объём tradein | единицы-десятки МБ/сутки: 5.8k карточек за 24ч по `scrape_runs`, ~153 Б/строку | | текущий json-file | tradein-postgres 04.07 прокрутил 40 МБ за 6 часов (два ротированных файла по 20 МБ) — 60-МБ потолок реально выбирается за часы | ## Проверено ДО правки (прод, throwaway-контейнер) ``` docker run --rm --log-driver=journald --log-opt tag=ponytail-preflight alpine ... # контейнер удалён (--rm), запись читается: journalctl -t ponytail-preflight → journald-preflight-<ts> journalctl CONTAINER_NAME=... → та же строка ``` ## Опровергнутая предпосылка Голый `journalctl` под deploy-юзером **не работает**: `gendesign` состоит в `docker`, но не в `adm`/`systemd-journal`, а `sudo` просит пароль → выдаёт «No entries». Поэтому в комментарии записан рабочий однострочник через docker-группу и разовая команда владельцу (`usermod -aG adm gendesign`) — до неё правка всё равно не регрессия: `docker logs <c>` работает ровно как раньше (демон читает журнал сам). ## Что НЕ сделано (осознанно) - **Уровень логирования не трогал** (п.3 issue). `LoggingIntegration(level=INFO, event_level=ERROR)` в `main.py`/`scheduler_main.py`/`tgbot_main.py` — поштучные `warning` в GlitchTip не попадают. Поднять до WARNING = 1600 событий за прогон → это отдельная задача с квотами и семплингом, и это правка app-кода, не infra. - **Основной gendesign-стек не трогал** — у него `logging:` вообще нет (дефолт json-file без потолка, `gendesign-postgres-1` = 155 МБ), но это другой деплой-пайплайн и другой blast radius. ## Test plan - [x] `docker compose -f docker-compose.prod.yml config -q` — OK - [x] journald-драйвер проверен на проде до мержа (см. выше) - [ ] после деплоя: все 6 контейнеров Up, планировщик жив (`scrape_runs` пополняется), запись, сделанная ДО пересоздания, читается ПОСЛЕ него Refs #2741, #2715
bot-backend added 1 commit 2026-08-06 21:19:46 +00:00
fix(tradein/devops): логи в journald — переживают пересоздание контейнера (#2741)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
62f64f36cb
json-file пишет в /var/lib/docker/containers/<id>/ — каталог удаляется вместе
с контейнером. При ~20 деплоях в сутки окно жизни лога редко больше часа, а
скрейперы работают ночью: к утреннему разбору логов заведомо нет. За один день
это трижды сорвало разбор (#2695 — 1600 отказов Авито, #2698, #2676).

journald отдаёт stdout/stderr в /var/log/journal на хосте: запись переживает
`docker rm` и адресуется по времени (--since/--until), а не «сколько осталось
от последнего рестарта». Глубина ограничена journald глобально (SystemMaxUse,
дефолт 4G), а не 60 МБ на сервис, обнуляемыми деплоем.

Проверено на проде до правки: контейнер с --log-driver=journald + --rm, после
его удаления запись читается по -t и по CONTAINER_NAME. Замеры там же:
/var/log/journal = 2.3G за 103 дня (~22 МБ/сутки), tradein добавит единицы-
десятки МБ/сутки (5.8k карточек за сутки по scrape_runs, ~153 Б/строку) —
вытеснения не будет неделями при требуемых «сутки-двое».

`docker logs <c>` работает как раньше (демон читает журнал сам). Прямой
journalctl под deploy-юзером не работает — он в docker, но не в adm; рабочий
docker-однострочник и разовая команда владельцу записаны в комментарии.
bot-backend merged commit b1498a9ca7 into main 2026-08-06 21:24:58 +00:00
bot-backend deleted branch fix/2741-log-retention 2026-08-06 21:24:58 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2758
No description provided.