Реализация логирования Python-сервиса
Реализуй единый технический механизм логирования процессов по уже согласованному
контракту наблюдаемости. Не переноси в код догадки о полях, событиях и уровнях.
Порядок работы
- Найди общий logging-контракт сервиса и профиль реализуемого процесса.
- Составь таблицу событий, обязательных полей, владельцев записи и уровней.
- Сверь существующую logging-библиотеку, renderer и инфраструктурное обогащение.
- Определи process-scoped и operation-scoped контекст и границы их жизни.
- Реализуй настройку, привязку контекста и запись событий на границах-владельцах.
- Добавь тесты логической структуры записей, изоляции контекста и ошибок.
Если нормативного контракта нет или реализация требует нового поля, события либо
уровня, сначала согласуй документацию через
service-observability-documentation-writing. Не делай текущие вызовы logger-а
источником требований.
Источник истины
- Брать формат, поля, события, уровни и безопасность из документации сервиса.
- Не закреплять в общем коде универсальный набор полей для всех сервисов.
- Использовать одинаковое имя и семантику понятия во всех процессах сервиса.
- Не переименовывать машинное событие при реализации.
- Машинные имена событий и внутренние классифицирующие значения оформлять в
snake_case с _; не заменять разделитель на -. Внешние URL, subject,
headers и другие значения чужого контракта сохранять без изменения.
- Не добавлять неприменимые поля со значением
None, если контракт этого не
требует.
- Учитывать поля, которые гарантированно добавляют runtime, контейнерная платформа
или collector; не дублировать их вторым источником.
Устройство реализации
Отделяй три роли:
logging configuration -> process context -> operation context -> final boundary
- Composition root выбирает library adapter, renderer, уровень и output и
передаёт готовый logger процессу.
- Общая настройка не импортирует presentation-, application- или domain-типы.
- Классифицирующие поля реализуй отдельными перечислениями logging-слоя. Не
импортируй для них перечисления application DTO, даже при совпадении значений
один к одному; используй явное исчерпывающее преобразование и проверь его
тестами.
- Process context один раз связывает поля экземпляра процесса.
- Operation context добавляет поля конкретного запроса, сообщения или итерации.
- Конечная граница записывает согласованное событие с итогом и длительностью.
- Не передавай глобальный изменяемый словарь контекста между конкурентными
операциями.
Не фиксируй конкретную библиотеку. Адаптируй существующую либо предложенную
пользователю библиотеку к этому контракту. Structured JSON используй только когда
он задан требованиями; локальный renderer должен сохранять те же логические поля.
Контекст и конкурентность
- Для неявного контекста используй
contextvars, а не thread-local и не
module-level mutable state.
- Явную передачу immutable context предпочитай, когда она не засоряет публичные
внутренние контракты и соответствует проекту.
- Устанавливай operation context до вызова пользовательского кода и обязательно
восстанавливай прежний контекст в
finally через token/reset либо эквивалент.
- Копируй контекст при создании отдельной задачи только осознанно; не допускай
утечки полей между параллельными запросами и сообщениями.
- Добавляй полученный correlation ID без замены и передавай его дальше по
требованиям. Не генерируй идентификатор, если контракт назначил владельцем
другую систему.
- Измеряй длительность монотонными часами. Timestamp записи предоставляет
logging runtime или renderer согласно контракту.
Владение записями
- Runtime процесса владеет startup, готовностью ресурсов, сигналом остановки,
завершением и фатальным shutdown.
- HTTP middleware владеет окончательным исходом HTTP-запроса; error boundary
предоставляет ему классификацию неожиданной ошибки без второй записи.
- Consumer владеет окончательным исходом сообщения после выбора и выполнения
ACK/NAK/TERM.
- Периодическая task владеет итогом итерации и переходами readiness, которые
вычисляет из результатов операции.
- Технологический адаптер может добавлять локальную диагностику, но не повторяет
итог операции и stack trace, принадлежащие внешней границе.
- Application и domain не должны зависеть от presentation logging context ради
технической записи.
Если одна ошибка пересекает несколько границ, заранее назначь одну границу записи.
Внутренние слои преобразуют или пробрасывают её без повторного логирования.
Ошибки и уровни
- Записывай ожидаемый отказ с безопасным
error_type без stack trace.
- Записывай неожиданную ошибку один раз с
exc_info на конечной границе.
- После записи сохраняй предусмотренную семантику: пробрасывай фатальную ошибку,
формируй ответ либо выполняй ACK-действие согласно контракту.
- Не считай сам факт записи обработкой ошибки и не подавляй
CancelledError.
- Уровень выбирай по нормативной таблице, а не по классу Python-исключения.
- Не создавай INFO-запись для каждой успешной высокочастотной операции, если
контракт назначил DEBUG или запретил запись.
- Отключай или перенастраивай access/error logs используемого сервера, когда они
дублируют нормативную итоговую запись или stack trace.
Безопасность
- Формируй запись из allowlist согласованных полей, а не из
__dict__, payload,
request model или объекта исключения целиком.
- Не записывай секреты, credentials, authorization, cookies, строки подключения,
полные HTTP/message payload, SQL и его параметры.
- Не добавляй персональные и предметно чувствительные поля без явного разрешения
контракта.
- Не используй произвольное сообщение исключения, пока не доказана его
безопасность.
- Ограничивай размер stack trace и повторяющихся записей согласно требованиям, не
скрывая продолжающийся окончательный сбой.
Тестирование
Тестируй логическое событие до сериализации либо через тестовый sink:
- точное машинное имя, уровень и обязательные поля;
- отсутствие неприменимых и запрещённых полей;
- соответствие каждого исхода нормативной таблице;
- одну итоговую запись и один stack trace на неожиданную ошибку;
- восстановление контекста после успеха, ошибки, timeout и cancellation;
- отсутствие утечки контекста между конкурентными операциями;
- стабильность идентификатора при повторе;
- измерение длительности управляемыми монотонными часами;
- отсутствие шумных событий, которые контракт запретил логировать.
Не привязывай тесты к порядку JSON-ключей, цветам локального renderer-а и
внутренностям сторонней logging-библиотеки.
Границы
В область скила входят configuration logging-а, structured context, binding и
очистка полей, вызов logger-а на согласованных границах и тесты контракта.
Не входят аналитическое определение полей и событий, collector, доставка и
хранение логов, dashboard, алерты, метрики, трассировка, transport/application/
domain-поведение и бизнес-аудит.
Проверка результата
- Реализация следует общему документу и профилю процесса без новых решений.
- Каждое событие имеет одного владельца и записывается один раз.
- Process и operation context разделены и безопасны при конкурентности.
- Ошибка не теряется и не получает несколько stack trace.
- Renderer и библиотека не просачиваются во внутренние слои.
- Запрещённые данные отсутствуют, а allowlist покрыта тестами.
- Профильный скил процесса проверяет свои события и поля.
1---2name: python-service-logging-writing3description: Используй при реализации или правке логирования отдельно запускаемых процессов Python-сервиса: общей настройки logger-а, structured context, полей запроса или сообщения, стабильных событий, уровней, единственной error boundary, JSON renderer-а и тестов logging-контракта. Применяй совместно со скилом конкретного API или worker-процесса. Не использовать для аналитического проектирования logging-контракта, выбора collector-а, метрик и трассировки.4---56# Реализация логирования Python-сервиса78Реализуй единый технический механизм логирования процессов по уже согласованному9контракту наблюдаемости. Не переноси в код догадки о полях, событиях и уровнях.1011## Порядок работы12131. Найди общий logging-контракт сервиса и профиль реализуемого процесса.142. Составь таблицу событий, обязательных полей, владельцев записи и уровней.153. Сверь существующую logging-библиотеку, renderer и инфраструктурное обогащение.164. Определи process-scoped и operation-scoped контекст и границы их жизни.175. Реализуй настройку, привязку контекста и запись событий на границах-владельцах.186. Добавь тесты логической структуры записей, изоляции контекста и ошибок.1920Если нормативного контракта нет или реализация требует нового поля, события либо21уровня, сначала согласуй документацию через22`service-observability-documentation-writing`. Не делай текущие вызовы logger-а23источником требований.2425## Источник истины2627- Брать формат, поля, события, уровни и безопасность из документации сервиса.28- Не закреплять в общем коде универсальный набор полей для всех сервисов.29- Использовать одинаковое имя и семантику понятия во всех процессах сервиса.30- Не переименовывать машинное событие при реализации.31- Машинные имена событий и внутренние классифицирующие значения оформлять в32 `snake_case` с `_`; не заменять разделитель на `-`. Внешние URL, subject,33 headers и другие значения чужого контракта сохранять без изменения.34- Не добавлять неприменимые поля со значением `None`, если контракт этого не35 требует.36- Учитывать поля, которые гарантированно добавляют runtime, контейнерная платформа37 или collector; не дублировать их вторым источником.3839## Устройство реализации4041Отделяй три роли:4243```text44logging configuration -> process context -> operation context -> final boundary45```4647- Composition root выбирает library adapter, renderer, уровень и output и48 передаёт готовый logger процессу.49- Общая настройка не импортирует presentation-, application- или domain-типы.50- Классифицирующие поля реализуй отдельными перечислениями logging-слоя. Не51 импортируй для них перечисления application DTO, даже при совпадении значений52 один к одному; используй явное исчерпывающее преобразование и проверь его53 тестами.54- Process context один раз связывает поля экземпляра процесса.55- Operation context добавляет поля конкретного запроса, сообщения или итерации.56- Конечная граница записывает согласованное событие с итогом и длительностью.57- Не передавай глобальный изменяемый словарь контекста между конкурентными58 операциями.5960Не фиксируй конкретную библиотеку. Адаптируй существующую либо предложенную61пользователю библиотеку к этому контракту. Structured JSON используй только когда62он задан требованиями; локальный renderer должен сохранять те же логические поля.6364## Контекст и конкурентность6566- Для неявного контекста используй `contextvars`, а не thread-local и не67 module-level mutable state.68- Явную передачу immutable context предпочитай, когда она не засоряет публичные69 внутренние контракты и соответствует проекту.70- Устанавливай operation context до вызова пользовательского кода и обязательно71 восстанавливай прежний контекст в `finally` через token/reset либо эквивалент.72- Копируй контекст при создании отдельной задачи только осознанно; не допускай73 утечки полей между параллельными запросами и сообщениями.74- Добавляй полученный correlation ID без замены и передавай его дальше по75 требованиям. Не генерируй идентификатор, если контракт назначил владельцем76 другую систему.77- Измеряй длительность монотонными часами. Timestamp записи предоставляет78 logging runtime или renderer согласно контракту.7980## Владение записями8182- Runtime процесса владеет startup, готовностью ресурсов, сигналом остановки,83 завершением и фатальным shutdown.84- HTTP middleware владеет окончательным исходом HTTP-запроса; error boundary85 предоставляет ему классификацию неожиданной ошибки без второй записи.86- Consumer владеет окончательным исходом сообщения после выбора и выполнения87 ACK/NAK/TERM.88- Периодическая task владеет итогом итерации и переходами readiness, которые89 вычисляет из результатов операции.90- Технологический адаптер может добавлять локальную диагностику, но не повторяет91 итог операции и stack trace, принадлежащие внешней границе.92- Application и domain не должны зависеть от presentation logging context ради93 технической записи.9495Если одна ошибка пересекает несколько границ, заранее назначь одну границу записи.96Внутренние слои преобразуют или пробрасывают её без повторного логирования.9798## Ошибки и уровни99100- Записывай ожидаемый отказ с безопасным `error_type` без stack trace.101- Записывай неожиданную ошибку один раз с `exc_info` на конечной границе.102- После записи сохраняй предусмотренную семантику: пробрасывай фатальную ошибку,103 формируй ответ либо выполняй ACK-действие согласно контракту.104- Не считай сам факт записи обработкой ошибки и не подавляй `CancelledError`.105- Уровень выбирай по нормативной таблице, а не по классу Python-исключения.106- Не создавай INFO-запись для каждой успешной высокочастотной операции, если107 контракт назначил DEBUG или запретил запись.108- Отключай или перенастраивай access/error logs используемого сервера, когда они109 дублируют нормативную итоговую запись или stack trace.110111## Безопасность112113- Формируй запись из allowlist согласованных полей, а не из `__dict__`, payload,114 request model или объекта исключения целиком.115- Не записывай секреты, credentials, authorization, cookies, строки подключения,116 полные HTTP/message payload, SQL и его параметры.117- Не добавляй персональные и предметно чувствительные поля без явного разрешения118 контракта.119- Не используй произвольное сообщение исключения, пока не доказана его120 безопасность.121- Ограничивай размер stack trace и повторяющихся записей согласно требованиям, не122 скрывая продолжающийся окончательный сбой.123124## Тестирование125126Тестируй логическое событие до сериализации либо через тестовый sink:127128- точное машинное имя, уровень и обязательные поля;129- отсутствие неприменимых и запрещённых полей;130- соответствие каждого исхода нормативной таблице;131- одну итоговую запись и один stack trace на неожиданную ошибку;132- восстановление контекста после успеха, ошибки, timeout и cancellation;133- отсутствие утечки контекста между конкурентными операциями;134- стабильность идентификатора при повторе;135- измерение длительности управляемыми монотонными часами;136- отсутствие шумных событий, которые контракт запретил логировать.137138Не привязывай тесты к порядку JSON-ключей, цветам локального renderer-а и139внутренностям сторонней logging-библиотеки.140141## Границы142143В область скила входят configuration logging-а, structured context, binding и144очистка полей, вызов logger-а на согласованных границах и тесты контракта.145146Не входят аналитическое определение полей и событий, collector, доставка и147хранение логов, dashboard, алерты, метрики, трассировка, transport/application/148domain-поведение и бизнес-аудит.149150## Проверка результата151152- Реализация следует общему документу и профилю процесса без новых решений.153- Каждое событие имеет одного владельца и записывается один раз.154- Process и operation context разделены и безопасны при конкурентности.155- Ошибка не теряется и не получает несколько stack trace.156- Renderer и библиотека не просачиваются во внутренние слои.157- Запрещённые данные отсутствуют, а allowlist покрыта тестами.158- Профильный скил процесса проверяет свои события и поля.