Модуль 5 · Урок 20 із 58
Logging: evidence без витоку даних
Log — operational evidence, а не смітник зі значеннями всіх variables. Корисний event відповідає: що сталося, де, з яким safe identifier, який result і що робити далі. Він не містить password, token, email, customer row або повний filesystem path лише тому, що їх легко надрукувати.
Безпечна практика модуля 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
Не логувати 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)
raiselogger.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 модуля
- Прочитайте synthetic JSON/CSV з explicit UTF-8 і root boundary.
- Перекладіть expected parser/I/O failures у
InputError. - Побудуйте deterministic report без partial overwrite.
- Додайте INFO summary та safe ERROR evidence.
- Перевірте normal, missing, malformed, duplicate-header, invalid-type, no-leak і stable-output cases.
Модуль 5 завершено
Після тесту прогрес становитиме 20/58 уроків. Review-проєкт 1 лишається доступним після уроку 16; фінальний іспит, PDF, QR та email-сертифікат заблоковані до всіх 58 уроків і чотирьох прийнятих проєктів.
Методичні джерела
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть лише на офіційну документацію Python.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.