{"id":1066,"library":"opentelemetry-instrumentation-logging","title":"OpenTelemetry Logging Instrumentation","description":"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.","status":"active","version":"0.61b0","language":"python","source_language":"en","source_url":"https://github.com/open-telemetry/opentelemetry-python-contrib","tags":["opentelemetry","logging","instrumentation","observability","tracing","logs"],"install":[{"cmd":"pip install opentelemetry-instrumentation-logging opentelemetry-sdk opentelemetry-exporter-otlp","lang":"bash","label":"Install core and OTLP exporter"}],"dependencies":[{"reason":"Core OpenTelemetry API for defining telemetry.","package":"opentelemetry-api"},{"reason":"Core OpenTelemetry SDK for processing and exporting telemetry.","package":"opentelemetry-sdk"},{"reason":"Common exporter for sending logs via OTLP (OpenTelemetry Protocol).","package":"opentelemetry-exporter-otlp","optional":true}],"imports":[{"symbol":"LoggingInstrumentor","correct":"from opentelemetry.instrumentation.logging import LoggingInstrumentor"},{"symbol":"LoggerProvider","correct":"from opentelemetry.sdk._logs import LoggerProvider"},{"symbol":"BatchLogRecordProcessor","correct":"from opentelemetry.sdk._logs.export import BatchLogRecordProcessor"},{"symbol":"OTLPLogExporter","correct":"from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter"}],"quickstart":{"code":"import logging\nfrom opentelemetry import trace\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.sdk._logs import LoggerProvider\nfrom opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.instrumentation.logging import LoggingInstrumentor\n\n# Configure a basic logger\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\n# 1. Configure OpenTelemetry Resource\nresource = Resource.create({\n    \"service.name\": \"my-python-logging-app\",\n    \"service.instance.id\": \"instance-1\"\n})\n\n# 2. Configure LoggerProvider with a processor and exporter\n# For demonstration, using ConsoleLogRecordExporter to print to stdout\n# In a real application, you'd use OTLPLogExporter or another backend exporter.\nlog_exporter = ConsoleLogRecordExporter()\nlog_processor = BatchLogRecordProcessor(log_exporter)\nlogger_provider = LoggerProvider(resource=resource)\nlogger_provider.add_log_record_processor(log_processor)\nset_logger_provider(logger_provider)\n\n# 3. Instrument the standard logging module\n# set_logging_format=True enables trace context injection into log format\nLoggingInstrumentor().instrument(set_logging_format=True)\n\n# 4. Use standard logging, which will now be captured by OpenTelemetry\nlogger.info(\"This is a regular Python log message.\")\n\n# 5. Demonstrate log correlation with an active trace span\ntracer = trace.get_tracer(\"my-tracer\")\nwith tracer.start_as_current_span(\"my-operation\") as span:\n    span.set_attribute(\"operation.id\", \"xyz123\")\n    logger.warning(\"This log message is inside a span, so it should be correlated.\")\n\n# 6. Shut down the logger provider to ensure all logs are exported\nlogger_provider.shutdown()\nprint(\"Logs sent to console (or configured exporter).\")","lang":"python","description":"This quickstart demonstrates how to set up `opentelemetry-instrumentation-logging` to capture standard Python log messages and export them. It configures a `LoggerProvider` with a `ConsoleLogRecordExporter` for easy viewing, enables the `LoggingInstrumentor` to inject trace context, and shows a log message emitted within an active span for correlation."},"warnings":[{"fix":"Review release notes for each update. Pin dependencies to specific versions (`==0.x.y`) in production to control updates.","message":"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.","severity":"breaking","affected_versions":"All 0.x.y beta versions"},{"fix":"Avoid calling `uninstrument()` if possible. If dynamic instrumentation/uninstrumentation is strictly necessary, carefully evaluate its impact on other logging components and consider alternative approaches like logging filters or custom loggers that do not rely on modifying the global log factory. Refer to GitHub Issue #3808 for context.","message":"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`.","severity":"gotcha","affected_versions":"All 0.x.y beta versions (at least up to 0.61b0)"},{"fix":"Ensure `LoggingInstrumentor().instrument(set_logging_format=True)` is called early in your application's startup, prior to any custom `logging.basicConfig()` calls that use trace context variables (e.g., `%(otelTraceID)s`).","message":"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.","severity":"gotcha","affected_versions":"All 0.x.y beta versions"},{"fix":"Install `opentelemetry-instrumentation-logging` and call `LoggingInstrumentor().instrument()` (or rely on auto-instrumentation). Avoid using the `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` environment variable if you are using this package.","message":"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.","severity":"deprecated","affected_versions":"Versions where `opentelemetry-sdk` deprecated its internal `LoggingHandler`."},{"fix":"Always follow the OpenTelemetry logging setup by creating a `Resource`, `LoggerProvider`, `LogRecordProcessor`, and `LogExporter`, and setting the global logger provider via `set_logger_provider()`.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T23:26:52.171Z","next_check":"2026-06-30T00:00:00.000Z","problems":[{"fix":"Ensure the library is installed in the correct Python environment: `pip install opentelemetry-instrumentation-logging`","cause":"This error occurs when the `opentelemetry-instrumentation-logging` package or its dependencies are not installed, or the Python environment where the application is run does not have access to the installed package.","error":"ModuleNotFoundError: No module named 'opentelemetry.instrumentation.logging'"},{"fix":"Initialize and set the `TracerProvider` and `LoggerProvider` with a `Resource` instance at the very beginning of your application's lifecycle, before any instrumentation or logging calls. For example:\n```python\nfrom opentelemetry import trace\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk._logs import LoggerProvider\nfrom opentelemetry.sdk.resources import Resource\n\n# Configure resource\nresource = Resource(attributes={\n    \"service.name\": \"my-python-app\",\n    \"service.version\": \"1.0.0\"\n})\n\n# Set global TracerProvider\ntracer_provider = TracerProvider(resource=resource)\ntrace.set_tracer_provider(tracer_provider)\n\n# Set global LoggerProvider\nlogger_provider = LoggerProvider(resource=resource)\nset_logger_provider(logger_provider)\n\n# Now instrument logging\nfrom opentelemetry.instrumentation.logging import LoggingInstrumentor\nLoggingInstrumentor().instrument()\n```","cause":"This error typically arises when an instrumentation attempts to access the `resource` attribute of the global `TracerProvider` (or `LoggerProvider`) before a concrete SDK provider (e.g., `TracerProvider(resource=...)`) has been set globally using `trace.set_tracer_provider()` or `set_logger_provider()`.","error":"AttributeError: 'ProxyTracerProvider' object has no attribute 'resource'"},{"fix":"1. Ensure a `LoggerProvider` and a `LogRecordProcessor` with an `OTLPLogExporter` (or `ConsoleLogRecordExporter` for local debugging) are configured and started.\n2. Set the Python root logger's level to `logging.NOTSET` or a sufficiently low level to capture all desired messages. Call `logging.basicConfig(level=logging.NOTSET, handlers=[LoggingHandler(logger_provider=logger_provider)])` *after* setting the `LoggerProvider`.\n3. If using auto-instrumentation, ensure `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true` is set as an environment variable or passed to `LoggingInstrumentor().instrument()`.\n\nExample setup:\n```python\nimport logging\nimport os\n\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.sdk._logs import LoggerProvider, LoggingHandler\nfrom opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter # or OTLPLogExporter\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.instrumentation.logging import LoggingInstrumentor\n\nresource = Resource(attributes={\n    \"service.name\": \"my-app-logs\"\n})\n\nlogger_provider = LoggerProvider(resource=resource)\n# Use ConsoleLogRecordExporter for debugging, OTLPLogExporter for sending to a collector\nlog_exporter = ConsoleLogRecordExporter() # or OTLPLogExporter()\nprocessor = BatchLogRecordProcessor(log_exporter)\nlogger_provider.add_log_record_processor(processor)\nset_logger_provider(logger_provider)\n\n# Instrument the standard logging module\nLoggingInstrumentor().instrument(set_logging_format=True)\n\n# Configure the root logger to use the OpenTelemetry handler\n# Ensure its level is low enough to capture desired logs\nlogging.basicConfig(level=logging.INFO, handlers=[LoggingHandler(logger_provider=logger_provider)])\n\nlogger = logging.getLogger(__name__)\nlogger.info(\"This log should appear in OpenTelemetry.\")\n```","cause":"Logs may not appear due to several reasons, including the Python root logger's level being set too high, an OpenTelemetry log exporter not being configured or started, incorrect initialization order where `logging.basicConfig()` overrides the OpenTelemetry handler, or the `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` environment variable not being set to `true` when using auto-instrumentation.","error":"OpenTelemetry logs not appearing in console or backend"},{"fix":"Ensure that the `LoggingInstrumentor().instrument()` call (or setting `OTEL_PYTHON_LOG_CORRELATION=true` for auto-instrumentation) happens *before* any calls to `logging.basicConfig()` or any custom formatter that attempts to access `otelTraceID` or `otelSpanID`. The `LoggingInstrumentor` registers a custom log record factory that adds these fields. If `set_logging_format=True` is passed to `instrument()`, it will handle `basicConfig()` for you.\n\n```python\nimport logging\nfrom opentelemetry.instrumentation.logging import LoggingInstrumentor\nfrom opentelemetry.sdk._logs import LoggerProvider # assuming LoggerProvider is set up globally\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry._logs import set_logger_provider\n\n# ... (setup resource and logger_provider as in previous example)\nresource = Resource(attributes={\"service.name\": \"my-app\"})\nlogger_provider = LoggerProvider(resource=resource)\nset_logger_provider(logger_provider)\n\n# Instrument logging FIRST, and let it handle basicConfig if desired\nLoggingInstrumentor().instrument(set_logging_format=True) # This will call basicConfig with trace context format\n\n# If you need a custom format, enable instrumentation first, then configure basicConfig without trace_id/span_id fields in format string or provide them via custom formatter after instrumentation is active.\n# Example with custom format, ensuring instrumentation runs first\n# LoggingInstrumentor().instrument()\n# logging.basicConfig(format='%(asctime)s [%(levelname)s] [%(name)s] - %(message)s', level=logging.INFO)\n\nlogger = logging.getLogger(__name__)\nlogger.info(\"Log with trace context.\")\n```","cause":"This error occurs when the logging format string includes placeholders like `%(otelTraceID)s` or `%(otelSpanID)s`, but the `opentelemetry-instrumentation-logging` has not yet injected these attributes into the log record, often because `logging.basicConfig()` (or a similar manual logger configuration) was called *before* the `LoggingInstrumentor` was enabled.","error":"KeyError: 'otelTraceID'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.62b1","cli_name":"opentelemetry-instrument","cli_version":"opentelemetry-instrument 0.62b1","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","installed_version":"0.62b1","pypi_latest":"0.62b1","is_stale":false,"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.32,"mem_mb":9.5,"disk_size":"52.0M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.34,"mem_mb":9.4,"disk_size":"51.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":5.6,"import_time_s":0.23,"mem_mb":9.5,"disk_size":"50M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.26,"mem_mb":9.4,"disk_size":"50M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.46,"mem_mb":10.8,"disk_size":"55.5M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.56,"mem_mb":10.7,"disk_size":"55.3M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":4.8,"import_time_s":0.42,"mem_mb":10.8,"disk_size":"53M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.45,"mem_mb":10.7,"disk_size":"53M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.59,"mem_mb":10.8,"disk_size":"47.1M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.67,"mem_mb":10.8,"disk_size":"46.8M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":4,"import_time_s":0.62,"mem_mb":10.8,"disk_size":"45M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.66,"mem_mb":10.8,"disk_size":"45M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.29,"mem_mb":8.3,"disk_size":"46.8M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.32,"mem_mb":8.2,"disk_size":"46.5M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":4,"import_time_s":0.3,"mem_mb":8.3,"disk_size":"45M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.33,"mem_mb":8.2,"disk_size":"44M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.26,"mem_mb":8.7,"disk_size":"51.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.29,"mem_mb":8.6,"disk_size":"51.1M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":6.4,"import_time_s":0.25,"mem_mb":8.7,"disk_size":"49M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"opentelemetry-instrumentation-logging","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.27,"mem_mb":8.6,"disk_size":"49M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}