When you start learning programming, the print
function is often the first tool used to display output. However, as you transition to writing production-grade code, you’ll encounter the need for a more robust and flexible solution: logging. I discovered this firsthand when a pull request review highlighted the importance of using a logger instead of print
. Here’s what I learned about the differences between these tools and how to use them effectively.
An example of the difference
print(f"Processing file: {file_name}")
print(f"Error encountered: {error}")
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(processName)s[%(process)d] %(levelname)s %(name)s %(threadName)s: %(message)s',
handlers=[
logging.FileHandler("app.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
logger.info("Processing file: data.csv")
logger.error("Error encountered: File not found")
With the print you won’t have any difference between the Processing and the Error message while it’ll appear on the logger output
Processing file: data.csv
Error encountered: File not found
2025-01-10 14:30:45,123 MainProcess[12345] INFO myapp.processor MainThread: Processing file: data.csv
2025-01-10 14:30:45,124 MainProcess[12345] ERROR myapp.processor MainThread: Error encountered: File not found
When to Use print
The print
function is a straightforward way to display output to the console. It’s ideal for simple scripts or situations where minimal setup is needed.
Appropriate Use Cases
- Quick Debugging: When you’re testing small code snippets or debugging simple issues,
print
statements can help you quickly inspect variable values or the flow of execution. - Educational or Experimental Code: In tutorials, learning materials, or interactive sessions,
print
is often used for its simplicity. - User-Focused Output: If the output is intended directly for the user, such as in command-line interfaces or small scripts,
print
is appropriate (for example in ourHello, world!
context)
Limitations of print
- Lack of Control: You cannot easily suppress or redirect
print
output in a large application. - No Severity Levels: It doesn’t distinguish between different types of messages, such as errors or warnings.
- Not Scalable: For large or production-grade applications,
print
statements quickly become unmanageable.
When to Use logger
The logging
module in Python is designed for applications requiring robust and configurable message logging. It is highly flexible and can scale from small scripts to enterprise-level systems.
Appropriate Use Cases
- Production Applications: Loggers provide detailed, timestamped messages that are crucial for monitoring and debugging in production environments.
- Granular Message Control: Loggers support different levels of severity (DEBUG, INFO, WARNING, ERROR, CRITICAL), allowing you to filter and prioritize messages.
- Output Customization: Loggers can output to various destinations (console, files, external systems) and can be formatted with timestamps, log levels, and other metadata.
- Concurrent Applications: In multi-threaded or distributed applications, the
logging
module ensures thread-safe logging and can help trace complex workflows.
Advantages of logger
- Configurable: Loggers can be configured globally or locally with different handlers and formatters.
- Non-Intrusive: Logging can be enabled or disabled at runtime without altering the code.
- Scalable: Suitable for both small scripts and large, distributed systems.
Example: Setting Up a Logger
import logging
# Configure the logger
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("app.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# Using the logger
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning")
logger.error("This is an error")
logger.critical("This is critical")
Key Differences
Feature | print | logger |
---|---|---|
Severity Levels | None | DEBUG, INFO, WARNING, ERROR, CRITICAL |
Configuration | Minimal | Handlers, formatters, and runtime control |
Scalability | Limited | Scales Well |
Output Destinations | Console only | Console, files, external systems |
Thread Safety | No | Yes |
Best Practices
- Use
print
for quick debugging or simple scripts. - Switch to
logger
for production code, especially if the application needs robust monitoring or error tracking. - Avoid mixing
print
andlogger
in the same application unless there’s a clear distinction (e.g.,print
for user-facing output,logger
for diagnostics).
Conclusion
Embracing logging over print
is a hallmark of transitioning from beginner programming to writing professional, maintainable code. Start small by configuring a basic logger in your projects and gradually explore advanced features like multiple handlers and external integrations.