Модуль 5 · Урок 20 із 58

Logging: evidence без витоку даних

Log — operational evidence, а не смітник зі значеннями всіх variables. Корисний event відповідає: що сталося, де, з яким safe identifier, який result і що робити далі. Він не містить password, token, email, customer row або повний filesystem path лише тому, що їх легко надрукувати.

logginglevelscontextredaction

Безпечна практика модуля 5

Пакет містить тільки synthetic JSON/CSV, explicit UTF-8, schema validation, deterministic output, safe logging і локальні tests. Жодних персональних чи production-даних, secrets, мережевих викликів або зовнішніх залежностей.

Завантажити практичний пакет →

Module logger, configuration на entry point

import logging

logger = logging.getLogger(__name__)

def main() -> int:
    logging.basicConfig(
        level=logging.INFO,
        format="%(levelname)s %(name)s %(message)s",
    )
    return run()

Library module створює logger і не викликає basicConfig при import. Entry point або application configuration визначає handlers, level і format. Це зберігає import-safety та не дублює events через випадкові handlers.

Level — severity contract

DEBUGДеталі для diagnosis, зазвичай вимкнені.
INFOНормальні milestones і summary.
WARNINGUnexpected, але operation продовжилась.
ERROROperation не виконана; process може жити.
CRITICALСистема не може безпечно продовжити.

Не логувати expected success як ERROR і не ховати data loss під INFO. Level має дозволяти monitoring rule без знання тексту кожного message.

Lazy formatting відділяє template від values

logger.info(
    "report_written records=%d rejected=%d",
    accepted_count,
    rejected_count,
)

Logging API відкладає interpolation, доки event справді потрібен. Stable event name і key=value fields легше шукати, ніж різні prose sentences. User-controlled strings не треба використовувати як format template.

Exception evidence без подвійного log

try:
    report = load_report(path)
except InputError:
    logger.exception("report_load_failed file=%s", path.name)
    raise

logger.exception додає traceback у active exception handler. Визначте ownership: або layer логить і re-raise, або caller логить; якщо кожний layer друкує той самий failure, один incident перетворюється на кілька misleading events. Public CLI message і internal traceback можуть мати різні audiences.

Redaction — до format, не після витоку

Allowlist fields кращий за спробу regex-ом знайти всі secrets. Логуйте record_id лише коли він synthetic або non-sensitive; замість email — internal correlation ID; замість full path — path.name, якщо цього достатньо. Ніколи не логувати environment dump, Authorization header, cookies, tokens або raw invalid payload.

Privacy gate

Retention, access і deletion logs є частиною design. «Це лише debug» не скасовує privacy та security boundary.

Logs треба тестувати як contract

unittest.TestCase.assertLogs може підтвердити logger, level і message для expected warning/error. Окремий negative assertion перевіряє, що synthetic secret marker не з’явився. Не прив’язуйте test до timestamp або absolute path, якщо вони не є contract.

with self.assertLogs("app.audit", level="INFO") as captured:
    build_summary(records)

self.assertIn("records=3", captured.output[0])
self.assertNotIn("secret-marker", "\n".join(captured.output))

Практичний pipeline модуля

  1. Прочитайте synthetic JSON/CSV з explicit UTF-8 і root boundary.
  2. Перекладіть expected parser/I/O failures у InputError.
  3. Побудуйте deterministic report без partial overwrite.
  4. Додайте INFO summary та safe ERROR evidence.
  5. Перевірте normal, missing, malformed, duplicate-header, invalid-type, no-leak і stable-output cases.
Definition of Done: log levels мають semantics; configuration лише на entry point; один failure не дублюється; sensitive markers відсутні; exit status і output files правдиві.

Модуль 5 завершено

Після тесту прогрес становитиме 20/58 уроків. Review-проєкт 1 лишається доступним після уроку 16; фінальний іспит, PDF, QR та email-сертифікат заблоковані до всіх 58 уроків і чотирьох прийнятих проєктів.

Методичні джерела

Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть лише на офіційну документацію Python.

Практична перевірка · урок 20 з 47

Закріпіть матеріал уроку

Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.

1. Де application має викликати basicConfig, щоб imported modules не змінювали global logging policy як side effect?
2. Operation завершилась успішно й записала summary. Який level найкраще підходить для normal milestone без anomaly?
3. Input row пропущено за documented recovery policy, а operation продовжилась. Який level найчастіше передає unexpected-but-recovered state?