Logging א': למה print אינו Logging, ורמות הלוג

מטרות השיעור
  • להסביר מה זה Log ולמה print לא מתאים לתיעוד במערכת אמיתית
  • להכיר את חמש רמות ה-Logging ומתי משתמשים בכל אחת
  • להגדיר Logging בסיסי עם logging.basicConfig ולבחור רמה מינימלית
  • להוסיף לפורמט הלוג זמן ורמה

מה נלמד?

  • מה זה Log (יומן) ולמה מערכות אמיתיות כותבות אותו.
  • למה print אינו Logging.
  • המודול logging של Python.
  • חמש רמות הלוג: debug, info, warning, error, critical.

למה צריך את זה?

השרת שתכתבו בנושא Backend ומסדי נתונים ירוץ בלי שאף אחד יסתכל עליו, אולי על מחשב בענן, באמצע הלילה. מחר בבוקר לקוח יגיד “ההזמנה שלי נעלמה בלילה”. איך תדעו מה קרה?

  • print הדפיס למסך שאף אחד לא ראה, וכבר נעלם.
  • ה-Debugger לא עוזר, כי הבאג קרה אתמול, לא עכשיו.

הלוג הוא “קופסה שחורה” כמו במטוס: תיעוד של מה שקרה, מתי, וכמה חמור. כל מערכת מקצועית כותבת לוגים, ומפתחים קוראים אותם כל יום.

הסבר מהבסיס

מה זה Log?

Log הוא רצף רשומות (Records). כל רשומה מתארת אירוע אחד: מתי קרה, כמה חמור הוא, ומה קרה.

2026-10-06 09:14:02 INFO     User dana logged in
2026-10-06 09:14:30 WARNING  Login attempt with wrong password for avi
2026-10-06 09:15:11 ERROR    Payment failed for order 1042: card declined

למה print אינו Logging

printlogging
זמןאין. לא יודעים מתי זה קרה.אוטומטי בכל רשומה
חומרהכל ההודעות נראות אותו דבר5 רמות. אפשר לסנן
כיבוי/הדלקהצריך למחוק או להוסיף שורות בקודמשנים הגדרה אחת, בלי לגעת בקוד
יעדרק למסךמסך, קובץ, שרת לוגים…
בשרתהולך לאיבודנשמר ונבדק אחר כך

כלל: print הוא לתקשורת עם משתמש (פלט של התוכנית). logging הוא לתקשורת עם מפתחים ואנשי תפעול (מה קרה בתוך התוכנית).

חמש הרמות

רמהמספרמתי משתמשיםדוגמה
DEBUG10פרטים טכניים למפתח, בזמן פיתוח ודיבאג"cart contents: [...]"
INFO20אירועים רגילים וחשובים — “הכול תקין”"user dana logged in"
WARNING30משהו חריג, אבל המערכת ממשיכה"disk 90% full", "retrying request"
ERROR40פעולה נכשלה"payment failed for order 1042"
CRITICAL50המערכת כולה בסכנה ואולי לא יכולה להמשיך"database unreachable - shutting down"

רמה מינימלית — הסינון

מגדירים רמה מינימלית, ומוצגות רק הודעות ממנה ומעלה:

  • בזמן פיתוח: DEBUG. רואים הכול.
  • בשרת אמיתי (Production): INFO או WARNING. רק מה שחשוב, בלי “רעש”.

ברירת המחדל של Python היא WARNING. לכן אם לא מגדירים כלום, הודעות debug ו-info לא יוצגו בכלל.

אנלוגיה: מערכת התראות בבית חולים

DEBUG = הרישום המלא של כל מדידה (רק הרופא החוקר מסתכל). INFO = “המטופל קיבל ארוחת צהריים”. WARNING = “חום מעט גבוה, לעקוב”. ERROR = “תרופה לא ניתנה בזמן”. CRITICAL = “קוד כחול!”. האחות במשמרת לילה מגדירה לעצמה לראות רק WARNING ומעלה, אחרת היא תטבע בהודעות.

תחביר

import logging

# configure once, at the start of the program
logging.basicConfig(
    level=logging.INFO,                                  # minimum level to show
    format="%(asctime)s %(levelname)s %(message)s",      # how each record looks
)

# write log records
logging.debug("technical details")
logging.info("normal important event")
logging.warning("something unusual")
logging.error("an operation failed")
logging.critical("the whole system is in danger")

שדות נפוצים ב-format:

שדהמה מוצג
%(asctime)sתאריך ושעה
%(levelname)sשם הרמה (INFO, ERROR…)
%(message)sההודעה שלכם
%(funcName)sשם הפונקציה שכתבה את הרשומה
%(lineno)dמספר השורה

דוגמת קוד ראשונה

week-2/log_levels.py:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)

logging.debug("This is a debug message")
logging.info("Application started")
logging.warning("Config file not found, using defaults")
logging.error("Could not connect to the payment service")
logging.critical("Out of memory - shutting down")

פלט:

2026-10-06 09:30:12,481 INFO Application started
2026-10-06 09:30:12,481 WARNING Config file not found, using defaults
2026-10-06 09:30:12,482 ERROR Could not connect to the payment service
2026-10-06 09:30:12,482 CRITICAL Out of memory - shutting down

פירוק הקוד שורה אחר שורה

שורההסבר
import loggingהמודול המובנה של Python ללוגים. אין צורך בהתקנה.
logging.basicConfig(...)הגדרה חד-פעמית בתחילת התוכנית: מה הרמה המינימלית ואיך נראית כל רשומה.
level=logging.INFOמציגים רק מ-INFO ומעלה.
format="..."תבנית הרשומה: זמן, רמה, הודעה.
logging.debug(...)לא מוצג! DEBUG (10) נמוך מ-INFO (20), ולכן סונן.
logging.info(...) עד logging.critical(...)מוצגים, כי הם ברמה INFO ומעלה.
,481 בפלטאלפיות שנייה. שימושי כשהרבה אירועים קורים באותה שנייה.

נסו: שנו ל-level=logging.DEBUG והריצו שוב. עכשיו מופיעות 5 שורות. ב-level=logging.ERROR מופיעות רק 2. שיניתם שורה אחת, ולא נגעתם בהודעות עצמן. זה הכוח של רמות.

דוגמה נוספת

לוגים בתוך תוכנית אמיתית, משולבים עם Exceptions מהשיעורים הקודמים. week-2/orders.py:

import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)-8s %(funcName)s: %(message)s",
)

STOCK = {"bread": 5, "milk": 0, "eggs": 12}


def place_order(product, quantity):
    logging.debug("place_order called with product=%s quantity=%s", product, quantity)

    if product not in STOCK:
        logging.error("Unknown product requested: %s", product)
        return False

    available = STOCK[product]
    if available == 0:
        logging.warning("Product out of stock: %s", product)
        return False

    if quantity > available:
        logging.warning("Not enough %s: requested %s, available %s", product, quantity, available)
        return False

    STOCK[product] = available - quantity
    logging.info("Order placed: %s x%s (left in stock: %s)", product, quantity, STOCK[product])
    return True


place_order("bread", 2)
place_order("milk", 1)
place_order("cake", 1)
place_order("eggs", 20)

פלט:

2026-10-06 09:41:03,115 DEBUG    place_order: place_order called with product=bread quantity=2
2026-10-06 09:41:03,115 INFO     place_order: Order placed: bread x2 (left in stock: 3)
2026-10-06 09:41:03,116 DEBUG    place_order: place_order called with product=milk quantity=1
2026-10-06 09:41:03,116 WARNING  place_order: Product out of stock: milk
2026-10-06 09:41:03,116 DEBUG    place_order: place_order called with product=cake quantity=1
2026-10-06 09:41:03,116 ERROR    place_order: Unknown product requested: cake
2026-10-06 09:41:03,117 DEBUG    place_order: place_order called with product=eggs quantity=20
2026-10-06 09:41:03,117 WARNING  place_order: Not enough eggs: requested 20, available 12

פירוק:

  • %(levelname)-8s — ה--8 מרפד את שם הרמה ל-8 תווים, כך שההודעות מיושרות בעמודה. נוח לקריאה.
  • %(funcName)s — רואים מאיזו פונקציה הגיעה כל רשומה.
  • logging.info("... %s ...", product, quantity) — %s הוא מקום לערך, והערכים מועברים כארגומנטים נוספים. זו הדרך המומלצת ב-logging: הטקסט נבנה רק אם ההודעה באמת תוצג, ולכן הודעות DEBUG מסוננות כמעט לא עולות כלום.
  • בחירת הרמות: “הוזמן” הוא INFO (אירוע רגיל וחשוב). “אזל מהמלאי” הוא WARNING (העסק עובד, אבל כדאי לדעת). “מוצר לא קיים” הוא ERROR (משהו לא תקין בבקשה, אולי באג בצד הלקוח). פרטי הקריאה הם DEBUG.
  • if product not in STOCK — in על dict בודק אם המפתח קיים.

עכשיו שנו ל-level=logging.WARNING: הלוג יציג רק את 3 הבעיות. כך ייראה בשרת אמיתי, שבו מעניינות רק התקלות.

טעות נפוצה

הטעות 1: לקרוא ל-basicConfig אחרי שכבר נכתבה הודעה, או פעמיים.

import logging
logging.info("starting")                     # uses the default config!
logging.basicConfig(level=logging.INFO)      # ignored - already configured
logging.info("now?")                         # still not shown

הקריאה הראשונה ל-logging.info מגדירה אוטומטית את ברירת המחדל (WARNING), ו-basicConfig מאוחר מתעלם בשקט. basicConfig תמיד ראשון, ופעם אחת, מיד אחרי ה-import.

הטעות 2: “לא רואה את ה-info שלי”. הסיבה היא כמעט תמיד ברירת המחדל WARNING. הפתרון: level=logging.INFO (או DEBUG).

הטעות 3: רמה לא נכונה.

logging.error("User dana logged in")       # not an error!
logging.info("Payment failed!")            # this IS an error

רמה שגויה הופכת את הסינון לחסר תועלת: מי שמסתכל רק על ERROR יפספס תשלום שנכשל, ויוצף בהתחברויות רגילות.

הטעות 4: לרשום מידע רגיש. logging.info("login: user=dana password=1234") — לעולם לא סיסמאות, מספרי כרטיס אשראי או טוקנים. לוגים נקראים על ידי הרבה אנשים ונשמרים זמן רב.

תרגול

התרגילים מבוססים רק על מה שנלמד בשיעור הזה ובשיעורים שלפניו. נסו לבד, ורק אז פתחו את הפתרון.

תרגיל 1: איזו רמה?

לכל אירוע — באיזו רמת לוג הייתם רושמים אותו: DEBUG, INFO, WARNING, ERROR או CRITICAL?

  1. משתמש התחבר בהצלחה.
  2. ערך של משתנה בתוך לולאה, בזמן חיפוש באג.
  3. משתמש הקליד סיסמה שגויה.
  4. התשלום נכשל.
  5. אין חיבור למסד הנתונים, והשרת לא יכול לעבוד בכלל.
הצג פתרון
  1. INFO — אירוע רגיל וחשוב לתיעוד.
  2. DEBUG — פרטים טכניים שרלוונטיים רק בזמן פיתוח.
  3. WARNING — משהו חריג, אבל המערכת ממשיכה לעבוד.
  4. ERROR — פעולה נכשלה.
  5. CRITICAL — המערכת כולה לא יכולה לעבוד.

תרגיל 2: רמה מינימלית

import logging

logging.basicConfig(level=logging.WARNING)

logging.debug("checking item 3")
logging.info("order 17 created")
logging.warning("stock is low: 2 left")
logging.error("payment failed for order 17")

אילו מההודעות יופיעו, ולמה? מה צריך לשנות כדי לראות את כולן?

הצג פתרון

יופיעו רק WARNING ו-ERROR:

WARNING:root:stock is low: 2 left
ERROR:root:payment failed for order 17

level=logging.WARNING הוא רמה מינימלית: מוצגות רק הודעות ברמה הזו ומעליה. כדי לראות את כולן משנים ל-level=logging.DEBUG. בלי לגעת בשאר הקוד — זה כל היתרון.

תרגיל 3: מ-print ל-logging

החליפו כל print ברמת הלוג המתאימה, והגדירו פורמט עם זמן, רמה והודעה:

def withdraw(balance, amount):
    print("withdraw called with", amount)
    if amount > balance:
        print("not enough money, balance is", balance)
        return balance
    print("withdrew", amount)
    return balance - amount
הצג פתרון
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)-8s %(message)s",
)


def withdraw(balance, amount):
    logging.debug("withdraw called with %s", amount)
    if amount > balance:
        logging.error("not enough money, balance is %s", balance)
        return balance
    logging.info("withdrew %s", amount)
    return balance - amount


withdraw(100, 30)
withdraw(100, 500)
  • כניסה לפונקציה — DEBUG, משיכה מוצלחת — INFO, כישלון — ERROR.
  • הפורמט מוסיף לכל שורה זמן ורמה, למשל: 2026-11-01 10:15:02 ERROR not enough money, balance is 100.

תרגיל 4: לקרוא שורת לוג

2026-11-01 09:14:30 WARNING  Wrong password for avi
  1. מה כל חלק בשורה, ואיזה חלק בהגדרה format יוצר אותו?
  2. למה חשוב שיש בשורה זמן?
הצג פתרון
  1. החלקים:
    • 2026-11-01 09:14:30 — הזמן, נוצר מ-%(asctime)s.
    • WARNING — הרמה, נוצרת מ-%(levelname)s.
    • Wrong password for avi — ההודעה, נוצרת מ-%(message)s.
  2. כשמשהו קורה בשרת בשלוש בלילה, הזמן מאפשר לשחזר מה קרה ובאיזה סדר, ולהצליב עם אירועים אחרים.

תרגיל 5: print או logging?

לכל מקרה — print או logging? הסבירו.

  1. תוכנית שמבקשת מהמשתמש את שמו ומברכת אותו.
  2. שרת שרץ כל הלילה, ורוצים לדעת בבוקר אילו הזמנות נכשלו.
  3. בדיקה זמנית של ערך משתנה בזמן פיתוח, שתרצו לכבות בלי למחוק.
הצג פתרון
  1. print — זה הפלט שהתוכנית מציגה למשתמש.
  2. logging (ERROR) — מידע למפתח, עם זמן ורמה, שאפשר לשמור ולחפש בו.
  3. logging (DEBUG) — אפשר לכבות את כל הודעות ה-DEBUG בשורה אחת (העלאת הרמה המינימלית), בלי למחוק קוד.

הכלל: print למשתמש, logging למפתח.

סיכום

  • Log = תיעוד של אירועים: מתי, כמה חמור, ומה קרה. “קופסה שחורה” של התוכנה.
  • print = פלט למשתמש. logging = תיעוד למפתחים: זמן, רמה, סינון ויעדים.
  • 5 רמות: DEBUG < INFO < WARNING < ERROR < CRITICAL. מוצגות רק הודעות מהרמה המינימלית ומעלה.
  • ברירת המחדל היא WARNING. basicConfig נקרא פעם אחת, ראשון.
  • logging.info("x=%s", x) היא הצורה המומלצת. ולעולם לא רושמים סיסמאות.

דוקומנטציה רשמית