Документация наблюдаемости сервиса
Документировать целевой logging-контракт всего сервиса и дополнения его отдельных процессов. Не считать текущие вызовы logging требованиями и не проектировать реализацию адаптеров.
Порядок работы
- Прочитать
$hexagonal-service-documentation-writingи получить от него корневой слот, структуру документации и позицию вSUMMARY.md. - Спросить, существует ли принятый набор полей, пример записи или соглашение экосистемы. Использовать их как требования только после подтверждения.
- Если готовой схемы нет, позволить пользователю описать любой удобный вход: сценарии поиска и расследования, процессы, важные операции и отказы, идентификаторы либо желаемые поля.
- Если пользователь не знает, с чего начать, изучить разрешённые им сведения о составе сервиса и предложить стартовый набор полей и ситуаций с объяснением, какой поиск они обеспечивают.
- Согласовать общий контракт сервиса. Не утверждать предложенные поля за пользователя.
- Для каждого отдельно запускаемого процесса согласовать дополнительные поля и значимые логируемые ситуации.
- Показать итоговые таблицы до записи документов. Непринятые варианты оставить предложениями или открытыми вопросами.
- Создать документы и дополнить только назначенный фрагмент
SUMMARY.md. - Проверить отсутствие дублирования, разрешимость ссылок и достижимость каждого документа из навигации.
Структура документов
По умолчанию создавать поддерево:
observability/
├── README.md
└── logging/
├── README.md
├── common.md
└── <process>.md
observability/README.md— индекс согласованных сигналов наблюдаемости.logging/README.md— назначение logging-контракта, состав процессов и навигация.logging/common.md— подтверждённые общие поля, формат, уровни, правила ошибок, идентификаторов, безопасности и объёма.logging/<process>.md— только дополнительные поля и ситуации конкретного фактически существующего процесса.
Технические имена файлов процессов писать в snake_case, например
http_api.md, nats_consumer.md и nats_publisher.md.
Не создавать единый logging.md. Не создавать страницы отсутствующих процессов
и будущих сигналов. Каждый содержательный документ завершать разделом
## Открытые вопросы по правилам общего скила.
Фрагмент навигации строить так:
- [Наблюдаемость](./observability/README.md)
- [Логирование](./observability/logging/README.md)
- [Общий контракт](./observability/logging/common.md)
- [Название процесса](./observability/logging/<process>.md)
Размещать раздел наблюдаемости в позиции, заданной общим скилом; не переставлять соседние корневые разделы.
Общий контракт
Стабильные обозначения
Использовать схему
<контекст>.observability.<сигнал>.<процесс или профиль>.<ситуация>.
Сигнал, процесс и ситуация являются отдельными смысловыми сегментами; не
склеивать процесс с ситуацией и не пропускать профиль. Одинаковый logging-контракт
или ситуация во всех документах имеет одно обозначение независимо от имени файла
и человекочитаемого сообщения.
Не задавать универсальный список обязательных полей внутри скила. Согласовывать их с пользователем для сервиса, учитывая поля, уже добавляемые runtime, контейнерной платформой или системой сбора. Для каждого поля фиксировать:
| Поле | Обязательность | Семантика | Источник контекста | Применимость | Ограничения |
|---|
Отсутствующее неприменимое поле не требовать заполнять null, если пользователь
не выбрал фиксированную схему. Одинаковое понятие называть одинаково во всех
процессах.
Для обязательности использовать единый закрытый словарь: Обязательное,
Условное, Необязательное. Условие присутствия условного поля указывать явно.
Спрашивать о существующей конвенции имён. При её отсутствии предлагать
snake_case. Отделять стабильное машинное имя ситуации от человекочитаемого
сообщения; переименование согласованного имени считать изменением контракта.
Для машинных имён событий и значений классифицирующих полей (operation,
outcome, тип процесса и аналогичные внутренние обозначения) по умолчанию
использовать слова с разделителем _, а не -. Не распространять это правило
на внешние значения: URL, subject, topic, header и заданные чужим контрактом
идентификаторы сохранять без переименования.
Для каждого ограниченного классифицирующего поля перечислять все допустимые значения. Перечисления профиля логирования принадлежат logging-контракту: они могут соответствовать значениям публичного application DTO один к одному, но не зависят от типа или перечисления прикладного слоя. Одинаковые типы worker-ов в экосистеме используют одинаковые имена полей и значения перечислений.
Формат и вывод
- Согласовывать формат с пользователем; по умолчанию предлагать structured JSON.
- Допускать человекочитаемый renderer для локальной разработки при сохранении тех же логических полей.
- Описывать семантику независимо от logging-библиотеки.
- Для контейнеров по умолчанию предлагать
stdout/stderr. - Файлы, прямую отправку и другой transport добавлять только по требованию.
- Не проектировать сбор, доставку, ротацию и хранение вне заданной области.
Уровни
Использовать единую семантику:
DEBUG— внутренние диагностические и высокочастотные шаги.INFO— штатный lifecycle и подтверждённый значимый успешный результат.WARNING— контролируемая деградация, retry или ожидаемая проблема без потери управления процессом.ERROR— операция не завершена, но процесс способен продолжать работу.CRITICAL— процесс не способен продолжать работу.
Показывать пользователю высокочастотные ситуации и отдельно согласовывать их
перевод из DEBUG в INFO. Не назначать INFO каждому успешному сообщению или
внутреннему шагу автоматически.
Профиль процесса
Для каждого процесса определить дополнительные поля, а затем таблицу:
| Ситуация | Машинное имя | Уровень | Условие записи | Обязательные поля | Дополнительные поля |
|---|
Описывать только значимые ситуации: lifecycle, итог операции, retry,
контролируемую деградацию и окончательный отказ. Не превращать документ в трассу
каждой функции. Не копировать общие поля в каждый профиль; ссылаться на
common.md.
Идентификаторы
Для каждого процесса обсуждать, какие идентификаторы он получает, создаёт, передаёт дальше и сохраняет при повторе. Предлагать подходящие смыслу варианты, например идентификатор запроса, сообщения, корреляции, события или запуска, но не делать их универсально обязательными.
Фиксировать требуемую семантику, а не способ реализации. Если согласован
event_id, документировать его стабильность при retry, но не определять таблицу,
адаптер, слой хранения или алгоритм генерации.
Ошибки
- Логировать один окончательный отказ один раз на внешней границе, знающей исход.
- Внутренним слоям и адаптерам разрешать преобразование ошибки без повторной записи того же отказа.
- Ожидаемые отказы и предусмотренные retry описывать без stack trace: безопасная категория, исход, попытка и относящийся к операции контекст.
- Для неожиданной ошибки предлагать один stack trace на конечной границе и согласовывать политику повторов, ограничения объёма и усечения. Для structured формата отдельно согласовывать и фиксировать стабильное имя условного поля, содержащего stack trace; в записях без stack trace это поле не требовать.
- Не делать stack trace обязательным общим полем.
- Для повторяющейся неожиданной ошибки worker-а предлагать ограничение или агрегацию одинаковых записей, не скрывая факт продолжающегося сбоя.
Безопасность
Не логировать секреты, токены, пароли, authorization headers, строки подключения, полные HTTP/message payload, SQL и его параметры. Персональные данные и иные предметно чувствительные сведения включать только после явного подтверждения. Спрашивать пользователя о дополнительных категориях чувствительных данных и о допустимых идентификаторах.
Границы
- Описывать целевое состояние, а не реестр расхождений реализации.
- Использовать код для определения процессов только с разрешения пользователя.
- Аудит текущего logging выполнять отдельным отчётом по явной просьбе.
- Не выбирать logging-библиотеку, collector, хранилище или dashboard.
- Не определять устройство HTTP, broker, persistence, outbox и worker-адаптеров.
- Пока не документировать метрики и трассировку и не создавать для них пустые разделы. Добавить их в этот скил позднее после отдельного согласования.
Проверка
- Общий контракт и каждый профиль процесса подтверждены пользователем.
- Для полей объяснены семантика и сценарии поиска.
- Для ситуаций определены условие, уровень и относящиеся к ним поля.
- Высокочастотные записи и политика неожиданных ошибок согласованы.
- Для structured-формата зафиксировано имя условного поля stack trace.
- Идентификаторы описаны семантически без проектирования чужих адаптеров.
- Чувствительные данные исключены.
- Process-документы не повторяют
common.md. - Поддерево встроено в структуру и
SUMMARY.mdобщего скила. - Каждый документ содержит актуальный раздел открытых вопросов.