# Python Service Logging Writing

> Используй при реализации или правке логирования отдельно запускаемых процессов Python-сервиса: общей настройки logger-а, structured context, полей запроса или сообщения, стабильных событий, уровней, единственной error boundary, JSON renderer-а и тестов logging-контракта. Применяй совместно со скилом конкретного API или worker-процесса. Не использовать для аналитического проектирования logging-контракта, выбора collector-а, метрик и трассировки.

- Skill: `nemagu/python-service-logging-writing` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add nemagu/python-service-logging-writing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nemagu/python-service-logging-writing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: Nemagu (https://skillmd.com/u/nemagu)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/nemagu/python-service-logging-writing

---


# Реализация логирования Python-сервиса

Реализуй единый технический механизм логирования процессов по уже согласованному
контракту наблюдаемости. Не переноси в код догадки о полях, событиях и уровнях.

## Порядок работы

1. Найди общий logging-контракт сервиса и профиль реализуемого процесса.
2. Составь таблицу событий, обязательных полей, владельцев записи и уровней.
3. Сверь существующую logging-библиотеку, renderer и инфраструктурное обогащение.
4. Определи process-scoped и operation-scoped контекст и границы их жизни.
5. Реализуй настройку, привязку контекста и запись событий на границах-владельцах.
6. Добавь тесты логической структуры записей, изоляции контекста и ошибок.

Если нормативного контракта нет или реализация требует нового поля, события либо
уровня, сначала согласуй документацию через
`service-observability-documentation-writing`. Не делай текущие вызовы logger-а
источником требований.

## Источник истины

- Брать формат, поля, события, уровни и безопасность из документации сервиса.
- Не закреплять в общем коде универсальный набор полей для всех сервисов.
- Использовать одинаковое имя и семантику понятия во всех процессах сервиса.
- Не переименовывать машинное событие при реализации.
- Машинные имена событий и внутренние классифицирующие значения оформлять в
  `snake_case` с `_`; не заменять разделитель на `-`. Внешние URL, subject,
  headers и другие значения чужого контракта сохранять без изменения.
- Не добавлять неприменимые поля со значением `None`, если контракт этого не
  требует.
- Учитывать поля, которые гарантированно добавляют runtime, контейнерная платформа
  или collector; не дублировать их вторым источником.

## Устройство реализации

Отделяй три роли:

```text
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 покрыта тестами.
- Профильный скил процесса проверяет свои события и поля.

