Logging is used to record events that happen when a program runs. These events may include information messages, warnings, errors, and debugging details. Logging helps developers understand the flow of execution, track issues, and maintain applications. It is a better alternative to using print() because logging provides levels, formatting, timestamps, and can store logs in files.
Python’s built-in logging module provides a flexible framework for adding log messages to programs.
The logging module is essential for:
Logs help identify what happened and when it happened, especially in large applications.
The simplest way to log messages is by calling the logging functions directly.
import logging
logging.warning("This is a warning")
logging.error("This is an error")
logging.info("Information message")
Output:
WARNING:root:This is a warning
ERROR:root:This is an error
By default, only WARNING and above are shown. INFO is ignored unless the configuration changes.
Python defines multiple levels of severity for log messages.
| Level | Description |
|---|---|
| DEBUG | Detailed information for debugging |
| INFO | General events and progress |
| WARNING | Something unexpected but recoverable |
| ERROR | Serious issue; function failed |
| CRITICAL | Severe error; program may stop |
Higher numbers represent higher severity.
To show all logs, including INFO and DEBUG, configure the logging level.
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("Debug message")
logging.info("Information")
logging.warning("Warning")
Output:
DEBUG:root:Debug message
INFO:root:Information
WARNING:root:Warning
basicConfig() must be called before logging messages.
Custom formatting makes logs more readable.
import logging logging.basicConfig( format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO ) import logging
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(message)s",
level=logging.INFO
)logging.info("Application started")
Output:
2025-03-30 11:24:10,245 - INFO - Application started
| Variable | Meaning |
|---|---|
| %(asctime)s | Timestamp |
| %(levelname)s | Log level |
| %(message)s | Log message |
| %(name)s | Logger name |
| %(lineno)d | Line number |
Instead of printing logs to the console, logs can be stored in a file.
import logging
logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)logging.info("Logging to a file")
Output inside app.log:
2025-03-30 11:30:15,450 - INFO - Logging to a file
This is commonly used in production systems.
Custom loggers allow more control, especially in large applications.
import logging
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)handler = logging.FileHandler("myapp.log")
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)logger.addHandler(handler)
logger.debug("Debug message from custom logger")
logger.error("Error occurred")
Output inside myapp.log:
DEBUG - Debug message from custom logger
ERROR - Error occurred
When errors occur, logging can capture them with full stack traces.
This is better than printing exceptions manually.
import logging
logging.basicConfig(level=logging.ERROR)
try:
x = 10 / 0
except Exception as e:
logging.exception("Exception occurred")
Output:
ERROR:root:Exception occurred
Traceback (most recent call last):
File "<script>", line 5, in <module>
ZeroDivisionError: division by zero
A common scenario is logging to both console and a file.
import logging
logger = logging.getLogger("multi")
logger.setLevel(logging.DEBUG)file_handler = logging.FileHandler("multi.log")
console_handler = logging.StreamHandler()formatter = logging.Formatter("%(levelname)s - %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)logger.addHandler(file_handler)
logger.addHandler(console_handler)logger.info("Logged in two places")
Output in Console:
INFO - Logged in two places
Output in multi.log:
INFO - Logged in two places
Large applications generate large logs.
logging.handlers module supports rotating logs automatically.
import logging
from logging.handlers import RotatingFileHandlerhandler = RotatingFileHandler("rotate.log", maxBytes=2000, backupCount=5)
logging.basicConfig(
handlers=[handler],
level=logging.INFO,
format="%(asctime)s - %(message)s"
)for i in range(1000):
logging.info("Logging line number %d", i)
This creates multiple logs when file size exceeds 2000 bytes.