OpenTelemetry Logging Instrumentation
The `opentelemetry-instrumentation-logging` library provides automatic instrumentation for Python's standard `logging` module. It converts native Python log messages into OpenTelemetry logs, enabling correlation with traces and metrics, and facilitates their export to an observability backend. Part of the `opentelemetry-python-contrib` project, this library is currently in beta (version 0.61b0) and undergoes regular releases as part of the broader OpenTelemetry Python ecosystem.
Warnings
- breaking The library is currently in beta (`0.x.y` versioning). While stable for many use cases, its API is subject to change, and breaking changes may occur in minor or patch releases.
- gotcha Calling `LoggingInstrumentor().uninstrument()` can corrupt the standard Python `logging` module's log factory linked list, potentially breaking other logging handlers or custom log record factories that were set after `LoggingInstrumentor`.
- gotcha If you manually call `logging.basicConfig()` and are not relying on the `OTEL_PYTHON_LOG_CORRELATION` environment variable to configure the logging format, you *must* ensure `LoggingInstrumentor().instrument()` is called *before* `logging.basicConfig()` to avoid `KeyError` exceptions when attempting to inject trace context variables.
- deprecated This package provides a logging handler to replace a deprecated `LoggingHandler` previously available in `opentelemetry-sdk`. If `opentelemetry-instrumentation-logging` is installed, you should *not* set the `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` environment variable to `true`, as this variable is intended for the *deprecated* SDK handler and can cause confusion or conflicts.
- gotcha Simply installing `opentelemetry-instrumentation-logging` and calling `instrument()` is not sufficient to export logs. You must also configure a `LoggerProvider`, add a `LogRecordProcessor`, and specify a `LogExporter` (e.g., `OTLPLogExporter`) to direct your OpenTelemetry logs to an observability backend.
Install
-
pip install opentelemetry-instrumentation-logging opentelemetry-sdk opentelemetry-exporter-otlp
Imports
- LoggingInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor
- LoggerProvider
from opentelemetry.sdk._logs import LoggerProvider
- BatchLogRecordProcessor
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
- OTLPLogExporter
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
Quickstart
import logging
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.instrumentation.logging import LoggingInstrumentor
# Configure a basic logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 1. Configure OpenTelemetry Resource
resource = Resource.create({
"service.name": "my-python-logging-app",
"service.instance.id": "instance-1"
})
# 2. Configure LoggerProvider with a processor and exporter
# For demonstration, using ConsoleLogRecordExporter to print to stdout
# In a real application, you'd use OTLPLogExporter or another backend exporter.
log_exporter = ConsoleLogRecordExporter()
log_processor = BatchLogRecordProcessor(log_exporter)
logger_provider = LoggerProvider(resource=resource)
logger_provider.add_log_record_processor(log_processor)
set_logger_provider(logger_provider)
# 3. Instrument the standard logging module
# set_logging_format=True enables trace context injection into log format
LoggingInstrumentor().instrument(set_logging_format=True)
# 4. Use standard logging, which will now be captured by OpenTelemetry
logger.info("This is a regular Python log message.")
# 5. Demonstrate log correlation with an active trace span
tracer = trace.get_tracer("my-tracer")
with tracer.start_as_current_span("my-operation") as span:
span.set_attribute("operation.id", "xyz123")
logger.warning("This log message is inside a span, so it should be correlated.")
# 6. Shut down the logger provider to ensure all logs are exported
logger_provider.shutdown()
print("Logs sent to console (or configured exporter).")