- беклог и план переехали в docs/tasks (38 задач, 11 целей), слаги переименованы с транслита на английские, 85 ссылок поправлены - conventions.md разобран в docs/conventions/, local-research.md — в docs/research/, review-journal.md — в docs/review.md с разделом настройки конвейера; заведены security.md, adr/ и .pm.json - шаг docs.py check добавлен в task gate; поведение в architecture.md помечено девятью маркерами долга, database.md получил настройки с числовым значением
39 lines
3.3 KiB
Markdown
39 lines
3.3 KiB
Markdown
# Логи
|
||
|
||
Структурированный JSON (`log/slog`) в stdout, один формат для dev и prod.
|
||
Сбор и ротацию делает окружение.
|
||
|
||
- `msg` — короткая константа в нижнем регистре, категория события
|
||
(`delivery accepted`, `parse failed`). Данные — атрибутами, не в тексте.
|
||
Подсистему выносим в поле `capability` (`ingest`/`parse`/`query`), не в
|
||
префикс сообщения.
|
||
- **Уровень — это адресат, а не громкость поломки:**
|
||
|
||
| Уровень | Кому | Примеры |
|
||
|---|---|---|
|
||
| `DEBUG` | разработчику при отладке | `/healthz`, тела запросов, шаги разбора |
|
||
| `INFO` | владельцу, аудит постфактум | принята доставка, разбор завершён, старт |
|
||
| `WARN` | владельцу, «может стать проблемой» | точка не разобрана, незнакомая форма метрики |
|
||
| `ERROR` | владельцу, в разбор | не записался архив, сбой БД |
|
||
|
||
- Невалидный ввод от отправителя — `DEBUG`, а не `ERROR`: это норма, разбирать
|
||
нечего. `WARN` ≠ «ничего страшного», `WARN` = «может стать проблемой».
|
||
- Событийное → `INFO`, рутинно-частое (healthcheck, поллинг) → `DEBUG`.
|
||
- **Либо лог, либо возврат, не оба.** Промежуточные слои только оборачивают и
|
||
возвращают. Ошибка логируется **один раз**, на границе доменного слоя,
|
||
которая определяет исход операции (`ingest`) — не в транспорте. Транспорт
|
||
переводит ошибку в ответ и не логирует повторно.
|
||
- Ошибка — атрибутом: `log.Error("parse failed", "error", err, "delivery_id", id)`.
|
||
- Время в логах — UTC, RFC 3339 с долями секунды.
|
||
- Корреляция — по `delivery_id` (ULID), отдельный `trace_id` не заводим.
|
||
- **Секреты в логи не попадают**: токены приёма и чтения, `Authorization`.
|
||
При сомнении логируем факт наличия, не значение.
|
||
- Данные о здоровье — чувствительные. Тела запросов пишем только на `DEBUG`
|
||
и с обрезкой по длине.
|
||
- **Текст ошибки разбора не содержит значений из входа** — только род токена
|
||
(словарём JSON, не именем типа языка) и смещение. Инвариант выше обходится
|
||
одним `fmt.Errorf("%v", tok)`: тело в 8 МиБ дало текст ошибки в 8 МиБ, и он
|
||
уехал атрибутом `error` на уровень `WARN`. Предел держит само сообщение, а не
|
||
обрезка на стороне логирующего: обрезка живёт в другом месте и о новой ошибке
|
||
разбора не узнает.
|