Structured Logging
Relevant source files
The following files were used as context for generating this wiki page:
Structured Logging in the FLEXT ecosystem provides a standardized way to capture, enrich, and propagate application logs as machine-readable JSON data. It integrates core observability signals—such as correlation IDs, trace IDs, and span IDs—directly into log entries to enable seamless debugging across distributed services.
The system is built upon Clean Architecture and Domain-Driven Design principles, ensuring that logging remains a cross-cutting concern that is decoupled from business logic while maintaining strict type safety and railway-oriented programming (ROP) patterns.
Sources: src/README.md:16-32, src/flext_observability/README.md:1-10, src/flext_observability/services/logging_integration.py:1-15
Architecture and Core Components
The structured logging system acts as an interface adapter between the flext-observability context and the flext-core logging utilities. It leverages structlog as a primary dependency to handle JSON formatting and context local storage.
Key Classes and Services
| Component | Description |
|---|---|
FlextObservabilityLogging | The primary service class for managing log context enrichment and logger creation. |
FlextObservabilityContext | Manages the thread-local or async-local storage of correlation and trace IDs. |
FlextLogEntry | A domain entity representing a structured log event with validation. |
FlextLoggingService | Application-layer service for managing logging lifecycle. |
Sources: src/flext_observability/services/logging_integration.py:19-21, src/flext_observability/README.md:46-52, pyproject.toml:35
Data Flow for Log Enrichment
When a log message is emitted, the system automatically retrieves the current execution context to append metadata.
The diagram shows how the logging_integration service intercepts log calls to inject metadata from the FlextObservabilityContext.
Sources: src/flext_observability/services/logging_integration.py:84-124
Trace Context Integration
A critical feature of FLEXT Structured Logging is the automatic enrichment of logs with distributed tracing identifiers. This ensures that every log line can be traced back to a specific user request or internal operation.
Enrichment Mechanism
The enrich_log_context method retrieves identifiers from the active observability context. If include_baggage is enabled, additional metadata (key-value pairs) propagated across service boundaries is also included.
- Correlation ID: Application-level request tracking identifier.
- Trace ID: Identifier for the entire distributed trace.
- Span ID: Identifier for the current unit of work.
Sources: src/flext_observability/services/logging_integration.py:84-118
Context Lifecycle
The system provides a mechanism to ensure a correlation_id always exists for the duration of a request.
This flow ensures that logging remains consistent even if the request was not explicitly initialized with an ID.
Sources: src/flext_observability/services/logging_integration.py:140-163
Implementation Patterns
Logger Creation
Loggers are created via a factory method that ensures they are configured for structured output.
from flext_observability import FlextObservabilityLogging
# Create logger with automatic trace context
logger_result = FlextObservabilityLogging.create_logger(__name__)
if logger_result.success:
logger = logger_result.value
logger.info("Service started", extra={"version": "1.0.0"})
Sources: src/flext_observability/services/logging_integration.py:46-70
Logging with Context
The log_with_context method allows for ad-hoc logging with explicit context injection, supporting various severity levels defined in the domain constants.
result = FlextObservabilityLogging.log_with_context(
logger,
level="info",
message="Processing transaction",
extra={"amount": 100.50},
include_baggage=True
)
Sources: src/flext_observability/services/logging_integration.py:202-230
Validation and Error Handling
Following the Railway-Oriented Programming (ROP) pattern, logging operations return p.Result[T] (specifically r[T]). This allows the system to handle logging failures (e.g., serialization errors or context retrieval issues) gracefully without crashing the main application flow.
| Level | Mapping |
|---|---|
DEBUG | c.Observability.ErrorSeverity.DEBUG |
INFO | c.Observability.ErrorSeverity.INFO |
WARNING | c.Observability.ErrorSeverity.WARNING |
ERROR | c.Observability.ErrorSeverity.ERROR |
CRITICAL | c.Observability.ErrorSeverity.CRITICAL |
Sources: src/flext_observability/services/logging_integration.py:240-250, examples/01_functional.py:34-40
Conclusion
Structured logging in the flext-observability repository is not merely about JSON output; it is a unified integration point for all observability signals. By binding correlation and trace IDs to every log entry, it transforms standard application logs into a powerful tool for distributed system debugging and performance analysis.
Sources: src/flext_observability/README.md:160-170, tests/integration/test_phase_11_integration.py:100-120