Files
av d79189be18 docs: документация переведена на канон av-dev-pm
- беклог и план переехали в 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 получил настройки с числовым значением
2026-08-03 17:14:53 +03:00

3.3 KiB
Raw Permalink Blame History

Логи

Структурированный 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. Предел держит само сообщение, а не обрезка на стороне логирующего: обрезка живёт в другом месте и о новой ошибке разбора не узнает.