From 4a8805eb270817dabbee6092dbbfc7190746eb2d Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Thu, 21 May 2026 11:48:23 +0200 Subject: [PATCH 1/2] distro: handle opentelemetry-instrumentation-logging LoggingHandler as the sdk one With recent releases the opentelemetry-instrumentation-logging LoggingHandler is used if installed and so we need to consider that as well when deciding to propagate. --- dev-requirements.txt | 8 ++++++-- pyproject.toml | 9 ++++++++- src/elasticotel/distro/config.py | 22 ++++++++++++++++++++-- tests/distro/test_distro.py | 30 ++++++++++++++++++++++++++++-- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 4c5bc38..ea233a6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,7 +6,7 @@ # build==1.4.4 # via pip-tools -certifi==2026.4.22 +certifi==2026.5.20 # via requests charset-normalizer==3.4.7 # via requests @@ -38,6 +38,7 @@ opentelemetry-api==1.41.1 # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http # opentelemetry-instrumentation + # opentelemetry-instrumentation-logging # opentelemetry-instrumentation-system-metrics # opentelemetry-opamp-client # opentelemetry-resourcedetector-gcp @@ -57,7 +58,10 @@ opentelemetry-exporter-otlp-proto-http==1.41.1 opentelemetry-instrumentation==0.62b1 # via # elastic-opentelemetry (pyproject.toml) + # opentelemetry-instrumentation-logging # opentelemetry-instrumentation-system-metrics +opentelemetry-instrumentation-logging==0.62b1 + # via elastic-opentelemetry (pyproject.toml) opentelemetry-instrumentation-system-metrics==0.62b1 # via elastic-opentelemetry (pyproject.toml) opentelemetry-opamp-client==0.2b0 @@ -146,7 +150,7 @@ uuid-utils==0.15.0 # opentelemetry-opamp-client wheel==0.47.0 # via pip-tools -wrapt==2.1.2 +wrapt==2.2.0 # via opentelemetry-instrumentation zipp==3.23.1 # via importlib-metadata diff --git a/pyproject.toml b/pyproject.toml index ac91ebf..4e67cf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,14 @@ dependencies = [ ] [project.optional-dependencies] -dev = ["pytest", "pip-tools", "oteltest==0.24.0", "leb128", "pytest-vcr ; python_version > '3.9'"] +dev = [ + "pytest", + "pip-tools", + "oteltest==0.24.0", + "leb128", + "pytest-vcr ; python_version > '3.9'", + "opentelemetry-instrumentation-logging", +] [project.entry-points.opentelemetry_configurator] configurator = "elasticotel.distro:ElasticOpenTelemetryConfigurator" diff --git a/src/elasticotel/distro/config.py b/src/elasticotel/distro/config.py index 887ad01..f206309 100644 --- a/src/elasticotel/distro/config.py +++ b/src/elasticotel/distro/config.py @@ -34,7 +34,16 @@ OpAMPRemoteConfigParseException, ) from opentelemetry._opamp.proto import opamp_pb2 as opamp_pb2 -from opentelemetry.sdk._logs import LoggingHandler + +try: + from opentelemetry.instrumentation.logging.handler import LoggingHandler +except ImportError: + + class LoggingHandler: + pass + + +from opentelemetry.sdk._logs import LoggingHandler as SDKLoggingHandler from opentelemetry.sdk.environment_variables import OTEL_LOG_LEVEL, OTEL_TRACES_SAMPLER_ARG from opentelemetry.sdk.trace import _TracerConfig from opentelemetry.sdk.util._configurator import ConfiguratorRulesT @@ -129,7 +138,16 @@ def _setup_logging(self): _logger.addHandler(handler) # We need to propagate if we have the OTel handler otherwise we don't see logs shipped, in the other # cases we shouldn't - _logger.propagate = any(isinstance(_handler, LoggingHandler) for _handler in logging.root.handlers) + _logger.propagate = any( + isinstance( + _handler, + ( + LoggingHandler, + SDKLoggingHandler, + ), + ) + for _handler in logging.root.handlers + ) # do validation, we only validate logging_level because sampling_rate is handled by the sdk already logging_level = _LOG_LEVELS_MAP.get(self.logging_level.value) diff --git a/tests/distro/test_distro.py b/tests/distro/test_distro.py index 1f39a84..8df4daa 100644 --- a/tests/distro/test_distro.py +++ b/tests/distro/test_distro.py @@ -17,7 +17,7 @@ import json import logging import os -from unittest import TestCase, mock +from unittest import TestCase, mock, skipIf from elasticotel.distro import ElasticOpenTelemetryConfigurator, ElasticOpenTelemetryDistro, logger as distro_logger from elasticotel.distro.config import EDOTOpAMPCallbacks, logger as config_logger, Config @@ -40,7 +40,12 @@ OTEL_METRICS_EXPORTER, OTEL_TRACES_EXPORTER, ) -from opentelemetry.sdk._logs import LoggingHandler + +try: + from opentelemetry.instrumentation.logging.handler import LoggingHandler +except ImportError: + LoggingHandler = None +from opentelemetry.sdk._logs import LoggingHandler as SDKLoggingHandler from opentelemetry.sdk.environment_variables import ( OTEL_EXPERIMENTAL_RESOURCE_DETECTORS, OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE, @@ -459,6 +464,27 @@ def test_logging_setup_add_handlers_only_once(self): _logger.removeHandler(_logger.handlers[0]) def test_logging_setup_set_propagate_true_if_sdk_logging_handler_found(self): + root_logger = logging.getLogger() + handler = SDKLoggingHandler(logger_provider=mock.Mock()) + root_logger.addHandler(handler) + + config = Config() + + config._setup_logging() + + for _logger in config._get_loggers(): + with self.subTest(logger=_logger): + self.assertEqual(len(_logger.handlers), 1) + self.assertTrue(_logger.propagate) + + # cleanup + _logger.removeHandler(_logger.handlers[0]) + _logger.propagate = True + + root_logger.removeHandler(handler) + + @skipIf(LoggingHandler is None, "opentelemetry-instrumentation-logging not installed") + def test_logging_setup_set_propagate_true_if_logging_instrumentation_handler_found(self): root_logger = logging.getLogger() handler = LoggingHandler(logger_provider=mock.Mock()) root_logger.addHandler(handler) From 8c4457ce9ce6f51a4fcbda9c6fa853113b8aa8ce Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Thu, 21 May 2026 11:55:20 +0200 Subject: [PATCH 2/2] Please pyright --- src/elasticotel/distro/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elasticotel/distro/config.py b/src/elasticotel/distro/config.py index f206309..c14e17a 100644 --- a/src/elasticotel/distro/config.py +++ b/src/elasticotel/distro/config.py @@ -36,7 +36,7 @@ from opentelemetry._opamp.proto import opamp_pb2 as opamp_pb2 try: - from opentelemetry.instrumentation.logging.handler import LoggingHandler + from opentelemetry.instrumentation.logging.handler import LoggingHandler # type: ignore[reportAssignmentType] except ImportError: class LoggingHandler: