logging

Updated March 13, 2026 · Modules
logging debugging stdlib

The logging module is Python’s built-in solution for application logging. It provides a flexible, hierarchical framework for emitting log messages from Python programs. Unlike simple print statements, logging lets you control message severity, route messages to different destinations, and configure output format without modifying your application code.

Syntax

import logging

# Get a logger for the current module
logger = logging.getLogger(__name__)

# Configure basic logging
logging.basicConfig(level=logging.INFO)

# Emit log messages
logger.debug("Detailed diagnostic info")
logger.info("Normal operation message")
logger.warning("Something unexpected happened")
logger.error("A serious problem occurred")
logger.critical("Program cannot continue")

Key Functions

The module provides module-level functions that operate on the root logger:

FunctionDescription
logging.getLogger(name)Returns a logger instance; same name returns same instance
logging.basicConfig(**kwargs)Configures the root logger with handlers, level, format
logging.debug(msg, *args, **kwargs)Log a DEBUG message
logging.info(msg, *args, **kwargs)Log an INFO message
logging.warning(msg, *args, **kwargs)Log a WARNING message
logging.error(msg, *args, **kwargs)Log an ERROR message
logging.critical(msg, *args, **kwargs)Log a CRITICAL message
logging.exception(msg, *args, **kwargs)Log an ERROR with exception traceback
logging.disable(level)Disable all logging at or below a given level

basicConfig Parameters

ParameterTypeDefaultDescription
levelintNOTSETMinimum level to log
filenamestrNoneFile to log to (if None, logs to console)
filemodestr'a'File open mode (‘a’ or ‘w’)
formatstr%(levelname)s:%(name)s:%(message)sLog message format
datefmtstrNoneDate format string
stylestr'%'Format style (’%’, ’{’, ’$‘)
handlerslistNoneList of handlers to attach

Logger Objects

Loggers are the primary interface for application code. Always obtain them via getLogger() rather than instantiating directly.

Logger Methods

MethodDescription
logger.setLevel(level)Set the minimum logging level
logger.getEffectiveLevel()Get the effective level (walks up hierarchy if NOTSET)
logger.isEnabledFor(level)Check if a level would be processed
logger.debug(msg, ...)Log at DEBUG level
logger.info(msg, ...)Log at INFO level
logger.warning(msg, ...)Log at WARNING level
logger.error(msg, ...)Log at ERROR level
logger.critical(msg, ...)Log at CRITICAL level
logger.exception(msg, ...)Log at ERROR with traceback
logger.log(level, msg, ...)Log at a specific level
logger.addHandler(hdlr)Attach a handler to this logger
logger.removeHandler(hdlr)Remove a handler
logger.addFilter(filter)Add a filter object
logger.hasHandlers()Check if any handlers are configured

Logger Attributes

AttributeDescription
logger.nameThe logger’s name (passed to getLogger)
logger.levelThe threshold level set on this logger
logger.parentParent logger in the hierarchy
logger.propagateIf True, messages pass to parent handlers (default True)
logger.handlersList of handlers attached to this logger

Log Levels

Logging levels are numeric values that determine message severity. The module defines these standard levels:

LevelValueWhen to Use
NOTSET0Inherit from parent (default for loggers)
DEBUG10Detailed diagnostic information
INFO20Confirmation that things work as expected
WARNING30Something unexpected, but the program continues
ERROR40A serious problem prevented a function from working
CRITICAL50The program itself may be unable to continue

Messages below the configured threshold are ignored. The root logger defaults to WARNING, while child loggers default to NOTSET (inheriting their parent’s level).

Handlers

Handlers determine where log messages go. The module provides several built-in handler types:

HandlerDescription
StreamHandlerLogs to a stream (default: stderr)
FileHandlerLogs to a file
RotatingFileHandlerLogs to a file with rotation
TimedRotatingFileHandlerLogs to a file rotated at intervals
SocketHandlerLogs to a network socket
DatagramHandlerLogs to a UDP socket
SysLogHandlerLogs to a Unix syslog
HTTPHandlerLogs to an HTTP server

Handler methods include setLevel(), setFormatter(), addFilter(), removeFilter(), and emit().

Examples

Basic Configuration with basicConfig

import logging

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

logger = logging.getLogger(__name__)

logger.debug("Debug message - detailed info for troubleshooting")
logger.info("Info message - normal operation")
logger.warning("Warning message - something looks off")
logger.error("Error message - something failed")
logger.critical("Critical message - system may crash")

Output:

2026-03-09 10:30:45 - __main__ - DEBUG - Debug message - detailed info for troubleshooting
2026-03-09 10:30:45 - __main__ - INFO - Info message - normal operation
2026-03-09 10:30:45 - __main__ - WARNING - Warning message - something looks off
2026-03-09 10:30:45 - __main__ - ERROR - Error message - something failed
2026-03-09 10:30:45 - __main__ - CRITICAL - Critical message - system may crash

Logger Hierarchy and Propagation

import logging

# Configure root logger
logging.basicConfig(level=logging.INFO, format='%(name)s - %(levelname)s - %(message)s')

# Create child loggers
app_logger = logging.getLogger('myapp')
db_logger = logging.getLogger('myapp.database')
api_logger = logging.getLogger('myapp.api')

# Set different levels for different components
app_logger.setLevel(logging.WARNING)
db_logger.setLevel(logging.DEBUG)
api_logger.setLevel(logging.INFO)

# Emit messages at various levels
app_logger.warning("App warning - config file missing")
db_logger.debug("Database: Executing query")
db_logger.info("Database: Connection established")
api_logger.info("API: Request received")
api_logger.error("API: Request failed")

Output:

myapp - WARNING - App warning - config file missing
myapp.database - DEBUG - Database: Executing query
myapp.database - INFO - Database: Connection established
myapp.api - INFO - API: Request received
myapp.api - ERROR - API: Request failed

Custom Handlers and Formatters

import logging

# Create a custom logger
logger = logging.getLogger('myapp.worker')
logger.setLevel(logging.DEBUG)

# Create handlers
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

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

# Create formatters
console_format = logging.Formatter('%(levelname)s: %(message)s')
file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# Attach formatters to handlers
console_handler.setFormatter(console_format)
file_handler.setFormatter(file_format)

# Add handlers to logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# Log messages
logger.debug("Debug: Variable x = 42")
logger.info("Info: Task started")
logger.warning("Warning: Resource usage high")

Console output:

DEBUG: Debug: Variable x = 42
INFO: Info: Task started
WARNING: Warning: Resource usage high

File output (app.log):

2026-03-09 10:30:45 - myapp.worker - DEBUG - Debug: Variable x = 42
2026-03-09 10:30:45 - myapp.worker - INFO - Info: Task started
2026-03-09 10:30:45 - myapp.worker - WARNING - Warning: Resource usage high

Common Patterns

Per-Module Loggers

The recommended pattern is creating a logger per module using __name__:

# mymodule.py
import logging
logger = logging.getLogger(__name__)

def process_data(data):
    logger.info("Processing started")
    # ... processing logic
    logger.info("Processing complete")

This creates a hierarchical logger structure matching your module hierarchy, allowing fine-grained control.

Disabling Logging Globally

You can disable all logging at or below a certain level:

import logging

# Disable all DEBUG and INFO messages
logging.disable(logging.WARNING)

logger = logging.getLogger('myapp')
logger.debug("This won't appear")  # Ignored
logger.info("This won't appear")   # Ignored
logger.warning("This will appear") # Shows

Exception Logging

Use logger.exception() to automatically include traceback information:

import logging

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.ERROR)

try:
    result = 10 / 0
except ZeroDivisionError:
    logger.exception("Division failed")

Output:

ERROR:__main__:Division failed
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ZeroDivisionError: division by zero

See Also