Advertisement
Most developers don't think about logs until something breaks. Maybe the app crashes or a bug shows up without a clear trace. Logs give you a snapshot of what was happening under the hood. In real projects, this can save hours of digging. But logging isn't about tossing in print statements.
It's about sending structured messages with a purpose. Python logging lets you do that straight from the standard library. No extra tools needed. But to get value from it, you need to set it up with intention, not just flip a switch.
Many beginners start with logging.basicConfig() and think that’s all there is. That gets the job done for simple scripts, but the logging module offers more control. You can define custom outputs, formats, and even multiple destinations depending on how serious the message is.
Python logging works around four main parts: loggers, handlers, formatters, and levels. A logger sends the message. A handler decides where it goes—file, console, etc. A formatter defines what the message looks like. The level shows how serious the message is: debug, info, warning, error, or critical.
Here’s a quick example:
python
CopyEdit
import logging
logging.basicConfig(
filename='app.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.info("Application started")
This saves messages to a file with time, level, and the message itself. You can adjust the level to get more or less detail. Use debugging for development and warnings or higher in production.
But for larger applications, basicConfig() won’t cut it. You'll want custom loggers with separate handlers and formats, especially when logs need to go to different places or follow different rules.
Log levels define how serious a message is. DEBUG is the most detailed, meant for internal checks during development. INFO tells you what’s happening at a high level. WARNING flags something odd but not broken. ERROR means something failed, but the app is still running. CRITICAL means total failure.
Filtering by level lets you ignore less important logs when you don’t need them. In production, you might only want warnings and above. In development, you probably want everything.
Handlers let you decide where the logs go. You can write to files, send messages to the screen, or even push them to an external server. You can use more than one at the same time. One handler might write everything to a log file, while another just shows errors in the console.
Example with two handlers:
python
CopyEdit
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler('file.log')
console_handler = logging.StreamHandler()
file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_format = logging.Formatter('%(levelname)s - %(message)s')
file_handler.setFormatter(file_format)
console_handler.setFormatter(console_format)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
This way, your file has all the technical details, but the console only shows quick highlights. It keeps everything readable without losing important insights.
You're not locked into one global logger. In bigger projects, it's better to use named loggers for different sections of the app. That way, logs stay organized. You can give different loggers their formats, outputs, or importance levels.
Contextual logging is another powerful trick. If you’re handling a user request, you might want the user ID or session info to appear in every message. You can pass custom data using the extra argument:
python
CopyEdit
logger = logging.getLogger('web')
extra = {'user': 'user123'}
logger.info('Request received', extra=extra)
To make this work, your formatter needs to include %(user)s. You can also build filters that add data automatically. This makes your logs much more readable when tracking issues tied to individual users or events.
Another critical part of logging is exception handling. If you wrap risky code in try-except blocks, use logger.exception() to capture the full stack trace:
python
CopyEdit
try:
result = 10 / 0
except ZeroDivisionError:
logger.exception("Division failed")
Instead of just getting an error message, you’ll have a full traceback in the logs, which speeds up debugging.
When an app gets bigger, logs can easily become cluttered. Too many lines, repeated formats, or irrelevant details make them harder to read. That’s why it's useful to decide early what you really want to log and at what level. Being deliberate helps avoid unnecessary noise and keeps logs focused on what matters most.
Many third-party packages in Python use the logging module too. Their messages may appear alongside yours if you don’t isolate them. You can control this by adjusting their logger’s level or setting propagate to False to block upstream output.
Python’s built-in logging system can cover nearly all use cases. If you want extras—like log rotation, colorized output, or JSON logs—you can explore packages like loguru, structlog, or use logging.config.dictConfig to load structured setups from files or external configuration tools. This approach supports scalability in larger deployments.
But even without plugins, Python logging handles most real-world needs if configured smartly. It gives you control without complexity and allows teams to trace issues quickly across multiple environments.
Logging doesn’t have to be noisy or complicated. When set up right, it gives you a steady flow of useful feedback while keeping your app understandable and traceable.
Python logging gives you reliable tools to monitor and debug your code without adding extra libraries. When used correctly, it shows you what your program is doing and where things go wrong, without the clutter. Setting up clear log levels, adding custom loggers, and formatting messages properly make your logs more readable and useful. Exception logging and contextual data further improve traceability. Whether you're working on a small script or a full application, thoughtful logging keeps your code manageable. With the logging module, you're not guessing—you're watching your app work, one meaningful message at a time.
Advertisement
Explore the features, key benefits, and real-world use cases of ERP AI chatbots transforming modern enterprise workflows.
Explore core concepts of artificial neural network modeling and know how neural networks in AI systems power real‑world solutions
Explore real vs. perceived risks of AI beyond fear-mongering and media hype in this balanced, insightful analysis.
Want to run Auto-GPT on Ubuntu without Docker? This step-by-step guide shows you how to install Python, clone the repo, add your API key, and get it running in minutes
Discover the eight best AI-powered video production tools of 2025 to boost creativity, streamline editing, and save time.
What if your AI coding partner actually understood your project? See how Meta’s Code Llama 70B helps developers write smarter, cleaner, and more reliable code
Need smarter workflows in Google Sheets? Learn how to use GPT for Sheets and Docs to write, edit, summarize, and automate text with simple AI formulas
Understand how mixture-of-experts models work and why they're critical to the future of scalable AI systems.
Looking to edit music like a pro without being a composer? Discover Adobe’s Project Music GenAI Control, a tool that lets you create and tweak music tracks with simple commands and no re-rendering required
Want to launch surveys quickly? Learn how Survicate lets you create and customize surveys with ease, collecting valuable customer feedback without hassle
Trying to choose between ChatGPT and Google Bard? See how they compare for writing, research, real-time updates, and daily tasks—with clear pros and cons
Explore the modern AI evolution timeline and decade of AI technology progress, highlighting rapid AI development milestones