+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 272 of 365

๐Ÿ“˜ Logging Levels: DEBUG, INFO, WARNING

Master logging levels: debug, info, warning in Python with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿš€Intermediate
25 min read

Prerequisites

  • Basic understanding of programming concepts ๐Ÿ“
  • Python installation (3.8+) ๐Ÿ
  • VS Code or preferred IDE ๐Ÿ’ป

What you'll learn

  • Understand the concept fundamentals ๐ŸŽฏ
  • Apply the concept in real projects ๐Ÿ—๏ธ
  • Debug common issues ๐Ÿ›
  • Write clean, Pythonic code โœจ

๐ŸŽฏ Introduction

Welcome to this exciting tutorial on Python logging levels! ๐ŸŽ‰ In this guide, weโ€™ll explore how DEBUG, INFO, and WARNING levels can transform your debugging and monitoring experience.

Youโ€™ll discover how proper logging can be your secret weapon for understanding whatโ€™s happening inside your applications. Whether youโ€™re building web APIs ๐ŸŒ, automation scripts ๐Ÿค–, or data pipelines ๐Ÿ“Š, mastering logging levels is essential for creating maintainable and debuggable code.

By the end of this tutorial, youโ€™ll confidently use logging levels to track your applicationโ€™s behavior like a pro! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Logging Levels

๐Ÿค” What Are Logging Levels?

Logging levels are like different volumes on your stereo ๐ŸŽš๏ธ. Think of them as filters that control how much information your application shares with you - from whispers (DEBUG) to normal conversation (INFO) to loud warnings (WARNING).

In Python terms, logging levels help you categorize messages by importance and control what gets recorded. This means you can:

  • โœจ Debug issues with detailed trace information
  • ๐Ÿš€ Monitor normal application flow
  • ๐Ÿ›ก๏ธ Catch potential problems before they become errors

๐Ÿ’ก Why Use Logging Levels?

Hereโ€™s why developers love logging levels:

  1. Flexible Debugging ๐Ÿ”: Turn on DEBUG in development, off in production
  2. Performance Control โšก: Less logging = faster execution
  3. Organized Output ๐Ÿ“Š: Filter noise, focus on what matters
  4. Problem Detection ๐ŸŽฏ: Spot issues before users do

Real-world example: Imagine running an online store ๐Ÿ›’. With logging levels, you can track detailed payment processing in DEBUG mode during development, monitor successful orders with INFO in production, and get alerts for WARNING when inventory runs low!

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Simple Example

Letโ€™s start with a friendly example:

import logging

# ๐Ÿ‘‹ Hello, logging!
logging.basicConfig(level=logging.DEBUG)

# ๐ŸŽจ Creating different level messages
logging.debug("๐Ÿ” Detailed information for debugging")
logging.info("๐Ÿ“Š General information about program flow")
logging.warning("โš ๏ธ Something unexpected but not critical")

# ๐ŸŽฏ Real example with context
user_balance = 50
purchase_amount = 45

logging.info(f"๐Ÿ’ฐ User balance: ${user_balance}")
logging.debug(f"๐Ÿ›’ Attempting purchase of ${purchase_amount}")

if purchase_amount > user_balance * 0.9:
    logging.warning(f"โš ๏ธ User spending {purchase_amount/user_balance*100:.0f}% of balance!")

๐Ÿ’ก Explanation: Notice how each level serves a different purpose! DEBUG gives us the nitty-gritty details, INFO tracks normal operations, and WARNING alerts us to potential issues.

๐ŸŽฏ Common Patterns

Here are patterns youโ€™ll use daily:

# ๐Ÿ—๏ธ Pattern 1: Setting up a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# ๐ŸŽจ Pattern 2: Conditional logging
def process_order(order_id, amount):
    logger.info(f"๐Ÿ“ฆ Processing order {order_id}")
    logger.debug(f"๐Ÿ’ณ Payment amount: ${amount}")
    
    if amount > 1000:
        logger.warning(f"๐Ÿ’ฐ Large transaction detected: ${amount}")
    
    return f"Order {order_id} processed! โœ…"

# ๐Ÿ”„ Pattern 3: Dynamic level adjustment
def set_log_level(verbose=False):
    level = logging.DEBUG if verbose else logging.INFO
    logging.getLogger().setLevel(level)
    logger.info(f"๐Ÿ“Š Log level set to: {logging.getLevelName(level)}")

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: E-Commerce Order Processor

Letโ€™s build something real:

import logging
from datetime import datetime

# ๐Ÿ›๏ธ Set up our logger
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("OrderProcessor")

class OrderProcessor:
    def __init__(self):
        self.orders = []
        self.inventory = {"๐Ÿ• Pizza": 10, "๐Ÿ” Burger": 15, "๐Ÿฅค Soda": 20}
    
    # ๐Ÿ“ฆ Process an order
    def process_order(self, item, quantity, customer):
        logger.info(f"๐Ÿ“ฅ New order from {customer}")
        logger.debug(f"๐Ÿ” Order details: {quantity}x {item}")
        
        # Check inventory
        if item not in self.inventory:
            logger.warning(f"โš ๏ธ Unknown item requested: {item}")
            return False
        
        current_stock = self.inventory[item]
        logger.debug(f"๐Ÿ“Š Current stock for {item}: {current_stock}")
        
        if current_stock < quantity:
            logger.warning(f"๐Ÿšจ Low inventory! Only {current_stock} {item} left")
            return False
        
        # Process the order
        self.inventory[item] -= quantity
        order_id = len(self.orders) + 1
        self.orders.append({
            "id": order_id,
            "item": item,
            "quantity": quantity,
            "customer": customer,
            "timestamp": datetime.now()
        })
        
        logger.info(f"โœ… Order #{order_id} completed successfully!")
        
        # Check if we need to restock
        if self.inventory[item] < 5:
            logger.warning(f"๐Ÿ“ฆ Low stock alert: {item} down to {self.inventory[item]}")
        
        return True
    
    # ๐Ÿ“Š Get daily summary
    def daily_summary(self):
        logger.info("๐Ÿ“ˆ Generating daily summary...")
        logger.debug(f"๐Ÿ” Total orders processed: {len(self.orders)}")
        
        for item, stock in self.inventory.items():
            if stock < 5:
                logger.warning(f"โš ๏ธ Restock needed: {item} ({stock} remaining)")
            else:
                logger.debug(f"โœ… {item}: {stock} in stock")

# ๐ŸŽฎ Let's use it!
processor = OrderProcessor()

# Simulate some orders
processor.process_order("๐Ÿ• Pizza", 3, "Alice")
processor.process_order("๐Ÿ” Burger", 20, "Bob")  # This will fail
processor.process_order("๐Ÿ• Pizza", 8, "Charlie")  # This will trigger low stock

# Get summary
processor.daily_summary()

๐ŸŽฏ Try it yourself: Add a restock_item method that logs when items are restocked!

๐ŸŽฎ Example 2: Game Server Monitor

Letโ€™s make monitoring fun:

import logging
import random
import time

# ๐Ÿ† Game server monitoring system
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    datefmt='%H:%M:%S'
)

class GameServer:
    def __init__(self, name):
        self.name = name
        self.players = []
        self.cpu_usage = 20
        self.memory_usage = 30
        self.logger = logging.getLogger(f"GameServer-{name}")
    
    # ๐ŸŽฎ Player joins
    def player_join(self, player_name):
        self.players.append(player_name)
        self.logger.info(f"๐ŸŽฎ {player_name} joined the server!")
        self.logger.debug(f"๐Ÿ‘ฅ Total players: {len(self.players)}")
        
        # Simulate resource usage increase
        self.cpu_usage += random.randint(5, 10)
        self.memory_usage += random.randint(3, 7)
        
        self._check_resources()
    
    # ๐Ÿ‘‹ Player leaves
    def player_leave(self, player_name):
        if player_name in self.players:
            self.players.remove(player_name)
            self.logger.info(f"๐Ÿ‘‹ {player_name} left the server")
            
            # Resources go down
            self.cpu_usage = max(20, self.cpu_usage - random.randint(3, 8))
            self.memory_usage = max(30, self.memory_usage - random.randint(2, 5))
    
    # ๐Ÿ” Check server resources
    def _check_resources(self):
        self.logger.debug(f"๐Ÿ’ป CPU: {self.cpu_usage}% | RAM: {self.memory_usage}%")
        
        if self.cpu_usage > 80:
            self.logger.warning(f"๐Ÿ”ฅ High CPU usage: {self.cpu_usage}%!")
        
        if self.memory_usage > 75:
            self.logger.warning(f"๐Ÿ’พ High memory usage: {self.memory_usage}%!")
        
        if len(self.players) > 10:
            self.logger.warning(f"๐Ÿ‘ฅ Server getting crowded: {len(self.players)} players")
    
    # ๐Ÿ“Š Server status
    def status_report(self):
        self.logger.info(f"๐Ÿ“Š === {self.name} Status Report ===")
        self.logger.info(f"๐Ÿ‘ฅ Players online: {len(self.players)}")
        self.logger.debug(f"๐Ÿ‘ค Player list: {', '.join(self.players) if self.players else 'None'}")
        self.logger.info(f"๐Ÿ’ป CPU: {self.cpu_usage}% | RAM: {self.memory_usage}%")
        
        # Health check
        if self.cpu_usage < 60 and self.memory_usage < 60:
            self.logger.info("โœ… Server health: Excellent")
        elif self.cpu_usage < 80 and self.memory_usage < 75:
            self.logger.info("โšก Server health: Good")
        else:
            self.logger.warning("โš ๏ธ Server health: Needs attention")

# ๐ŸŽฎ Simulate game server activity
server = GameServer("DragonRealm")

# Players joining
players = ["Alice๐Ÿฆ„", "Bob๐Ÿ‰", "Charlieโš”๏ธ", "Diana๐Ÿน", "Eve๐Ÿง™โ€โ™€๏ธ"]
for player in players:
    server.player_join(player)
    time.sleep(0.5)  # Small delay for realistic logs

# Status check
server.status_report()

# Some players leave
server.player_leave("Bob๐Ÿ‰")
server.player_leave("Diana๐Ÿน")

# Final status
server.status_report()

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Topic 1: Custom Log Formatting

When youโ€™re ready to level up, try custom formatters:

import logging

# ๐ŸŽฏ Create a custom formatter with emojis
class EmojiFormatter(logging.Formatter):
    emoji_map = {
        logging.DEBUG: "๐Ÿ”",
        logging.INFO: "๐Ÿ“Š",
        logging.WARNING: "โš ๏ธ",
        logging.ERROR: "โŒ",
        logging.CRITICAL: "๐Ÿšจ"
    }
    
    def format(self, record):
        emoji = self.emoji_map.get(record.levelno, "๐Ÿ“")
        record.emoji = emoji
        return super().format(record)

# ๐Ÿช„ Set up the magical formatter
handler = logging.StreamHandler()
formatter = EmojiFormatter('%(emoji)s %(levelname)-8s | %(message)s')
handler.setFormatter(formatter)

logger = logging.getLogger("MagicalLogger")
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

# โœจ Test our magical logger
logger.debug("Finding the bug...")
logger.info("Process completed successfully")
logger.warning("Memory usage is getting high")

๐Ÿ—๏ธ Advanced Topic 2: Log Level Context Manager

For the brave developers:

import logging
from contextlib import contextmanager

# ๐Ÿš€ Temporary log level changer
@contextmanager
def log_level(logger, level):
    """Temporarily change log level - perfect for debugging! ๐ŸŽฏ"""
    old_level = logger.level
    logger.setLevel(level)
    logger.debug(f"๐Ÿ”„ Switching log level to {logging.getLevelName(level)}")
    try:
        yield logger
    finally:
        logger.setLevel(old_level)
        logger.debug(f"๐Ÿ”„ Restored log level to {logging.getLevelName(old_level)}")

# ๐Ÿ’ก Usage example
logger = logging.getLogger("SmartLogger")
logger.setLevel(logging.INFO)

logger.info("๐Ÿ“Š Normal operation mode")
logger.debug("๐Ÿ” This won't show (level is INFO)")

# Temporarily enable DEBUG for troubleshooting
with log_level(logger, logging.DEBUG):
    logger.debug("๐Ÿ” Now I can see debug messages!")
    logger.info("๐Ÿ“Š Info still works too")

logger.debug("๐Ÿ” Back to being invisible")

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Print vs Logging

# โŒ Wrong way - using print for debugging
def calculate_discount(price, percentage):
    print(f"Calculating discount for ${price}")  # ๐Ÿ˜ฐ No control!
    discount = price * (percentage / 100)
    print(f"Discount amount: ${discount}")
    return price - discount

# โœ… Correct way - using proper logging
import logging
logger = logging.getLogger(__name__)

def calculate_discount(price, percentage):
    logger.debug(f"๐Ÿงฎ Calculating {percentage}% discount for ${price}")
    discount = price * (percentage / 100)
    logger.info(f"๐Ÿ’ฐ Applied discount: ${discount:.2f}")
    return price - discount

๐Ÿคฏ Pitfall 2: Wrong Level Selection

# โŒ Dangerous - using wrong levels
logger.debug("โŒ User password incorrect!")  # Too low level for security!
logger.warning("๐Ÿ“Š Processing order #12345")  # Not a warning!
logger.info("๐Ÿšจ SYSTEM CRASH IMMINENT")  # Should be CRITICAL!

# โœ… Safe - appropriate level usage
logger.warning("โš ๏ธ Failed login attempt for user 'admin'")
logger.info("๐Ÿ“ฆ Processing order #12345")
logger.critical("๐Ÿšจ Database connection lost!")
logger.debug("๐Ÿ” Checking cache for user_id=42")

๐Ÿ› ๏ธ Best Practices

  1. ๐ŸŽฏ Choose Wisely: DEBUG for development details, INFO for flow, WARNING for issues
  2. ๐Ÿ“ Be Descriptive: Include context in your messages
  3. ๐Ÿ›ก๏ธ Security First: Never log sensitive data (passwords, tokens)
  4. ๐ŸŽจ Stay Consistent: Use the same format across your app
  5. โœจ Performance Aware: DEBUG logging can slow things down

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Weather Station Monitor

Create a logging system for a weather station:

๐Ÿ“‹ Requirements:

  • โœ… Log temperature readings (INFO level)
  • ๐ŸŒก๏ธ Warn when temperature exceeds thresholds
  • ๐Ÿ’จ Debug wind speed calculations
  • ๐ŸŒง๏ธ Track rainfall with appropriate levels
  • ๐Ÿ“Š Generate hourly summaries

๐Ÿš€ Bonus Points:

  • Add custom formatter for weather emojis
  • Implement log rotation for daily files
  • Create alert system for extreme weather

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
import logging
import random
from datetime import datetime

# ๐ŸŽฏ Our weather station monitoring system!
class WeatherStation:
    def __init__(self, location):
        self.location = location
        self.logger = self._setup_logger()
        self.readings = []
        
    def _setup_logger(self):
        """Set up logger with custom formatting ๐ŸŽจ"""
        logger = logging.getLogger(f"WeatherStation-{self.location}")
        logger.setLevel(logging.DEBUG)
        
        # Console handler with custom format
        handler = logging.StreamHandler()
        formatter = logging.Formatter(
            '%(asctime)s | %(name)s | %(levelname)s | %(message)s',
            datefmt='%H:%M:%S'
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        
        return logger
    
    def read_temperature(self):
        """Read temperature sensor ๐ŸŒก๏ธ"""
        temp = random.uniform(15, 35)
        self.logger.info(f"๐ŸŒก๏ธ Temperature: {temp:.1f}ยฐC")
        
        # Check thresholds
        if temp > 30:
            self.logger.warning(f"๐Ÿ”ฅ High temperature alert: {temp:.1f}ยฐC")
        elif temp < 18:
            self.logger.warning(f"โ„๏ธ Low temperature alert: {temp:.1f}ยฐC")
        
        return temp
    
    def read_wind_speed(self):
        """Read wind speed sensor ๐Ÿ’จ"""
        base_speed = random.uniform(5, 25)
        gust_factor = random.uniform(0.8, 1.5)
        
        self.logger.debug(f"๐Ÿ” Base wind speed: {base_speed:.1f} km/h")
        self.logger.debug(f"๐Ÿ” Gust factor: {gust_factor:.2f}")
        
        actual_speed = base_speed * gust_factor
        self.logger.info(f"๐Ÿ’จ Wind speed: {actual_speed:.1f} km/h")
        
        if actual_speed > 30:
            self.logger.warning(f"๐ŸŒช๏ธ Strong wind warning: {actual_speed:.1f} km/h")
        
        return actual_speed
    
    def read_rainfall(self):
        """Read rainfall sensor ๐ŸŒง๏ธ"""
        rainfall = random.uniform(0, 10)
        self.logger.info(f"๐ŸŒง๏ธ Rainfall: {rainfall:.1f} mm")
        
        if rainfall > 5:
            self.logger.warning(f"โ˜” Heavy rain alert: {rainfall:.1f} mm")
        
        return rainfall
    
    def collect_reading(self):
        """Collect all sensor readings ๐Ÿ“Š"""
        self.logger.debug("๐Ÿ“ก Starting sensor collection...")
        
        reading = {
            "timestamp": datetime.now(),
            "temperature": self.read_temperature(),
            "wind_speed": self.read_wind_speed(),
            "rainfall": self.read_rainfall()
        }
        
        self.readings.append(reading)
        self.logger.debug("โœ… Sensor collection complete")
        
        return reading
    
    def hourly_summary(self):
        """Generate hourly weather summary ๐Ÿ“ˆ"""
        self.logger.info("๐Ÿ“Š === Hourly Weather Summary ===")
        
        if not self.readings:
            self.logger.warning("โš ๏ธ No readings available for summary")
            return
        
        # Calculate averages
        avg_temp = sum(r["temperature"] for r in self.readings) / len(self.readings)
        avg_wind = sum(r["wind_speed"] for r in self.readings) / len(self.readings)
        total_rain = sum(r["rainfall"] for r in self.readings)
        
        self.logger.info(f"๐ŸŒก๏ธ Average temperature: {avg_temp:.1f}ยฐC")
        self.logger.info(f"๐Ÿ’จ Average wind speed: {avg_wind:.1f} km/h")
        self.logger.info(f"๐ŸŒง๏ธ Total rainfall: {total_rain:.1f} mm")
        
        # Weather assessment
        if avg_temp > 28 and total_rain < 1:
            self.logger.warning("โ˜€๏ธ Hot and dry conditions - fire risk!")
        elif avg_wind > 25 and total_rain > 5:
            self.logger.warning("โ›ˆ๏ธ Stormy conditions detected!")
        else:
            self.logger.info("โœ… Weather conditions: Normal")

# ๐ŸŽฎ Test our weather station!
station = WeatherStation("Tokyo")

# Simulate hourly readings
for i in range(5):
    station.logger.info(f"๐Ÿ“ก Reading #{i+1}")
    station.collect_reading()
    
# Generate summary
station.hourly_summary()

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much! Hereโ€™s what you can now do:

  • โœ… Use logging levels appropriately (DEBUG, INFO, WARNING) ๐Ÿ’ช
  • โœ… Replace print statements with proper logging ๐Ÿ›ก๏ธ
  • โœ… Design logging strategies for real applications ๐ŸŽฏ
  • โœ… Debug issues with the right level of detail ๐Ÿ›
  • โœ… Monitor applications like a pro! ๐Ÿš€

Remember: Good logging is like having a conversation with your future self - make it clear and helpful! ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered Python logging levels!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Practice with the weather station exercise
  2. ๐Ÿ—๏ธ Add logging to your existing projects
  3. ๐Ÿ“š Explore ERROR and CRITICAL levels in our next tutorial
  4. ๐ŸŒŸ Share your logging best practices with your team!

Remember: Every debugging session becomes easier with good logging. Keep learning, keep logging, and most importantly, have fun! ๐Ÿš€


Happy coding! ๐ŸŽ‰๐Ÿš€โœจ