Python Standard Library Logging: The Foundation of Python Observability

In Python's ecosystem, the standard library's logging module remains the bedrock of application observability. This built-in solution offers a powerful, flexible, and standardized approach to logging that has stood the test of time, continuing to serve as the foundation for Python application logging in 2025.

Why the Standard logging Module Endures as Python's Primary Logging Solution

The logging module has maintained its position as Python's go-to logging framework through several enduring strengths:

  • Built-in Availability: No external dependencies required
  • Hierarchical Loggers: Organize logs using a parent-child hierarchy
  • Handler System: Output logs to multiple destinations simultaneously
  • Filter Support: Control which log records are processed
  • Formatter Framework: Customize log appearance and structure
  • Thread Safety: Safe for use in concurrent applications
  • Configurable: Set up via code, dictionaries, files, or environment variables
  • Level-based Filtering: Granular control over verbosity
  • Exception Information: Automatic inclusion of traceback information
  • Extensive Documentation: Comprehensive official documentation

Getting Started with Python's logging Module

Since logging is part of the standard library, no installation is needed:

python
13456781011131415161819202122
import logging
# Basic configuration
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='application.log'
)
# Simple logging
logging.info("Application started")
# Different log levels
logging.debug("This won't show unless level is changed to DEBUG")
logging.warning("Resource utilization high")
logging.error("Failed to connect to database")
# With exception information
try:
result = 10 / 0
except Exception as e:
logging.exception("An error occurred during calculation")

For more advanced usage with logger hierarchies:

python
12356791011131416171819
# Create logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
# Create console handler and set level
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
# Add handler to logger
logger.addHandler(console_handler)
# Log messages
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")

Enhancing Python's logging with OpenTelemetry for Complete Observability

While the standard logging module provides robust capabilities, modern distributed applications demand a more integrated approach to observability. By combining Python's logging with an OpenTelemetry-native observability platform, you can transform isolated logs into components of a unified monitoring strategy.

This powerful integration enables:

  • Trace Context Enrichment: Automatically add trace and span IDs to your log entries
  • Log-Trace Correlation: Connect logs directly to distributed traces for context-rich debugging
  • Cross-Service Visibility: Track requests across service boundaries with correlated logs
  • Unified Monitoring: Manage logs, metrics, and traces through a single platform
  • Contextual Analysis: Understand logs within the full application context

Implementing Python logging with OpenTelemetry

Setting up the integration requires minimal configuration:

python
12345689101112141516171819202122232426272829303132343536373839404142
import logging
import sys
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
# Configure OpenTelemetry
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)
span_processor = BatchSpanProcessor(ConsoleSpanExporter())
trace.get_tracer_provider().add_span_processor(span_processor)
# Custom log formatter that includes trace context
class OpenTelemetryFormatter(logging.Formatter):
def format(self, record):
span = trace.get_current_span()
if span.get_span_context().is_valid:
record.trace_id = f"{span.get_span_context().trace_id:032x}"
record.span_id = f"{span.get_span_context().span_id:016x}"
else:
record.trace_id = "undefined"
record.span_id = "undefined"
return super().format(record)
# Configure logging
logger = logging.getLogger("app")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
formatter = OpenTelemetryFormatter('%(asctime)s - %(name)s - [trace_id=%(trace_id)s span_id=%(span_id)s] - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# Use trace context in logs
with tracer.start_as_current_span("operation") as span:
logger.info("This log will contain trace context")
# Application code here
logger.warning("Warning message with trace context")
# Nested spans will correctly propagate through logs
with tracer.start_as_current_span("nested_operation") as child_span:
logger.info("Log from nested operation")

Analyzing OpenTelemetry Logs in Dash0

Logs can be directly routed into Dash0. Dash0 with OpenTelemetry provides the ability to filter, search, group, and triage within a simple user interface, with full keyboard support. Dash0 also gives full log context by showing trace context, the call and resource that created the log - including details like the Kubernetes Pod, server, and cloud environment.

Log AI also enhanced the logs with more semantical metadata and structure without any manual pattern declaration.

Conclusion

In 2025, Python's standard library logging module continues to be the foundation of Python application logging, offering a robust, well-documented, and universally available solution. Its flexible architecture and broad ecosystem support make it suitable for projects of all sizes and complexities.

By enhancing Python's logging with OpenTelemetry integration, developers can maintain this solid foundation while gaining the advantages of unified observability. This combination delivers powerful insights by connecting logs with traces and metrics, enabling faster problem resolution and better application understanding.

For Python applications that need both reliable logging and comprehensive observability, the standard logging module with OpenTelemetry integration provides an ideal solution that leverages Python's built-in capabilities while embracing modern observability practices.

Last updated: March 28, 2025