Ad – 728Γ—90
πŸ“‹ Real-World

Python Logging – logging Module & Best Practices

Print statements break in production. Python's built-in logging module provides levels, formatting, file output, and rotation β€” everything needed to debug and monitor real applications.

⏱️ 20 min read🎯 Real-WorldπŸ“… Updated 2026

Basic Setup

Python
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)

logger = logging.getLogger(__name__)
logger.debug("Diagnostic info")
logger.info("Normal event")
logger.warning("Unexpected but non-fatal")
logger.error("Something failed")
logger.critical("System cannot continue")

File & Rotating Handlers

Python
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)

fmt = logging.Formatter("%(asctime)s | %(levelname)-8s | %(name)s:%(lineno)d | %(message)s")

console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(fmt)

# Rotate at 5 MB, keep 3 backups
file_h = RotatingFileHandler("app.log", maxBytes=5_000_000, backupCount=3)
file_h.setLevel(logging.DEBUG)
file_h.setFormatter(fmt)

logger.addHandler(console)
logger.addHandler(file_h)

Structured JSON Logging

Python
import json

class JSONFormatter(logging.Formatter):
    def format(self, record):
        entry = {
            "time": self.formatTime(record),
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
        }
        if record.exc_info:
            entry["exception"] = self.formatException(record.exc_info)
        return json.dumps(entry)

handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger("api").addHandler(handler)

Logging Exceptions

Python
try:
    result = 10 / 0
except ZeroDivisionError:
    logger.exception("Division failed")  # Auto-includes traceback

logger.info("User login", extra={"user_id": 42, "ip": "127.0.0.1"})
Tip: Use logging.getLogger(__name__) in every module β€” creates a hierarchy so you can control log levels per module.