OpenTelemetry Log Integration
In the modern observability landscape, logs have traditionally existed in silos, often disconnected from the traces and metrics that provide context to system behavior. OpenTelemetry (OTel) changes this paradigm by treating logs as a first-class citizen, standing on equal footing with traces and metrics.
The goal of OpenTelemetry log integration is not to force developers to abandon their preferred logging libraries. Instead, it aims to wrap existing logging outputs into a unified data model and a standardized transport pipeline. By doing so, logs become enriched with resource attributes, severity levels, and, most importantly, trace context. This correlation allows engineers to jump from a specific trace span directly to the relevant log lines, seeing the trace_id, span_id, service name, and environment metadata all in one view.
Core Components of the OpenTelemetry Logging Model
To understand how integration works, we must first look at the fundamental building blocks that make up the OTel logging ecosystem.
- LogRecord: This is the atomic unit of the logging model. Unlike a simple string of text, a
LogRecordis a structured object containing a timestamp, observed time, severity level, the log body, and a collection of attributes. Crucially, it also includesTraceIdandSpanIdfields to enable seamless correlation. - Resource: This represents the entity producing the logs. It contains metadata that describes the source, such as
service.name,service.version, anddeployment.environment. By attaching these attributes to every log, you gain powerful dimensions for filtering and grouping data in your backend. - Context: This is the mechanism that propagates trace information. When a log is generated within the scope of an active span, the Context ensures that the current
trace_idandspan_idare automatically injected into theLogRecord. - Logs Bridge API: For most existing applications, rewriting all logging statements is impractical. The Bridge API acts as a translation layer, intercepting logs from established libraries (like Python's
logging, Java'sLog4j, or .NET'sILogger) and converting them into OTel-compliantLogRecords. - Logs SDK: Once logs are converted, the SDK handles the heavy lifting: processing, batching, and exporting. It is important to note that while the API is stable, the maturity of the SDK varies across different programming languages.
- OTLP (OpenTelemetry Protocol): This is the standardized communication protocol used to transmit logs, metrics, and traces to a backend or a collector.
- OpenTelemetry Collector: A vendor-agnostic proxy that receives, processes, and exports telemetry data. In many logging workflows, the Collector uses a
filelogreceiver to ingest logs from local files and anotlpexporter to forward them to a centralized storage system.
Strategic Integration Approaches
Depending on your application architecture and the level of control you have over the code, there are three primary ways to integrate logs with OpenTelemetry.
1. Application-Level Bridging
This is the most common approach for mature applications. You continue to use your existing, familiar logging framework, but you add a "bridge" or "handler" provided by the OpenTelemetry SDK. This handler intercepts log calls and transforms them into OTel records. This method is highly effective because it preserves your existing logging logic while gaining the benefits of structured data and trace correlation.
2. Collector-Based File Collection
If you are dealing with legacy applications that cannot be modified, or if you need to collect logs from infrastructure components (like Nginx or systemd), the Collector approach is ideal. The application simply writes logs to a file or stdout. The OpenTelemetry Collector, running as a sidecar or a daemon, uses the filelog receiver to tail these files, parse them (e.g., from JSON or regex), and export them via OTLP.
3. Direct Logs API Usage
For greenfield projects, you can bypass existing libraries entirely and call the OpenTelemetry Logs API directly. While this provides the most "pure" and unified implementation, it requires developers to learn a new API and necessitates checking the stability of the language-specific SDK before moving to production.
Implementation Example: Python Logging Bridge
The following example demonstrates how to bridge the standard Python logging module with OpenTelemetry. This setup ensures that every log message emitted by the standard logger is automatically enriched with the current trace context.
Prerequisites:
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc
Code Implementation:
import logging
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter
# 1. Define the Resource metadata
resource = Resource.create({"service.name": "demo-service"})
# 2. Set up the Tracing Provider
trace.set_tracer_provider(TracerProvider(resource=resource))
# 3. Set up the Logging Provider and Processor
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
logger_provider.add_log_record_processor(
BatchLogRecordProcessor(ConsoleLogExporter())
)
# 4. Bridge Python's standard logging to OpenTelemetry
handler = LoggingHandler(level=logging.INFO, logger_provider=logger_provider)
logging.basicConfig(level=logging.INFO, handlers=[handler])
logger = logging.getLogger(__name__)
tracer = trace.get_tracer(__name__)
# 5. Generate logs within a trace span
with tracer.start_as_current_span("handle-request"):
# The log below will automatically include trace_id and span_id
logger.info("Processing request", extra={"user.id": "u-123"})
In a production environment, you would replace ConsoleLogExporter with OTLPLogExporter to send your logs to an OpenTelemetry Collector or a managed observability backend.
Infrastructure-Level Integration: Collector File Collection
For scenarios where code changes are not an option, the OpenTelemetry Collector can be configured to scrape logs from the filesystem. This is particularly useful for parsing structured JSON logs produced by containerized applications.
Below is a conceptual configuration for an OpenTelemetry Collector using the filelog receiver:
receivers:
filelog:
include:
- /var/log/app/*.log
operators:
- type: json_parser
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
processors:
batch:
exporters:
otlp:
endpoint: "otel-collector:4317"
tls:
insecure: true
service:
pipelines:
logs:
receivers: [filelog]
processors: [batch]
exporters: [otlp]
By utilizing this configuration, the Collector acts as an intelligent agent that transforms raw text files into structured, enriched telemetry, ensuring that even your oldest legacy systems contribute to your modern observability strategy.