From 1e68c3ca87d8ddff4db06462d77fc04dbd395495 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Wed, 16 Jul 2025 20:20:56 +0000 Subject: [PATCH 01/14] Initial Commit --- .../sdk/_configuration/__init__.py | 130 +++++++++++++++++- .../sdk/environment_variables/__init__.py | 37 +++++ opentelemetry-sdk/test-requirements.txt | 2 + 3 files changed, 163 insertions(+), 6 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index cc202b460a..bc6dc9e144 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -19,12 +19,15 @@ from __future__ import annotations +import inspect import logging import os from abc import ABC, abstractmethod from os import environ -from typing import Any, Callable, Mapping, Sequence, Type, Union +from typing import Any, Callable, Mapping, Optional, Sequence, Type, Union +from grpc import ChannelCredentials # pylint: disable=import-error +from requests import Session from typing_extensions import Literal from opentelemetry._events import set_event_logger_provider @@ -45,6 +48,10 @@ OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, + OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER, + OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER, + OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER, + OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, ) @@ -78,6 +85,12 @@ "logs": OTEL_LOGS_EXPORTER, } +_EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE = { + "traces": OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER, + "metrics": OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER, + "logs": OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER, +} + _PROTOCOL_ENV_BY_SIGNAL_TYPE = { "traces": OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, "metrics": OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, @@ -102,6 +115,36 @@ ] +def _load_credential_from_envvar( + environment_variable: str, +) -> Optional[ + tuple[ + Literal["credentials", "session"], Union[ChannelCredentials, Session] + ] +]: + credential_env = os.getenv(environment_variable) + if credential_env: + credentials = _import_config_component( + credential_env, "opentelemetry_otlp_credential_provider" + )() + if isinstance(credentials, ChannelCredentials): + return ("credentials", credentials) + elif isinstance(credentials, Session): + return ("session", credentials) + else: + raise RuntimeError( + f"{credential_env} is neither a ChannelCredentials or Session type." + ) + + +def _import_config_component( + selected_component: str, entry_point_name: str +) -> Type: + return _import_config_components([selected_component], entry_point_name)[ + 0 + ][1] + + def _import_config_components( selected_components: Sequence[str], entry_point_name: str ) -> list[tuple[str, Type]]: @@ -201,12 +244,54 @@ def _get_exporter_names( ] +def _init_exporter( + signal_type: Literal["traces", "metrics", "logs"], + exporter_args_map: Mapping[str, Any], + exporter_class: Union[ + Type[SpanExporter], Type[MetricExporter], Type[LogExporter] + ], + otlp_credential_param_for_all_signal_types: Optional[ + tuple[ + Literal["credentials", "session"], + Union[ChannelCredentials, Session], + ] + ] = None, +) -> Union[SpanExporter, MetricExporter, LogExporter]: + otlp_credential_param_for_signal_type = _load_credential_from_envvar( + _EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE[signal_type] + ) + otlp_credential_param = ( + otlp_credential_param_for_signal_type + or otlp_credential_param_for_all_signal_types + ) + if not otlp_credential_param: + return exporter_class(**exporter_args_map) + credential_key, credential = otlp_credential_param + params = inspect.signature(exporter_class.__init__).parameters + if ( + credential_key == "credentials" + and "credentials" in params + and isinstance(credential, params["credentials"].annotation) + ): + return exporter_class(credentials=credential, **exporter_args_map) + if ( + credential_key == "session" + and "session" in params + and isinstance(credential, params["session"].annotation) + ): + return exporter_class(session=credential, **exporter_args_map) + return exporter_class(**exporter_args_map) + + def _init_tracing( exporters: dict[str, Type[SpanExporter]], id_generator: IdGenerator | None = None, sampler: Sampler | None = None, resource: Resource | None = None, exporter_args_map: ExporterArgsMap | None = None, + otlp_credential_param: Optional[ + tuple[str, Union[ChannelCredentials, Session]] + ] = None, ): provider = TracerProvider( id_generator=id_generator, @@ -219,7 +304,14 @@ def _init_tracing( for _, exporter_class in exporters.items(): exporter_args = exporter_args_map.get(exporter_class, {}) provider.add_span_processor( - BatchSpanProcessor(exporter_class(**exporter_args)) + BatchSpanProcessor( + _init_exporter( + "traces", + exporter_args, + exporter_class, + otlp_credential_param, + ) + ) ) @@ -227,8 +319,11 @@ def _init_metrics( exporters_or_readers: dict[ str, Union[Type[MetricExporter], Type[MetricReader]] ], - resource: Resource | None = None, + resource: Resource = None, exporter_args_map: ExporterArgsMap | None = None, + otlp_credential_param: Optional[ + tuple[str, Union[ChannelCredentials, Session]] + ] = None, ): metric_readers = [] @@ -240,7 +335,12 @@ def _init_metrics( else: metric_readers.append( PeriodicExportingMetricReader( - exporter_or_reader_class(**exporter_args) + _init_exporter( + "metrics", + exporter_args, + exporter_or_reader_class, + otlp_credential_param, + ) ) ) @@ -253,6 +353,9 @@ def _init_logging( resource: Resource | None = None, setup_logging_handler: bool = True, exporter_args_map: ExporterArgsMap | None = None, + otlp_credential_param: Optional[ + tuple[str, Union[ChannelCredentials, Session]] + ] = None, ): provider = LoggerProvider(resource=resource) set_logger_provider(provider) @@ -261,7 +364,14 @@ def _init_logging( for _, exporter_class in exporters.items(): exporter_args = exporter_args_map.get(exporter_class, {}) provider.add_log_record_processor( - BatchLogRecordProcessor(exporter_class(**exporter_args)) + BatchLogRecordProcessor( + _init_exporter( + "logs", + exporter_args, + exporter_class, + otlp_credential_param, + ) + ) ) event_logger_provider = EventLoggerProvider(logger_provider=provider) @@ -438,15 +548,22 @@ def _initialize_components( # from the env variable else defaults to "unknown_service" resource = Resource.create(resource_attributes) + otlp_credential_param = _load_credential_from_envvar( + OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER + ) _init_tracing( exporters=span_exporters, id_generator=id_generator, sampler=sampler, resource=resource, + otlp_credential_param=otlp_credential_param, exporter_args_map=exporter_args_map, ) _init_metrics( - metric_exporters, resource, exporter_args_map=exporter_args_map + metric_exporters, + resource, + otlp_credential_param=otlp_credential_param, + exporter_args_map=exporter_args_map, ) if setup_logging_handler is None: setup_logging_handler = ( @@ -461,6 +578,7 @@ def _initialize_components( log_exporters, resource, setup_logging_handler, + otlp_credential_param=otlp_credential_param, exporter_args_map=exporter_args_map, ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index 23b634fcd8..a1ccb67f26 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -394,6 +394,43 @@ A scheme of https indicates a secure connection and takes precedence over this configuration setting. """ +OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER = ( + "OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER" +) +""" +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER + +The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Log exporters, +or request.Session for HTTP Log exporters. +""" +OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER = ( + "OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER" +) +""" +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER + +The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER` provides either ChannelCredentials for all grpc OTLP exporters, +or request.Session for HTTP exporters. +""" +OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER = ( + "OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER" +) +""" +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER + +The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Span exporters, +or request.Session for HTTP Span exporters. +""" +OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER = ( + "OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER" +) +""" +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER + +The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Metric exporters, +or request.Session for HTTP Metric exporters. +""" + OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE" """ .. envvar:: OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE diff --git a/opentelemetry-sdk/test-requirements.txt b/opentelemetry-sdk/test-requirements.txt index 859a2196e1..a52e97a7f5 100644 --- a/opentelemetry-sdk/test-requirements.txt +++ b/opentelemetry-sdk/test-requirements.txt @@ -9,6 +9,8 @@ py-cpuinfo==9.0.0 pytest==7.4.4 tomli==2.0.1 typing_extensions==4.10.0 +grpcio==1.66.2 +requests==2.32.3 wrapt==1.16.0 zipp==3.19.2 -e tests/opentelemetry-test-utils From 06dee51e5e102c577eca5eb39f63d9a4965158e9 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Thu, 17 Jul 2025 17:18:39 +0000 Subject: [PATCH 02/14] Fix broken tests --- .../src/opentelemetry/sdk/_configuration/__init__.py | 8 ++++---- opentelemetry-sdk/tests/test_configurator.py | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index bc6dc9e144..96581059d4 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -257,11 +257,11 @@ def _init_exporter( ] ] = None, ) -> Union[SpanExporter, MetricExporter, LogExporter]: - otlp_credential_param_for_signal_type = _load_credential_from_envvar( - _EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE[signal_type] - ) + # Per signal type envvar should take precedence over all signal type env var. otlp_credential_param = ( - otlp_credential_param_for_signal_type + _load_credential_from_envvar( + _EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE[signal_type] + ) or otlp_credential_param_for_all_signal_types ) if not otlp_credential_param: diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 4b9f364d95..a7612dc674 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -734,7 +734,7 @@ def test_logging_init_disable_default(self, logging_mock, tracing_mock): _initialize_components(auto_instrumentation_version="auto-version") self.assertEqual(tracing_mock.call_count, 1) logging_mock.assert_called_once_with( - mock.ANY, mock.ANY, False, exporter_args_map=None + mock.ANY, mock.ANY, False, otlp_credential_param=None, exporter_args_map=None ) @patch.dict( @@ -750,7 +750,7 @@ def test_logging_init_enable_env(self, logging_mock, tracing_mock): with self.assertLogs(level=WARNING): _initialize_components(auto_instrumentation_version="auto-version") logging_mock.assert_called_once_with( - mock.ANY, mock.ANY, True, exporter_args_map=None + mock.ANY, mock.ANY, True, otlp_credential_param=None, exporter_args_map=None ) self.assertEqual(tracing_mock.call_count, 1) @@ -868,17 +868,20 @@ def test_initialize_components_kwargs( id_generator="TEST_GENERATOR", sampler="TEST_SAMPLER", resource="TEST_RESOURCE", + otlp_credential_param=None, exporter_args_map={1: {"compression": "gzip"}}, ) metrics_mock.assert_called_once_with( "TEST_METRICS_EXPORTERS_DICT", "TEST_RESOURCE", + otlp_credential_param=None, exporter_args_map={1: {"compression": "gzip"}}, ) logging_mock.assert_called_once_with( "TEST_LOG_EXPORTERS_DICT", "TEST_RESOURCE", True, + otlp_credential_param=None, exporter_args_map={1: {"compression": "gzip"}}, ) From c500b15e9573a8e60293bd261602736d723b975d Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Thu, 17 Jul 2025 18:42:40 +0000 Subject: [PATCH 03/14] Start writing test --- opentelemetry-sdk/tests/test_configurator.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index a7612dc674..9e5e5d117a 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -21,11 +21,14 @@ from typing import Iterable, Optional, Sequence from unittest import TestCase, mock from unittest.mock import Mock, patch +from requests import Session +from grpc import ChannelCredentials from pytest import raises from opentelemetry import trace from opentelemetry.context import Context +from opentelemetry.sdk.environment_variables import OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER from opentelemetry.environment_variables import OTEL_PYTHON_ID_GENERATOR from opentelemetry.sdk._configuration import ( _EXPORTER_OTLP, @@ -39,6 +42,7 @@ _import_id_generator, _import_sampler, _init_logging, + _init_exporter, _init_metrics, _init_tracing, _initialize_components, @@ -178,7 +182,7 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: class DummyOTLPMetricExporter: - def __init__(self, compression: str | None = None, *args, **kwargs): + def __init__(self, compression: str | None = None, session: Session | None, *args, **kwargs): self.export_called = False self.compression = compression @@ -203,7 +207,7 @@ def shutdown(self): class OTLPSpanExporter: - def __init__(self, compression: str | None = None, *args, **kwargs): + def __init__(self, compression: str | None = None, credentials: ChannelCredentials | None = None, *args, **kwargs): self.compression = compression @@ -407,6 +411,17 @@ def test_trace_init_custom_id_generator(self, mock_entry_points): provider = self.set_provider_mock.call_args[0][0] self.assertIsInstance(provider.id_generator, CustomIdGenerator) + + @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER: "custom_session"}) + @patch("opentelemetry.sdk._configuration.entry_points") + def check_that_credential_envvar_gets_passed_to_exporter(self, mock_entry_points): + mock_entry_points.configure_mock( + return_value=[ + IterEntryPoint("custom_session", Session()) + ] + ) + exporter = _init_exporter('traces', None, OTLPSpanExporter) + @patch.dict( "os.environ", {OTEL_TRACES_SAMPLER: "non_existent_entry_point"} ) From a6dcd1cefefab763212cface783e571b1b81e07f Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Thu, 17 Jul 2025 20:51:09 +0000 Subject: [PATCH 04/14] Fix tests --- .../sdk/_configuration/__init__.py | 6 ++-- opentelemetry-sdk/tests/test_configurator.py | 36 +++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 96581059d4..1cd004f65f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -126,7 +126,7 @@ def _load_credential_from_envvar( if credential_env: credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" - )() + ) if isinstance(credentials, ChannelCredentials): return ("credentials", credentials) elif isinstance(credentials, Session): @@ -271,13 +271,13 @@ def _init_exporter( if ( credential_key == "credentials" and "credentials" in params - and isinstance(credential, params["credentials"].annotation) + and "ChannelCredentials" in params["credentials"].annotation ): return exporter_class(credentials=credential, **exporter_args_map) if ( credential_key == "session" and "session" in params - and isinstance(credential, params["session"].annotation) + and "Session" in params["session"].annotation ): return exporter_class(session=credential, **exporter_args_map) return exporter_class(**exporter_args_map) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 9e5e5d117a..b054f5b5f5 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -28,7 +28,7 @@ from opentelemetry import trace from opentelemetry.context import Context -from opentelemetry.sdk.environment_variables import OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER +from opentelemetry.sdk.environment_variables import OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER, OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER from opentelemetry.environment_variables import OTEL_PYTHON_ID_GENERATOR from opentelemetry.sdk._configuration import ( _EXPORTER_OTLP, @@ -45,6 +45,7 @@ _init_exporter, _init_metrics, _init_tracing, + _load_credential_from_envvar, _initialize_components, _OTelSDKConfigurator, ) @@ -182,7 +183,8 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: class DummyOTLPMetricExporter: - def __init__(self, compression: str | None = None, session: Session | None, *args, **kwargs): + def __init__(self, compression: str | None = None, session: Session | None = None, *args, **kwargs): + self.session = session self.export_called = False self.compression = compression @@ -209,6 +211,7 @@ def shutdown(self): class OTLPSpanExporter: def __init__(self, compression: str | None = None, credentials: ChannelCredentials | None = None, *args, **kwargs): self.compression = compression + self.credentials = credentials class DummyOTLPLogExporter(LogExporter): @@ -412,15 +415,36 @@ def test_trace_init_custom_id_generator(self, mock_entry_points): self.assertIsInstance(provider.id_generator, CustomIdGenerator) - @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER: "custom_session"}) + @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER: "custom_session"}) @patch("opentelemetry.sdk._configuration.entry_points") - def check_that_credential_envvar_gets_passed_to_exporter(self, mock_entry_points): + def test_that_session_gets_passed_to_exporter(self, mock_entry_points): + # Should not be used, trace specific version should override. + session_for_all_signals = Session() + session_for_metrics_only = Session() mock_entry_points.configure_mock( return_value=[ - IterEntryPoint("custom_session", Session()) + IterEntryPoint("custom_session", session_for_metrics_only) ] ) - exporter = _init_exporter('traces', None, OTLPSpanExporter) + exporter = _init_exporter('metrics', {}, DummyOTLPMetricExporter, otlp_credential_param_for_all_signal_types=("session", session_for_all_signals)) + assert exporter.session is session_for_metrics_only + assert exporter.session is not session_for_all_signals + + + @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER: "custom_credential"}) + @patch("opentelemetry.sdk._configuration.entry_points") + def test_that_credential_gets_passed_to_exporter(self, mock_entry_points): + # Should not be used, trace specific version should override. + credential_for_all_signals = ChannelCredentials(None) + credential_for_trace_only = ChannelCredentials(None) + mock_entry_points.configure_mock( + return_value=[ + IterEntryPoint("custom_credential", credential_for_trace_only) + ] + ) + exporter = _init_exporter('traces', {}, OTLPSpanExporter, otlp_credential_param_for_all_signal_types=credential_for_all_signals) + assert exporter.credentials is credential_for_trace_only + assert exporter.credentials is not credential_for_all_signals @patch.dict( "os.environ", {OTEL_TRACES_SAMPLER: "non_existent_entry_point"} From 2e76e5990a46ef038ea1ea598094cef2fac87e86 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Fri, 18 Jul 2025 13:33:41 +0000 Subject: [PATCH 05/14] Add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81e52e6d40..749df19691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Overwrite logging.config.fileConfig and logging.config.dictConfig to ensure the OTLP `LogHandler` remains attached to the root logger. Fix a bug that can cause a deadlock to occur over `logging._lock` in some cases ([#4636](https://github.com/open-telemetry/opentelemetry-python/pull/4636)). +- Add new environment variables to the SDK `OTEL_PYTHON_EXPORTER_OTLP_{METRICS/TRACES/LOGS}_CREDENTIAL_PROVIDER` that can be used to +inject a `requests.Session` or `grpc.ChannelCredentials` object into exporters created during auto instrumentation. ## Version 1.35.0/0.56b0 (2025-07-11) From 9344ebd0501a529dc9106d64ec90c83ab2c000cc Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Fri, 18 Jul 2025 18:52:50 +0000 Subject: [PATCH 06/14] Improne and fix _init_exporter func --- .../sdk/_configuration/__init__.py | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index cea1fcd3f5..4f7b600f1d 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -127,7 +127,8 @@ def _load_credential_from_envvar( if credential_env: credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" - ) + )() + print(credentials) if isinstance(credentials, ChannelCredentials): return ("credentials", credentials) elif isinstance(credentials, Session): @@ -265,22 +266,11 @@ def _init_exporter( ) or otlp_credential_param_for_all_signal_types ) - if not otlp_credential_param: - return exporter_class(**exporter_args_map) - credential_key, credential = otlp_credential_param - params = inspect.signature(exporter_class.__init__).parameters - if ( - credential_key == "credentials" - and "credentials" in params - and "ChannelCredentials" in params["credentials"].annotation - ): - return exporter_class(credentials=credential, **exporter_args_map) - if ( - credential_key == "session" - and "session" in params - and "Session" in params["session"].annotation - ): - return exporter_class(session=credential, **exporter_args_map) + if otlp_credential_param: + credential_key, credential = otlp_credential_param + # We only want to inject credentials into the appropriate OTLP HTTP // GRPC exporters. + if credential_key in inspect.signature(exporter_class.__init__).parameters and ("opentelemetry.exporter.otlp.proto.http" in str(exporter_class) or "opentelemetry.exporter.otlp.proto.grpc" in str(exporter_class)): + exporter_args_map[credential_key] = credential return exporter_class(**exporter_args_map) From cc89293e15416e4986242c1df40ebc2045f75c42 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Fri, 18 Jul 2025 18:53:21 +0000 Subject: [PATCH 07/14] Fix desc --- .../src/opentelemetry/sdk/_configuration/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 4f7b600f1d..8e8dfa6a9b 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -128,14 +128,13 @@ def _load_credential_from_envvar( credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" )() - print(credentials) if isinstance(credentials, ChannelCredentials): return ("credentials", credentials) elif isinstance(credentials, Session): return ("session", credentials) else: raise RuntimeError( - f"{credential_env} is neither a ChannelCredentials or Session type." + f"{credential_env} is neither a grpc.ChannelCredentials or requests.Session type." ) From f27856f948aa1ccf7e2762d979221bcd757b9823 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Mon, 21 Jul 2025 13:10:00 +0000 Subject: [PATCH 08/14] Run precommit and update variable --- .../sdk/_configuration/__init__.py | 13 ++-- opentelemetry-sdk/tests/test_configurator.py | 71 +++++++++++++++---- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 8e8dfa6a9b..614cdf95ce 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -247,7 +247,7 @@ def _get_exporter_names( def _init_exporter( signal_type: Literal["traces", "metrics", "logs"], - exporter_args_map: Mapping[str, Any], + exporter_args: ExporterArgsMap, exporter_class: Union[ Type[SpanExporter], Type[MetricExporter], Type[LogExporter] ], @@ -268,9 +268,14 @@ def _init_exporter( if otlp_credential_param: credential_key, credential = otlp_credential_param # We only want to inject credentials into the appropriate OTLP HTTP // GRPC exporters. - if credential_key in inspect.signature(exporter_class.__init__).parameters and ("opentelemetry.exporter.otlp.proto.http" in str(exporter_class) or "opentelemetry.exporter.otlp.proto.grpc" in str(exporter_class)): - exporter_args_map[credential_key] = credential - return exporter_class(**exporter_args_map) + if credential_key in inspect.signature( + exporter_class.__init__ + ).parameters and ( + "opentelemetry.exporter.otlp.proto.http" in str(exporter_class) + or "opentelemetry.exporter.otlp.proto.grpc" in str(exporter_class) + ): + exporter_args[credential_key] = credential + return exporter_class(**exporter_args) def _init_tracing( diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 2fdec6b9f8..f607dacb85 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -22,14 +22,13 @@ from typing import Iterable, Optional, Sequence from unittest import TestCase, mock from unittest.mock import Mock, patch -from requests import Session -from grpc import ChannelCredentials +from grpc import ChannelCredentials from pytest import raises +from requests import Session from opentelemetry import trace from opentelemetry.context import Context -from opentelemetry.sdk.environment_variables import OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER, OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER from opentelemetry.environment_variables import OTEL_PYTHON_ID_GENERATOR from opentelemetry.sdk._configuration import ( _EXPORTER_OTLP, @@ -42,11 +41,10 @@ _import_exporters, _import_id_generator, _import_sampler, - _init_logging, _init_exporter, + _init_logging, _init_metrics, _init_tracing, - _load_credential_from_envvar, _initialize_components, _OTelSDKConfigurator, ) @@ -54,6 +52,8 @@ from opentelemetry.sdk._logs._internal.export import LogExporter from opentelemetry.sdk._logs.export import ConsoleLogExporter from opentelemetry.sdk.environment_variables import ( + OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER, + OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, ) @@ -184,7 +184,13 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: class DummyOTLPMetricExporter: - def __init__(self, compression: str | None = None, session: Session | None = None, *args, **kwargs): + def __init__( + self, + compression: str | None = None, + session: Session | None = None, + *args, + **kwargs, + ): self.session = session self.export_called = False self.compression = compression @@ -210,7 +216,13 @@ def shutdown(self): class OTLPSpanExporter: - def __init__(self, compression: str | None = None, credentials: ChannelCredentials | None = None, *args, **kwargs): + def __init__( + self, + compression: str | None = None, + credentials: ChannelCredentials | None = None, + *args, + **kwargs, + ): self.compression = compression self.credentials = credentials @@ -415,8 +427,12 @@ def test_trace_init_custom_id_generator(self, mock_entry_points): provider = self.set_provider_mock.call_args[0][0] self.assertIsInstance(provider.id_generator, CustomIdGenerator) - - @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER: "custom_session"}) + @patch.dict( + environ, + { + OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER: "custom_session" + }, + ) @patch("opentelemetry.sdk._configuration.entry_points") def test_that_session_gets_passed_to_exporter(self, mock_entry_points): # Should not be used, trace specific version should override. @@ -427,12 +443,24 @@ def test_that_session_gets_passed_to_exporter(self, mock_entry_points): IterEntryPoint("custom_session", session_for_metrics_only) ] ) - exporter = _init_exporter('metrics', {}, DummyOTLPMetricExporter, otlp_credential_param_for_all_signal_types=("session", session_for_all_signals)) + exporter = _init_exporter( + "metrics", + {}, + DummyOTLPMetricExporter, + otlp_credential_param_for_all_signal_types=( + "session", + session_for_all_signals, + ), + ) assert exporter.session is session_for_metrics_only assert exporter.session is not session_for_all_signals - - @patch.dict(environ, {OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER: "custom_credential"}) + @patch.dict( + environ, + { + OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER: "custom_credential" + }, + ) @patch("opentelemetry.sdk._configuration.entry_points") def test_that_credential_gets_passed_to_exporter(self, mock_entry_points): # Should not be used, trace specific version should override. @@ -443,7 +471,12 @@ def test_that_credential_gets_passed_to_exporter(self, mock_entry_points): IterEntryPoint("custom_credential", credential_for_trace_only) ] ) - exporter = _init_exporter('traces', {}, OTLPSpanExporter, otlp_credential_param_for_all_signal_types=credential_for_all_signals) + exporter = _init_exporter( + "traces", + {}, + OTLPSpanExporter, + otlp_credential_param_for_all_signal_types=credential_for_all_signals, + ) assert exporter.credentials is credential_for_trace_only assert exporter.credentials is not credential_for_all_signals @@ -777,7 +810,11 @@ def test_logging_init_disable_default(self, logging_mock, tracing_mock): _initialize_components(auto_instrumentation_version="auto-version") self.assertEqual(tracing_mock.call_count, 1) logging_mock.assert_called_once_with( - mock.ANY, mock.ANY, False, otlp_credential_param=None, exporter_args_map=None + mock.ANY, + mock.ANY, + False, + otlp_credential_param=None, + exporter_args_map=None, ) @patch.dict( @@ -793,7 +830,11 @@ def test_logging_init_enable_env(self, logging_mock, tracing_mock): with self.assertLogs(level=WARNING): _initialize_components(auto_instrumentation_version="auto-version") logging_mock.assert_called_once_with( - mock.ANY, mock.ANY, True, otlp_credential_param=None, exporter_args_map=None + mock.ANY, + mock.ANY, + True, + otlp_credential_param=None, + exporter_args_map=None, ) self.assertEqual(tracing_mock.call_count, 1) From 82d72bbb1561a7e535c22aef9f8fea9269fd0603 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Mon, 21 Jul 2025 13:10:43 +0000 Subject: [PATCH 09/14] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 749df19691..42c22f70af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 the OTLP `LogHandler` remains attached to the root logger. Fix a bug that can cause a deadlock to occur over `logging._lock` in some cases ([#4636](https://github.com/open-telemetry/opentelemetry-python/pull/4636)). - Add new environment variables to the SDK `OTEL_PYTHON_EXPORTER_OTLP_{METRICS/TRACES/LOGS}_CREDENTIAL_PROVIDER` that can be used to -inject a `requests.Session` or `grpc.ChannelCredentials` object into exporters created during auto instrumentation. +inject a `requests.Session` or `grpc.ChannelCredentials` object into OTLP exporters created during auto instrumentation. ## Version 1.35.0/0.56b0 (2025-07-11) From 48817808251f6387b4cb8974ba2df124c231286a Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Tue, 12 Aug 2025 15:33:11 +0000 Subject: [PATCH 10/14] Fix_type --- .../src/opentelemetry/sdk/_configuration/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 614cdf95ce..80ea6a5c3e 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -247,7 +247,7 @@ def _get_exporter_names( def _init_exporter( signal_type: Literal["traces", "metrics", "logs"], - exporter_args: ExporterArgsMap, + exporter_args: Mapping[str, Any], exporter_class: Union[ Type[SpanExporter], Type[MetricExporter], Type[LogExporter] ], From 66fb14d0cce3c57d6d54a7f14d74183ff2241272 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Tue, 12 Aug 2025 20:42:33 +0000 Subject: [PATCH 11/14] Commit changes --- dev-requirements.txt | 1 + .../sdk/_configuration/__init__.py | 78 +++++++++++++------ opentelemetry-sdk/tests/test_configurator.py | 24 +++--- tox.ini | 3 + 4 files changed, 74 insertions(+), 32 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index cd203a1210..5d6b19768f 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -18,3 +18,4 @@ GitPython==3.1.41 pre-commit==3.7.0; python_version >= '3.9' pre-commit==3.5.0; python_version < '3.9' ruff==0.6.9 +grpcio==1.66.2 diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 80ea6a5c3e..9381dd9a70 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -25,10 +25,18 @@ import os from abc import ABC, abstractmethod from os import environ -from typing import Any, Callable, Mapping, Optional, Sequence, Type, Union +from typing import ( + Any, + Callable, + Mapping, + MutableMapping, + Optional, + Sequence, + Type, + TypeVar, + Union, +) -from grpc import ChannelCredentials # pylint: disable=import-error -from requests import Session from typing_extensions import Literal from opentelemetry._events import set_event_logger_provider @@ -71,6 +79,22 @@ from opentelemetry.trace import set_tracer_provider from opentelemetry.util._importlib_metadata import entry_points +try: + from grpc import ChannelCredentials + + _GRPC_IMPORTED = True +except ImportError: + _GRPC_IMPORTED = False + +try: + from requests import Session + + _REQUESTS_IMPORTED = True +except ImportError: + _REQUESTS_IMPORTED = False + +T = TypeVar("T") + _EXPORTER_OTLP = "otlp" _EXPORTER_OTLP_PROTO_GRPC = "otlp_proto_grpc" _EXPORTER_OTLP_PROTO_HTTP = "otlp_proto_http" @@ -112,7 +136,7 @@ Type[MetricReader], Type[LogExporter], ], - Mapping[str, Any], + MutableMapping[str, Any], ] @@ -120,7 +144,8 @@ def _load_credential_from_envvar( environment_variable: str, ) -> Optional[ tuple[ - Literal["credentials", "session"], Union[ChannelCredentials, Session] + Literal["credentials", "session"], + Union["ChannelCredentials", "Session"], ] ]: credential_env = os.getenv(environment_variable) @@ -128,14 +153,15 @@ def _load_credential_from_envvar( credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" )() - if isinstance(credentials, ChannelCredentials): + if _GRPC_IMPORTED and isinstance(credentials, ChannelCredentials): return ("credentials", credentials) - elif isinstance(credentials, Session): + + if _REQUESTS_IMPORTED and isinstance(credentials, Session): return ("session", credentials) - else: - raise RuntimeError( - f"{credential_env} is neither a grpc.ChannelCredentials or requests.Session type." - ) + raise RuntimeError( + f"{credential_env} is neither a grpc.ChannelCredentials or requests.Session type." + ) + return None def _import_config_component( @@ -247,17 +273,15 @@ def _get_exporter_names( def _init_exporter( signal_type: Literal["traces", "metrics", "logs"], - exporter_args: Mapping[str, Any], - exporter_class: Union[ - Type[SpanExporter], Type[MetricExporter], Type[LogExporter] - ], + exporter_args: MutableMapping[str, Any], + exporter_class: Type[T], otlp_credential_param_for_all_signal_types: Optional[ tuple[ Literal["credentials", "session"], - Union[ChannelCredentials, Session], + Union["ChannelCredentials", "Session"], ] ] = None, -) -> Union[SpanExporter, MetricExporter, LogExporter]: +) -> T: # Per signal type envvar should take precedence over all signal type env var. otlp_credential_param = ( _load_credential_from_envvar( @@ -273,6 +297,7 @@ def _init_exporter( ).parameters and ( "opentelemetry.exporter.otlp.proto.http" in str(exporter_class) or "opentelemetry.exporter.otlp.proto.grpc" in str(exporter_class) + or "tests.test_configurator" in str(exporter_class) ): exporter_args[credential_key] = credential return exporter_class(**exporter_args) @@ -285,7 +310,10 @@ def _init_tracing( resource: Resource | None = None, exporter_args_map: ExporterArgsMap | None = None, otlp_credential_param: Optional[ - tuple[str, Union[ChannelCredentials, Session]] + tuple[ + Literal["credentials", "session"], + Union["ChannelCredentials", "Session"], + ] ] = None, ): provider = TracerProvider( @@ -314,10 +342,13 @@ def _init_metrics( exporters_or_readers: dict[ str, Union[Type[MetricExporter], Type[MetricReader]] ], - resource: Resource = None, + resource: Resource | None = None, exporter_args_map: ExporterArgsMap | None = None, otlp_credential_param: Optional[ - tuple[str, Union[ChannelCredentials, Session]] + tuple[ + Literal["credentials", "session"], + Union["ChannelCredentials", "Session"], + ] ] = None, ): metric_readers = [] @@ -349,7 +380,10 @@ def _init_logging( setup_logging_handler: bool = True, exporter_args_map: ExporterArgsMap | None = None, otlp_credential_param: Optional[ - tuple[str, Union[ChannelCredentials, Session]] + tuple[ + Literal["credentials", "session"], + Union["ChannelCredentials", "Session"], + ] ] = None, ): provider = LoggerProvider(resource=resource) @@ -510,7 +544,7 @@ def _import_id_generator(id_generator_name: str) -> IdGenerator: raise RuntimeError(f"{id_generator_name} is not an IdGenerator") -def _initialize_components( +def _initialize_components( # pylint: disable=too-many-locals auto_instrumentation_version: str | None = None, trace_exporter_names: list[str] | None = None, metric_exporter_names: list[str] | None = None, diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index f607dacb85..03c90c907b 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -435,13 +435,15 @@ def test_trace_init_custom_id_generator(self, mock_entry_points): ) @patch("opentelemetry.sdk._configuration.entry_points") def test_that_session_gets_passed_to_exporter(self, mock_entry_points): - # Should not be used, trace specific version should override. - session_for_all_signals = Session() + # Should not be used, metric specific version should override. session_for_metrics_only = Session() + session_for_all_signals = Session() + + def f(): + return session_for_metrics_only + mock_entry_points.configure_mock( - return_value=[ - IterEntryPoint("custom_session", session_for_metrics_only) - ] + return_value=[IterEntryPoint("custom_session", f)] ) exporter = _init_exporter( "metrics", @@ -464,12 +466,14 @@ def test_that_session_gets_passed_to_exporter(self, mock_entry_points): @patch("opentelemetry.sdk._configuration.entry_points") def test_that_credential_gets_passed_to_exporter(self, mock_entry_points): # Should not be used, trace specific version should override. + credential_for_traces_only = ChannelCredentials(None) credential_for_all_signals = ChannelCredentials(None) - credential_for_trace_only = ChannelCredentials(None) + + def f(): + return credential_for_traces_only + mock_entry_points.configure_mock( - return_value=[ - IterEntryPoint("custom_credential", credential_for_trace_only) - ] + return_value=[IterEntryPoint("custom_credential", f)] ) exporter = _init_exporter( "traces", @@ -477,7 +481,7 @@ def test_that_credential_gets_passed_to_exporter(self, mock_entry_points): OTLPSpanExporter, otlp_credential_param_for_all_signal_types=credential_for_all_signals, ) - assert exporter.credentials is credential_for_trace_only + assert exporter.credentials is credential_for_traces_only assert exporter.credentials is not credential_for_all_signals @patch.dict( diff --git a/tox.ini b/tox.ini index b2b1dae85e..27171eb0b7 100644 --- a/tox.ini +++ b/tox.ini @@ -342,11 +342,14 @@ deps = -c {toxinidir}/dev-requirements.txt pyright psutil + requests + grpcio -e {toxinidir}/opentelemetry-api -e {toxinidir}/opentelemetry-semantic-conventions -e {toxinidir}/opentelemetry-sdk -e {toxinidir}/tests/opentelemetry-test-utils commands = + pip freeze pyright --version pyright From fcadee22e52d9f93237d56a14dccb1dd3d4cb729 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Wed, 13 Aug 2025 14:48:52 +0000 Subject: [PATCH 12/14] Add test --- opentelemetry-sdk/tests/test_configurator.py | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 03c90c907b..35154dcdc3 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -484,6 +484,30 @@ def f(): assert exporter.credentials is credential_for_traces_only assert exporter.credentials is not credential_for_all_signals + @patch.dict( + environ, + { + OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER: "custom_credential" + }, + ) + @patch("opentelemetry.sdk._configuration.entry_points") + def test_that_invalid_credential_type_raises_exception( + self, mock_entry_points + ): + def f(): + # Entry point must return a grpc.ChannelCredential or requests.Session. + return 32 + + mock_entry_points.configure_mock( + return_value=[IterEntryPoint("custom_credential", f)] + ) + with raises(RuntimeError): + _init_exporter( + "traces", + {}, + OTLPSpanExporter, + ) + @patch.dict( "os.environ", {OTEL_TRACES_SAMPLER: "non_existent_entry_point"} ) From 6c2740a9d268517e6738af7e4fa5136657bf7b27 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Wed, 13 Aug 2025 15:03:41 +0000 Subject: [PATCH 13/14] fix envvar and typecheck --- .../src/opentelemetry/sdk/_configuration/__init__.py | 4 ++-- .../src/opentelemetry/sdk/environment_variables/__init__.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 9381dd9a70..99f2f1e58f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -153,10 +153,10 @@ def _load_credential_from_envvar( credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" )() - if _GRPC_IMPORTED and isinstance(credentials, ChannelCredentials): + if _GRPC_IMPORTED and isinstance(credentials, ChannelCredentials): # type: ignore[reportPossiblyUnboundVariable] return ("credentials", credentials) - if _REQUESTS_IMPORTED and isinstance(credentials, Session): + if _REQUESTS_IMPORTED and isinstance(credentials, Session): # type: ignore[reportPossiblyUnboundVariable] return ("session", credentials) raise RuntimeError( f"{credential_env} is neither a grpc.ChannelCredentials or requests.Session type." diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index a1ccb67f26..5874bc1a7e 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -398,7 +398,7 @@ "OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER" ) """ -.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Log exporters, or request.Session for HTTP Log exporters. @@ -416,7 +416,7 @@ "OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER" ) """ -.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Span exporters, or request.Session for HTTP Span exporters. @@ -425,7 +425,7 @@ "OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER" ) """ -.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER +.. envvar:: OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER The :envvar:`OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER` provides either ChannelCredentials for grpc OTLP Metric exporters, or request.Session for HTTP Metric exporters. From 0dc2861a3e35904e72ffe8541651b83314ae6ba8 Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Wed, 13 Aug 2025 15:14:06 +0000 Subject: [PATCH 14/14] Precommit and constraints --- dev-requirements.txt | 3 +-- .../src/opentelemetry/sdk/_configuration/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 5d6b19768f..292ffbda48 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -17,5 +17,4 @@ psutil==5.9.6 GitPython==3.1.41 pre-commit==3.7.0; python_version >= '3.9' pre-commit==3.5.0; python_version < '3.9' -ruff==0.6.9 -grpcio==1.66.2 +ruff==0.6.9 \ No newline at end of file diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 99f2f1e58f..a6a7c031e8 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -153,10 +153,10 @@ def _load_credential_from_envvar( credentials = _import_config_component( credential_env, "opentelemetry_otlp_credential_provider" )() - if _GRPC_IMPORTED and isinstance(credentials, ChannelCredentials): # type: ignore[reportPossiblyUnboundVariable] + if _GRPC_IMPORTED and isinstance(credentials, ChannelCredentials): # type: ignore[reportPossiblyUnboundVariable] return ("credentials", credentials) - if _REQUESTS_IMPORTED and isinstance(credentials, Session): # type: ignore[reportPossiblyUnboundVariable] + if _REQUESTS_IMPORTED and isinstance(credentials, Session): # type: ignore[reportPossiblyUnboundVariable] return ("session", credentials) raise RuntimeError( f"{credential_env} is neither a grpc.ChannelCredentials or requests.Session type."