Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • 📝 Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • 📝 Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • 📝 Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • 📝 Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • 📝 While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • 📝 For Each Assignments
    • 📝 All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • 📝 Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • 📝 Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • 📝 Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • 📝 Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • 📝 Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • 📝 Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • 📝 Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • 📝 Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • 📝 Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • 📝 Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • 📝 Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • 📝 Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • 📝 Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • 📝 Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • 📝 Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • 📝 Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • 📝 Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • 📝 Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • 📝 Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Logging

Python Logging - Complete Guide

Track what's happening in your code with proper logging.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
On this page:
  • What is Logging?
  • Why Use Logging?
  • Log Levels
  • Basic Logging
  • Advanced Logging
  • Real-World Example
  • Best Practices
  • Try It Yourself
  • Quick Quiz
  • Frequently Asked Questions
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • What is logging — tracking events in your code
  • Why use logging — better than print statements
  • Log levels — DEBUG, INFO, WARNING, ERROR, CRITICAL
  • Basic logging — getting started quickly
  • Advanced logging — handlers, formatters, filters
  • Real-world examples — logging in applications

What is Logging?

Logging is the practice of recording events that happen in your program. It's like keeping a diary of what your code does — when it starts, what it processes, if there are errors, and when it finishes.

Think of logging like a flight recorder in an airplane. It records everything that happens during the flight. If something goes wrong, you can look at the logs to figure out what happened. Logging works the same way for your code.

Python has a built-in logging module that's much better than using print() statements for debugging.

💡 Key concept: Logging is a way to record events in your program for debugging, monitoring, and troubleshooting.

Why Use Logging?

1

Logging vs Print

Logging is much better than using print() for debugging. Here's why.

# Why Use Logging?

print("=" * 50)
print("WHY USE LOGGING?")
print("=" * 50)

# ============================================================
# USING PRINT - Problems
# ============================================================

print("\n1. USING PRINT")

print("""
def calculate_order(items, tax_rate):
    print("Starting calculate_order")  # Debug print
    total = sum(items)
    print(f"Subtotal: {total}")         # Debug print
    tax = total * tax_rate
    print(f"Tax: {tax}")                # Debug print
    final = total + tax
    print(f"Final: {final}")            # Debug print
    return final

# Problems:
# - Print statements everywhere
# - Hard to turn off
# - No timestamp
# - No log levels
# - Can't filter by level
# - Can't easily write to files
""")


# ============================================================
# USING LOGGING - Better
# ============================================================

print("\n2. USING LOGGING")

print("""
import logging

logging.basicConfig(level=logging.INFO)

def calculate_order(items, tax_rate):
    logging.info("Starting calculate_order")
    total = sum(items)
    logging.debug(f"Subtotal: {total}")  # Won't show at INFO level
    tax = total * tax_rate
    logging.info(f"Tax: {tax}")
    final = total + tax
    logging.info(f"Final: {final}")
    return final

# Benefits:
# - Log levels (DEBUG, INFO, WARNING, ERROR)
# - Easy to configure
# - Can write to files
# - Timestamps
# - Can be disabled without removing code
# - Different outputs (console, file, email)
""")


# ============================================================
# BENEFITS SUMMARY
# ============================================================

print("\n" + "-" * 30)
print("BENEFITS OF LOGGING")
print("-" * 30)
print("""
- Log levels for different severity
- Timestamps automatically added
- Can write to files, console, or network
- Can be configured without changing code
- Better than print for production code
- Can filter messages by level
- Thread-safe
- Can include stack traces for errors
""")

Benefits of logging:

  • Log levels — control what gets logged
  • Timestamps — know when events happened
  • Multiple outputs — console, file, network
  • Configurable — change without modifying code
  • Better than print — more control and flexibility

Quick Check: Why is logging better than using print? (Answer: Logging has levels, timestamps, multiple outputs, and is configurable)

Log Levels

2

Different Levels for Different Situations

Python logging has five standard levels. Each level represents a different severity.

# Log Levels

print("=" * 50)
print("LOG LEVELS")
print("=" * 50)

# ============================================================
# FIVE STANDARD LEVELS
# ============================================================

print("\n1. FIVE STANDARD LEVELS")

print("""
┌─────────────┬─────────────────────────────────────────────────────┐
│ Level       │ When to use                                        │
├─────────────┼─────────────────────────────────────────────────────┤
│ DEBUG       │ Detailed information for debugging                 │
│ INFO        │ Confirmation that things are working as expected   │
│ WARNING     │ Something unexpected happened (still working)     │
│ ERROR       │ A problem occurred (function couldn't complete)    │
│ CRITICAL    │ A serious error (program might crash)              │
└─────────────┴─────────────────────────────────────────────────────┘
""")


# ============================================================
# USING LOG LEVELS
# ============================================================

print("\n2. USING LOG LEVELS")

print("""
import logging

# Set the minimum level to show
logging.basicConfig(level=logging.INFO)

# Different log levels
logging.debug("Debug message - for development")
logging.info("Info message - normal operation")
logging.warning("Warning message - something unexpected")
logging.error("Error message - a problem occurred")
logging.critical("Critical message - serious error")

# With INFO level, only INFO and above are shown:
# INFO, WARNING, ERROR, CRITICAL
# DEBUG is hidden
""")


# ============================================================
# SETTING LOG LEVEL
# ============================================================

print("\n3. SETTING LOG LEVEL")

print("""
# Set to DEBUG - show everything
logging.basicConfig(level=logging.DEBUG)

# Set to ERROR - only show errors and critical
logging.basicConfig(level=logging.ERROR)

# Set to WARNING - show warnings and above
logging.basicConfig(level=logging.WARNING)

# In code:
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)  # Set for a specific logger
""")


# ============================================================
# NUMERIC VALUES
# ============================================================

print("\n4. NUMERIC VALUES")

print("""
┌─────────────┬─────────┐
│ Level       │ Value   │
├─────────────┼─────────┤
│ DEBUG       │ 10      │
│ INFO        │ 20      │
│ WARNING     │ 30      │
│ ERROR       │ 40      │
│ CRITICAL    │ 50      │
└─────────────┴─────────┘

Higher values = more severe
A level of 20 (INFO) shows messages with value >= 20
""")

Log levels key points:

  • DEBUG — detailed info for debugging
  • INFO — normal operation
  • WARNING — something unexpected
  • ERROR — problem occurred
  • CRITICAL — serious error

Quick Check: Which log level is the most severe? (Answer: CRITICAL)

Basic Logging

3

Getting Started with Logging

The simplest way to use logging is with logging.basicConfig() and the module-level functions.

# Basic Logging

print("=" * 50)
print("BASIC LOGGING")
print("=" * 50)

# ============================================================
# SIMPLE LOGGING SETUP
# ============================================================

print("\n1. SIMPLE LOGGING SETUP")

print("""
import logging

# Basic configuration
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# Log messages
logging.info("Application started")
logging.warning("Low disk space")
logging.error("Connection failed")
""")


# ============================================================
# LOGGING EXAMPLES
# ============================================================

print("\n2. LOGGING EXAMPLES")

import logging

# Configure logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

print("   Logging configured with DEBUG level")

# Log messages
logging.debug("This is a debug message")
logging.info("This is an info message")
logging.warning("This is a warning message")
logging.error("This is an error message")
logging.critical("This is a critical message")

print("   Logs printed with timestamps and levels")


# ============================================================
# LOGGING CONFIGURATION OPTIONS
# ============================================================

print("\n3. LOGGING CONFIGURATION OPTIONS")

print("""
# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    filename='app.log',  # Write to file instead of console
    filemode='w'         # 'w' = overwrite, 'a' = append
)

# Without filename, logs go to console
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
""")

# ============================================================
# FORMAT ATTRIBUTES
# ============================================================

print("\n4. FORMAT ATTRIBUTES")

print("""
Common format attributes:
    %(asctime)s  - Time of the log message
    %(levelname)s - Log level name (INFO, ERROR, etc.)
    %(name)s     - Logger name
    %(message)s  - The log message
    %(filename)s - Source file name
    %(lineno)d   - Line number
    %(funcName)s - Function name
    %(pathname)s - Full path of source file
    %(process)d  - Process ID
    %(thread)d   - Thread ID

Example format:
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    '2024-01-15 10:30:45 - root - INFO - Application started'
""")

Basic logging key points:

  • basicConfig() — configure logging once
  • level — set minimum level to show
  • format — customize log message format
  • filename — write logs to a file

Quick Check: What function do you use to configure logging? (Answer: logging.basicConfig())

Advanced Logging

4

Handlers, Formatters, and Filters

Advanced logging lets you send logs to multiple places and customize the format.

# Advanced Logging

print("=" * 50)
print("ADVANCED LOGGING")
print("=" * 50)

# ============================================================
# LOGGERS, HANDLERS, FORMATTERS
# ============================================================

print("\n1. LOGGERS, HANDLERS, FORMATTERS")

print("""
Components of logging:
    1. Logger - The object that creates log messages
    2. Handler - Sends log messages to a destination (console, file, email)
    3. Formatter - Defines the format of log messages
    4. Filter - Controls which messages are logged

Example:
    logger = logging.getLogger('my_app')
    
    # Console handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    
    # File handler
    file_handler = logging.FileHandler('app.log')
    file_handler.setLevel(logging.DEBUG)
    
    # Formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    file_handler.setFormatter(formatter)
    
    # Add handlers to logger
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
""")


# ============================================================
# MULTIPLE HANDLERS
# ============================================================

print("\n2. MULTIPLE HANDLERS")

print("""
import logging

# Create logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)

# Console handler
console = logging.StreamHandler()
console.setLevel(logging.INFO)

# File handler
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.DEBUG)

# Formatter
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console.setFormatter(formatter)
file_handler.setFormatter(formatter)

# Add handlers
logger.addHandler(console)
logger.addHandler(file_handler)

# Now logs go to both console and file
logger.info("This goes to console and file")
logger.debug("This only goes to file (DEBUG is below INFO)")
""")


# ============================================================
# LOGGING EXCEPTIONS
# ============================================================

print("\n3. LOGGING EXCEPTIONS")

print("""
import logging

logging.basicConfig(level=logging.ERROR)

try:
    result = 10 / 0
except ZeroDivisionError:
    # Log the exception with full traceback
    logging.exception("Division by zero occurred")

# Output:
# ERROR:root:Division by zero occurred
# Traceback (most recent call last):
#   File "", line 2, in 
# ZeroDivisionError: division by zero
""")


# ============================================================
# LOGGING EXCEPTIONS WITH CUSTOM MESSAGE
# ============================================================

print("\n4. LOGGING EXCEPTIONS WITH CUSTOM MESSAGE")

print("""
try:
    result = 10 / 0
except ZeroDivisionError as e:
    logging.error(f"Failed to calculate: {e}", exc_info=True)
    # Same as logging.exception()

# With custom message:
try:
    result = 10 / 0
except ZeroDivisionError:
    logging.error("A division by zero error occurred", exc_info=True)
""")


# ============================================================
# LOGGER HIERARCHY
# ============================================================

print("\n5. LOGGER HIERARCHY")

print("""
import logging

# Root logger (used by logging.info(), etc.)
# Child loggers inherit from parent

# Create a logger with a name
logger = logging.getLogger(__name__)  # '__main__' or module name

# Child logger
child_logger = logging.getLogger(__name__ + '.child')

# If parent has a handler, child inherits it
# But child can also have its own handlers

# Set levels separately
logger.setLevel(logging.INFO)
child_logger.setLevel(logging.DEBUG)

# Use the logger
logger.info("Parent logger")
child_logger.debug("Child logger - debug")
""")

# ============================================================
# SUMMARY
# ============================================================

print("\n6. SUMMARY")

print("""
┌─────────────────────┬────────────────────────────────────────────┐
│ Component           │ Purpose                                    │
├─────────────────────┼────────────────────────────────────────────┤
│ Logger              │ Creates log messages                       │
│ Handler             │ Sends logs to destination                  │
│ Formatter           │ Formats log messages                       │
│ Filter              │ Filters which logs to include              │
│ Level               │ Controls severity threshold                │
└─────────────────────┴────────────────────────────────────────────┘
""")

Advanced logging key points:

  • Logger — creates log messages
  • Handler — sends logs to destinations
  • Formatter — formats log messages
  • exception() — logs exceptions with traceback

Quick Check: What function logs an exception with traceback? (Answer: logging.exception())

Real-World Example

5

Building a Web Application Logger

# Real-World Example: Web Application Logger

import logging
from datetime import datetime
import os

print("=" * 60)
print("WEB APPLICATION LOGGER")
print("=" * 60)

# ============================================================
# LOGGER CONFIGURATION
# ============================================================

def setup_logger():
    """Set up logging for the application"""
    
    # Create logs directory if it doesn't exist
    if not os.path.exists('logs'):
        os.makedirs('logs')
    
    # Create logger
    logger = logging.getLogger('webapp')
    logger.setLevel(logging.DEBUG)
    
    # Clear existing handlers
    logger.handlers.clear()
    
    # Format for console
    console_format = logging.Formatter(
        '%(asctime)s - %(levelname)s - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    
    # Format for file (more detailed)
    file_format = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    
    # Console handler
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(console_format)
    
    # File handler - all logs
    file_all = logging.FileHandler('logs/app.log')
    file_all.setLevel(logging.DEBUG)
    file_all.setFormatter(file_format)
    
    # File handler - errors only
    file_error = logging.FileHandler('logs/errors.log')
    file_error.setLevel(logging.ERROR)
    file_error.setFormatter(file_format)
    
    # Add handlers
    logger.addHandler(console)
    logger.addHandler(file_all)
    logger.addHandler(file_error)
    
    return logger

# ============================================================
# WEB APPLICATION SIMULATION
# ============================================================

class WebApp:
    """Simulate a web application with logging"""
    
    def __init__(self):
        self.logger = setup_logger()
        self.logger.info("Application starting up...")
    
    def handle_request(self, endpoint, user_id, data=None):
        """Handle a request with logging"""
        self.logger.info(f"Request received: {endpoint} from user {user_id}")
        
        try:
            if endpoint == "/login":
                result = self.login(user_id, data)
            elif endpoint == "/profile":
                result = self.get_profile(user_id)
            elif endpoint == "/update":
                result = self.update_profile(user_id, data)
            else:
                result = {"error": "Unknown endpoint"}
            
            self.logger.info(f"Request completed: {endpoint} (status: {result.get('status', 'unknown')})")
            return result
            
        except Exception as e:
            self.logger.error(f"Error processing request: {e}", exc_info=True)
            return {"error": str(e)}
    
    def login(self, user_id, data):
        """Login user"""
        self.logger.debug(f"Login attempt for user {user_id}")
        
        if not data or 'password' not in data:
            self.logger.warning(f"Login failed: missing password for user {user_id}")
            return {"status": "failed", "reason": "Missing password"}
        
        if user_id == 1 and data.get('password') == 'secret':
            self.logger.info(f"User {user_id} logged in successfully")
            return {"status": "success", "user": {"id": user_id, "name": "Admin"}}
        else:
            self.logger.warning(f"Login failed: invalid credentials for user {user_id}")
            return {"status": "failed", "reason": "Invalid credentials"}
    
    def get_profile(self, user_id):
        """Get user profile"""
        self.logger.debug(f"Fetching profile for user {user_id}")
        
        if user_id == 1:
            return {"status": "success", "user": {"id": 1, "name": "Admin", "email": "admin@example.com"}}
        else:
            self.logger.warning(f"Profile not found for user {user_id}")
            return {"status": "failed", "reason": "User not found"}
    
    def update_profile(self, user_id, data):
        """Update user profile"""
        self.logger.debug(f"Updating profile for user {user_id}")
        
        if not data:
            self.logger.warning(f"Update failed: no data for user {user_id}")
            return {"status": "failed", "reason": "No data provided"}
        
        if user_id == 1:
            self.logger.info(f"Profile updated for user {user_id}: {data}")
            return {"status": "success", "message": "Profile updated"}
        else:
            self.logger.warning(f"Update failed: user {user_id} not authorized")
            return {"status": "failed", "reason": "Not authorized"}


# ============================================================
# DEMONSTRATION
# ============================================================

print("\n1. CREATING APPLICATION")
app = WebApp()
print("   Application started with logging")

print("\n2. HANDLING REQUESTS")
print("   Login successful:")
result = app.handle_request("/login", 1, {"password": "secret"})
print(f"      {result}")

print("\n   Login failed:")
result = app.handle_request("/login", 2, {"password": "wrong"})
print(f"      {result}")

print("\n   Get profile:")
result = app.handle_request("/profile", 1)
print(f"      {result}")

print("\n   Update profile:")
result = app.handle_request("/update", 1, {"email": "new@example.com"})
print(f"      {result}")

print("\n   Unknown endpoint:")
result = app.handle_request("/unknown", 1)
print(f"      {result}")

print("\n3. LOG FILES CREATED")
print("   - logs/app.log (all logs)")
print("   - logs/errors.log (errors only)")
print("   Check these files for complete logs")

print("\n" + "=" * 60)
print("KEY TAKEAWAYS:")
print("=" * 60)
print("""
- Use different log levels for different severity
- Log both success and failure cases
- Log exceptions with traceback
- Use separate files for different log levels
- Include timestamps and context
- Log enough detail to debug issues
""")

Real-world example key points:

  • Multiple handlers — console, all logs, errors only
  • Different formats — console vs file
  • Log levels — debug, info, warning, error
  • Exception logging — log errors with traceback
  • Log files — separate files for different purposes

Quick Check: Why would you use separate files for different log levels? (Answer: To separate normal logs from errors for easier troubleshooting)

Best Practices

6

Logging Best Practices

# Best Practices for Logging

print("=" * 60)
print("BEST PRACTICES FOR LOGGING")
print("=" * 60)

# ============================================================
# 1. USE THE RIGHT LOG LEVEL
# ============================================================

print("\n1. USE THE RIGHT LOG LEVEL")

print("""
# Good - appropriate levels
logger.debug("Processing item #123")        # Development details
logger.info("User alice logged in")        # Normal operations
logger.warning("Disk usage at 85%")         # Something to watch
logger.error("Failed to save file: permission denied")  # Error
logger.critical("Database connection lost") # Critical failure

# Bad - wrong levels
logger.info("This is a detailed debug message")  # Should be DEBUG
logger.debug("Failed to connect to API")         # Should be ERROR
logger.error("Starting application")              # Should be INFO
""")


# ============================================================
# 2. INCLUDE CONTEXT
# ============================================================

print("\n2. INCLUDE CONTEXT")

print("""
# Good - includes context
logger.error(f"User {user_id} failed to update profile: {error}")

# Better - includes timestamp, function, line number via formatter
# Already handled by the formatter

# Bad - no context
logger.error("Something went wrong")
""")

# ============================================================
# 3. DON'T LOG SENSITIVE INFORMATION
# ============================================================

print("\n3. DON'T LOG SENSITIVE INFORMATION")

print("""
# Bad - logging passwords
logger.info(f"User {user} logged in with password {password}")

# Bad - logging credit cards
logger.info(f"Payment processed for card {card_number}")

# Good - log without sensitive data
logger.info(f"User {user} logged in")
logger.info(f"Payment processed for user {user}")

# Good - mask sensitive data
logger.debug(f"API request: {request_data} (password masked)")
""")

# ============================================================
# 4. USE LOGGER HIERARCHY
# ============================================================

print("\n4. USE LOGGER HIERARCHY")

print("""
# Good - use module-level loggers
logger = logging.getLogger(__name__)  # 'myapp.module'

# Good - create a hierarchy
app_logger = logging.getLogger('myapp')
module_logger = logging.getLogger('myapp.module')
function_logger = logging.getLogger('myapp.module.function')

# This allows different levels for different parts
""")


# ============================================================
# 5. HANDLE EXCEPTIONS PROPERLY
# ============================================================

print("\n5. HANDLE EXCEPTIONS PROPERLY")

print("""
# Good - log the exception
try:
    result = risky_operation()
except Exception as e:
    logger.error(f"Operation failed: {e}", exc_info=True)
    # Or use logger.exception()

# Bad - log without traceback
try:
    result = risky_operation()
except Exception as e:
    logger.error(f"Operation failed: {e}")  # No traceback

# Bad - no logging at all
try:
    result = risky_operation()
except Exception:
    pass  # Silent failure
""")


# ============================================================
# 6. CONFIGURE LOGGING ONCE
# ============================================================

print("\n6. CONFIGURE LOGGING ONCE")

print("""
# Good - configure at the start of the application
# main.py
import logging
import config

def main():
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    logger.info("Application started")

# Bad - configure in multiple places
""")


# ============================================================
# 7. SUMMARY
# ============================================================

print("\n" + "=" * 60)
print("BEST PRACTICES SUMMARY")
print("=" * 60)
print("""
- Use appropriate log levels
- Include context in log messages
- Don't log sensitive information
- Use logger hierarchy (__name__)
- Log exceptions with traceback
- Configure logging once
- Use different handlers for different needs
- Set different levels for different environments
- Keep logs structured and consistent
""")

Best practices summary:

  • Right level — use appropriate severity
  • Include context — add useful information
  • Don't log secrets — passwords, credit cards
  • Use hierarchy — __name__ for module names
  • Log exceptions — include traceback

Quick Check: Should you log passwords? (Answer: No, never log sensitive information)

Try It Yourself

Experiment with logging in the editor below.

Loading Pyodide... 0%
Python Code Editor
==================================================
LOGGING - PRACTICE
==================================================

1. BASIC LOGGING
Logging configured with INFO level
2024-01-15 10:30:45,123 - INFO - This is INFO
2024-01-15 10:30:45,124 - WARNING - This is WARNING
2024-01-15 10:30:45,124 - ERROR - This is ERROR
DEBUG messages are hidden because level=INFO

2. LOGGER WITH NAME
2024-01-15 10:30:45,125 - practice - DEBUG - Debug message from named logger
2024-01-15 10:30:45,125 - practice - INFO - Info message from named logger
2024-01-15 10:30:45,125 - practice - WARNING - Warning message from named logger

3. LOGGING EXCEPTIONS
ERROR:root:Division by zero error
Traceback (most recent call last):
File "", line 2, in
ZeroDivisionError: division by zero
Exception logged with traceback
🏆

You've Got It!

You now understand logging in Python. You know how to use log levels, configure logging, and write logs to files.

Quick Quiz

Test what you've learned:

1. Which log level is used for detailed debugging information?
2. What function do you use to configure logging?
3. How do you log an exception with traceback?
4. Which component sends logs to a destination?
5. What should you NOT log?

Frequently Asked Questions

What is logging in Python? ▼

Logging is the practice of recording events in your program. Python's logging module provides a flexible framework for generating log messages with different severity levels, timestamps, and multiple output destinations.

What's the difference between logging and print? ▼

Logging is more powerful than print. It has log levels, timestamps, multiple outputs (console, file, network), and can be configured without changing code. Print is simple but lacks these features.

How do I write logs to a file? ▼

Use logging.basicConfig(filename='app.log') to write to a file. For more control, create a FileHandler: handler = logging.FileHandler('app.log') and add it to your logger.

What are log levels? ▼

Log levels represent the severity of a log message. From lowest to highest: DEBUG, INFO, WARNING, ERROR, CRITICAL. You set a minimum level, and only messages at or above that level are logged.

How do I log exceptions with traceback? ▼

Use logging.exception() inside an except block. This logs the error message along with the full traceback. You can also use logging.error(msg, exc_info=True).

What's the best practice for logging in modules? ▼

Use logger = logging.getLogger(__name__) in each module. This creates a hierarchy of loggers based on the module names, making it easy to control logging levels for different parts of your application.

Where to Go From Here

Now that you understand logging, check out these related topics:

Code Optimization

Learn how to write efficient Python code.

Learn More →

Debugging

Learn techniques for debugging Python code.

Learn More →

Docstrings

Learn about documenting your code.

Learn More →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Docstrings Next: Code Optimization →