Модуль 31

Логування задач та трасування помилок

Ось готовий урок, створений спеціально для тебе у стилі CS50. Уяви, що ми зараз в аудиторії Сандерс Театру, я ходжу сценою, активно жестикулюю, а за моєю спиною — величезний екран з кодом.

Поїхали! 🚀


🎓 УРОК: ЛОГУВАННЯ ЗАДАЧ ТА ТРАСУВАННЯ ПОМИЛОК

(або: Як перестати гадати і почати бачити)


1. 🔥 Вступ: Чорна скринька вашого коду

Уявіть ситуацію. Ви написали геніальний скрипт. Він обробляє замовлення в інтернет-магазині. Ви запускаєте його, він працює, ви йдете спати.

О 3-й годині ночі скрипт падає. Клієнти не отримують товари. Гроші зависають. Ви прокидаєтесь, відкриваєте консоль, а там... пустота. Або, що ще гірше, просто напис Error.

І все.

Питання до вас: Як ви дізнаєтесь, що саме сталося о 3-й ночі? Як ви відтворите помилку, яка виникає лише раз на тиждень при певному положенні зірок?

Без логування ваш код — це чорна кімната, в якій ви шукаєте чорну кішку. З логуванням — ви Шерлок Холмс, який приходить на місце злочину і бачить: ось відбитки пальців, ось розбита ваза, а ось записка від злочинця з точним часом злочину.

Сьогодні ми навчимося залишати ці "хлібні крихти", щоб завжди знати, хто, коли і чому зламав вашу програму.


2. 🧠 Теоретична база: Це більше, ніж просто print()

Багато новачків кажуть: "Девід, навіщо мені щось вчити? Я просто напишу print('Я тут') і все побачу!"

І це працює... поки ваш проєкт маленький. Але коли це сервер, який обробляє 1000 запитів на секунду, ваші print-и перетворяться на нечитабельний потік сміття.

Як це працює "під капотом"?

У професійному програмуванні (наприклад, у Python бібліотека logging) логування — це не просто текст. Це потік подій, який має структуру.

Головне, що треба запам'ятати — це Рівні Логування (Log Levels). Уявіть це як рівень гучності вашої програми:

  1. DEBUG (🐞) — "Я тут, змінна x=5, зайшов у функцію". Це для вас, коли ви пишете код. У продакшні це зазвичай вимикають, бо занадто "гучно".
  2. INFO (ℹ️) — "Сервер запустився", "Користувач увійшов". Це нормальний ритм життя програми.
  3. WARNING (⚠️) — "Хм, дивно, але працюємо далі". Наприклад, мало місця на диску.
  4. ERROR (❌) — "Ми не змогли виконати операцію, але програма ще жива". Наприклад, платіж не пройшов.
  5. CRITICAL (🔥) — "Все пропало!". Програма має негайно зупинитися або вимагає втручання людини.

🔑 Ключова відмінність:

  • print() — це просто крик у порожнечу (консоль).
  • Logging — це документ. Ви можете сказати: "Всі помилки (ERROR) записуй у файл errors.txt, а все інше ігноруй".

3. 🧪 Приклади: Від хаосу до порядку

Давайте подивимось на код. Я використовуватиму Python, бо він читається як англійська, але логіка однакова і для Java, і для C++, і для JavaScript.

Приклад 1: "Наївний підхід" (Як робити НЕ треба)

def divide(a, b):
    print(f"Пробую поділити {a} на {b}...") # Це сміття в консолі
    try:
        return a / b
    except ZeroDivisionError:
        print("Ой, помилка!") # Це неінформативно
        return None

divide(10, 0)

Що тут поганого? Якщо цей код запуститься на сервері вночі, ви побачите "Ой, помилка!". Де? Коли? Які були дані? Невідомо.


Приклад 2: Професійний підхід

Тепер підключаємо logging.

import logging

# Налаштування: показувати час, рівень важливості та повідомлення
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def divide_smart(a, b):
    logging.info(f"Отримано запит на ділення: {a} / {b}")
    try:
        result = a / b
        logging.info(f"Успіх! Результат: {result}")
        return result
    except ZeroDivisionError:
        logging.error("Спроба ділення на нуль! Операція скасована.", exc_info=True)
        return None

# Виклик
divide_smart(10, 0)

Результат у консолі буде таким:

2023-10-25 14:30:05,123 - INFO - Отримано запит на ділення: 10 / 0
2023-10-25 14:30:05,125 - ERROR - Спроба ділення на нуль! Операція скасована.
Traceback (most recent call last):
  File "main.py", line 8, in divide_smart
    result = a / b
ZeroDivisionError: division by zero

🤯 Бачите різницю? Ми бачимо ЧАС. Ми бачимо РІВЕНЬ (ERROR). І завдяки exc_info=True, ми бачимо Трасування (Traceback) — тобто де саме в коді стався вибух.


4. 🛠 Практична частина

Час закачати рукави! Якщо у вас є інтерпретатор Python — вперед. Якщо ні — просто продумайте логіку.

Завдання 1: Перший лог 🔹

Напишіть функцію, яка приймає ім'я користувача і "логує" (INFO) повідомлення: "Користувач [Ім'я] увійшов у систему".

Завдання 2: Рівні важливості 🔹

Додайте у цю функцію перевірку. Якщо ім'я — "admin", виведіть WARNING: "Увага! Вхід адміністратора!".

Завдання 3: Файлова система 🔹

(Трохи складніше) Змініть налаштування так, щоб логи писалися не в консоль, а у файл app.log. Підказка: Параметр filename='app.log' у basicConfig. Запустіть скрипт кілька разів і відкрийте файл. Що ви там бачите?

Завдання 4: Міні-кейс "Банкомат" 🔹

Напишіть функцію withdraw_money(balance, amount). 1. Логуйте спробу зняття (INFO). 2. Якщо amount > balance — логуйте ERROR з текстом "Недостатньо коштів". 3. Якщо все ок — логуйте INFO з новим балансом. 4. Спробуйте зняти більше, ніж є, і подивіться на лог.

Питання "А що, якщо..." 🔹

А що, якщо ваш файл логів app.log виросте до 100 Гігабайт? Він заповнить весь диск і сервер впаде. Як би ви це вирішили? (Подумайте про видалення старих записів або архівування).


5. 💡 Мислення як у розробника

Ви тепер знаєте синтаксис. Але як думати правильно?

❌ Типові помилки новачків:

  1. Логувати паролі. logging.info(f"User login: {password}"). НІКОЛИ! Логи читають адміни, а іноді їх крадуть хакери. Ви щойно подарували їм ключі від квартири.
  2. Тиша. Ловити помилку (except) і нічого не писати в лог. Це називається "ковтати помилку". Програма працює неправильно, але мовчить як партизан.
  3. Забагато шуму. Ставити INFO на кожен "чих" у циклі на мільйон ітерацій. Ви просто покладете свій диск.

✅ Як думає Senior Developer:

  • "Чи допоможе цей рядок мені зрозуміти причину падіння через пів року?"
  • "Чи є тут персональні дані (GDPR)?"
  • "Чи можу я відфільтрувати цей лог?" (Використовуйте теги або JSON-формат для логів, щоб їх могли читати машини).

Порада від Дейвіна: Хороший лог — це історія. Він має початок, дію і результат. Якщо ви читаєте лог і не розумієте сюжету — перепишіть його.


6. 🧩 Підсумок

Отже, що ми сьогодні зробили? 1. Зрозуміли, що програма без логів — це чорна скринька. 2. Вивчили рівні: DEBUG, INFO, WARNING, ERROR, CRITICAL. 3. Навчилися відловлювати помилки так, щоб бачити traceback (слід злочину). 4. Зрозуміли, що логи — це інструмент для майбутнього вас.

Тепер ви не сліпі кошенята в темряві коду, а оператори складної системи з панеллю приладів.

🔮 Тизер наступного уроку: Добре, ми записали логи у файл. Але що, якщо серверів — 50 штук? Ви ж не будете бігати по кожному і відкривати файл блокнотом? На наступному занятті ми поговоримо про Моніторинг і ELK Stack — як збирати логи звідусіль в одне красиве місце.

А поки що... це був CS50! 👋