Get AI summaries of any video or article — Sign up free
Python Tutorial: Logging Basics - Logging to Files, Setting Levels, and Formatting thumbnail

Python Tutorial: Logging Basics - Logging to Files, Setting Levels, and Formatting

Corey Schafer·
4 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Python’s logging module is built in, so it can replace print statements without extra installation.

Briefing

Python’s built-in logging module is presented as a practical upgrade from print statements: it lets developers capture what happened (including errors and operational details) over time, route messages by severity, and store them in files for later review or analysis.

The walkthrough starts with a simple arithmetic script that previously relied on commented-out print statements to verify results. Replacing those prints with logging calls demonstrates the first key behavior: logging levels act as a filter. Python provides five standard levels—DEBUG, INFO, WARNING, ERROR, and CRITICAL. DEBUG is detailed diagnostic information, INFO confirms normal operation, WARNING signals something unexpected but not necessarily fatal, ERROR indicates a serious failure, and CRITICAL represents an error severe enough that the program may not continue.

By default, Python’s logging level is WARNING, meaning DEBUG and INFO messages are silently ignored. When the script switches from print to logging.debug, nothing appears in the console until the configuration is changed. The fix is to set the global logging threshold using logging.basicConfig(level=logging.DEBUG). After that, the same debug calls begin to show up.

The next step moves from console output to persistent records. Instead of relying on the default console behavior, the configuration adds a file target via logging.basicConfig(..., filename='test_log'). Running the script creates (or updates) the log file, and repeated runs append new entries—making it possible to track behavior across executions rather than only observing a single run’s console output.

Formatting is then treated as a second major control knob. The log file initially includes extra fields such as the level name and logger name. To customize what appears, the configuration adds a format string using logging “special values” from Python’s logging documentation. The example narrows the output to human-readable time, the level name, and the message, producing entries like a timestamp followed by “DEBUG” and the logged text.

To show how these ideas carry into real code structure, the tutorial briefly applies logging to an object-oriented example with an Employee class. The script configures logging.basicConfig with a different file (employee log), sets level=logging.INFO, and uses a format that includes the level name and message. Replacing a print statement inside the Employee constructor with logging.info results in no console output (because INFO is filtered only if the level is higher), but the employee creation events appear in the employee log file with the chosen formatting.

The closing takeaway is that basic logging is a strong starting point for small applications, but multi-module projects introduce complications: multiple modules may share the same logger, leading to configuration conflicts. The next lesson is positioned around creating separate loggers, adding handlers and formatters, and sending logs to multiple destinations.

Cornell Notes

Logging in Python replaces ad-hoc print debugging with structured, level-based messages that can be filtered and persisted. Python’s standard levels—DEBUG, INFO, WARNING, ERROR, and CRITICAL—control what gets emitted; the default threshold is WARNING, so DEBUG/INFO won’t show unless the level is lowered. logging.basicConfig can route output to the console or to a file (e.g., test_log, employee log), and it can also change the log line layout using a format string (such as time, level name, and message). Applying logging to an Employee class shows how INFO messages can be recorded without cluttering the console, while still capturing events across runs.

Why do DEBUG and INFO messages appear to “disappear” when switching from print to logging?

Python’s default logging threshold is WARNING. That means only WARNING, ERROR, and CRITICAL messages are emitted; DEBUG and INFO calls are filtered out. In the arithmetic example, logging.debug calls produce no console output until logging.basicConfig(level=logging.DEBUG) is set.

How does logging.basicConfig change where log messages go and how they’re recorded?

logging.basicConfig sets global logging behavior. Adding filename='test_log' routes output to a file instead of the console. Running the script again updates the same file, so earlier runs remain visible and new entries accumulate, enabling time-over-run tracking.

What’s the practical difference between changing the logging level in code vs. changing the logging call itself?

Changing the logging call from logging.debug to logging.warning changes the message’s severity category, but it still depends on the configured threshold. In the tutorial, switching debug calls to warning makes them appear under the default WARNING threshold; the more robust approach is configuring the threshold (e.g., level=logging.DEBUG) so the intended severities (DEBUG/INFO) are allowed through.

How can log output be reformatted to include only the most useful fields?

By adding a format=... argument to logging.basicConfig. The example uses logging “special values” to build a format string that includes human-readable time, the level name, and the message. After updating the format, the log file’s line structure changes accordingly (timestamp + level + message).

How does the Employee class example demonstrate logging in a real code path?

The Employee constructor originally used a print statement to announce instance creation. Replacing it with logging.info means those events are written to employee log instead of the console. With logging configured at level=logging.INFO and a custom format, each new Employee instance (e.g., employee 3) produces a corresponding INFO entry in the file.

Review Questions

  1. What happens to DEBUG and INFO log calls when logging.basicConfig is left at its default settings?
  2. How would you configure logging to write INFO and above messages to a file named app.log with a format that includes time and the message?
  3. Why can basic logging become problematic when multiple modules are imported into a larger project?

Key Points

  1. 1

    Python’s logging module is built in, so it can replace print statements without extra installation.

  2. 2

    Logging levels (DEBUG, INFO, WARNING, ERROR, CRITICAL) determine which messages are emitted based on the configured threshold.

  3. 3

    The default logging level is WARNING, so DEBUG and INFO messages are ignored unless the threshold is lowered.

  4. 4

    logging.basicConfig can send logs to a file using the filename parameter, enabling persistent records across runs.

  5. 5

    A format string in logging.basicConfig lets developers control what fields appear in each log line (e.g., time, level name, message).

  6. 6

    In small scripts, basic logging is sufficient, but multi-module applications often require separate loggers and handlers to avoid conflicts.

Highlights

Default logging only outputs WARNING and higher, so logging.debug and logging.info won’t show up until the threshold is changed.
Adding filename='test_log' turns transient console output into an accumulating audit trail across multiple script runs.
A custom format string can reshape log lines to include exactly the fields needed—like timestamp, level name, and message.
Replacing a print inside a class constructor with logging.info records object-creation events in a dedicated log file without console noise.

Topics

  • Logging Levels
  • logging.basicConfig
  • File Logging
  • Log Formatting
  • Python Logging

Mentioned