1919
2020from __future__ import annotations
2121
22+ import inspect
2223import logging
2324import os
2425from abc import ABC , abstractmethod
2526from os import environ
26- from typing import Any , Callable , Mapping , Sequence , Type , Union
27+ from typing import Any , Callable , Mapping , Optional , Sequence , Type , Union
2728
29+ from grpc import ChannelCredentials # pylint: disable=import-error
30+ from requests import Session
2831from typing_extensions import Literal
2932
3033from opentelemetry ._events import set_event_logger_provider
4548 OTEL_EXPORTER_OTLP_METRICS_PROTOCOL ,
4649 OTEL_EXPORTER_OTLP_PROTOCOL ,
4750 OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ,
51+ OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER ,
52+ OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER ,
53+ OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER ,
54+ OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER ,
4855 OTEL_TRACES_SAMPLER ,
4956 OTEL_TRACES_SAMPLER_ARG ,
5057)
7885 "logs" : OTEL_LOGS_EXPORTER ,
7986}
8087
88+ _EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE = {
89+ "traces" : OTEL_PYTHON_EXPORTER_OTLP_TRACES_CREDENTIAL_PROVIDER ,
90+ "metrics" : OTEL_PYTHON_EXPORTER_OTLP_METRICS_CREDENTIAL_PROVIDER ,
91+ "logs" : OTEL_PYTHON_EXPORTER_OTLP_LOGS_CREDENTIAL_PROVIDER ,
92+ }
93+
8194_PROTOCOL_ENV_BY_SIGNAL_TYPE = {
8295 "traces" : OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ,
8396 "metrics" : OTEL_EXPORTER_OTLP_METRICS_PROTOCOL ,
102115]
103116
104117
118+ def _load_credential_from_envvar (
119+ environment_variable : str ,
120+ ) -> Optional [
121+ tuple [
122+ Literal ["credentials" , "session" ], Union [ChannelCredentials , Session ]
123+ ]
124+ ]:
125+ credential_env = os .getenv (environment_variable )
126+ if credential_env :
127+ credentials = _import_config_component (
128+ credential_env , "opentelemetry_otlp_credential_provider"
129+ )()
130+ if isinstance (credentials , ChannelCredentials ):
131+ return ("credentials" , credentials )
132+ elif isinstance (credentials , Session ):
133+ return ("session" , credentials )
134+ else :
135+ raise RuntimeError (
136+ f"{ credential_env } is neither a ChannelCredentials or Session type."
137+ )
138+
139+
140+ def _import_config_component (
141+ selected_component : str , entry_point_name : str
142+ ) -> Type :
143+ return _import_config_components ([selected_component ], entry_point_name )[
144+ 0
145+ ][1 ]
146+
147+
105148def _import_config_components (
106149 selected_components : Sequence [str ], entry_point_name : str
107150) -> list [tuple [str , Type ]]:
@@ -201,12 +244,54 @@ def _get_exporter_names(
201244 ]
202245
203246
247+ def _init_exporter (
248+ signal_type : Literal ["traces" , "metrics" , "logs" ],
249+ exporter_args_map : Mapping [str , Any ],
250+ exporter_class : Union [
251+ Type [SpanExporter ], Type [MetricExporter ], Type [LogExporter ]
252+ ],
253+ otlp_credential_param_for_all_signal_types : Optional [
254+ tuple [
255+ Literal ["credentials" , "session" ],
256+ Union [ChannelCredentials , Session ],
257+ ]
258+ ] = None ,
259+ ) -> Union [SpanExporter , MetricExporter , LogExporter ]:
260+ otlp_credential_param_for_signal_type = _load_credential_from_envvar (
261+ _EXPORTER_CREDENTIAL_BY_SIGNAL_TYPE [signal_type ]
262+ )
263+ otlp_credential_param = (
264+ otlp_credential_param_for_signal_type
265+ or otlp_credential_param_for_all_signal_types
266+ )
267+ if not otlp_credential_param :
268+ return exporter_class (** exporter_args_map )
269+ credential_key , credential = otlp_credential_param
270+ params = inspect .signature (exporter_class .__init__ ).parameters
271+ if (
272+ credential_key == "credentials"
273+ and "credentials" in params
274+ and isinstance (credential , params ["credentials" ].annotation )
275+ ):
276+ return exporter_class (credentials = credential , ** exporter_args_map )
277+ if (
278+ credential_key == "session"
279+ and "session" in params
280+ and isinstance (credential , params ["session" ].annotation )
281+ ):
282+ return exporter_class (session = credential , ** exporter_args_map )
283+ return exporter_class (** exporter_args_map )
284+
285+
204286def _init_tracing (
205287 exporters : dict [str , Type [SpanExporter ]],
206288 id_generator : IdGenerator | None = None ,
207289 sampler : Sampler | None = None ,
208290 resource : Resource | None = None ,
209291 exporter_args_map : ExporterArgsMap | None = None ,
292+ otlp_credential_param : Optional [
293+ tuple [str , Union [ChannelCredentials , Session ]]
294+ ] = None ,
210295):
211296 provider = TracerProvider (
212297 id_generator = id_generator ,
@@ -219,16 +304,26 @@ def _init_tracing(
219304 for _ , exporter_class in exporters .items ():
220305 exporter_args = exporter_args_map .get (exporter_class , {})
221306 provider .add_span_processor (
222- BatchSpanProcessor (exporter_class (** exporter_args ))
307+ BatchSpanProcessor (
308+ _init_exporter (
309+ "traces" ,
310+ exporter_args ,
311+ exporter_class ,
312+ otlp_credential_param ,
313+ )
314+ )
223315 )
224316
225317
226318def _init_metrics (
227319 exporters_or_readers : dict [
228320 str , Union [Type [MetricExporter ], Type [MetricReader ]]
229321 ],
230- resource : Resource | None = None ,
322+ resource : Resource = None ,
231323 exporter_args_map : ExporterArgsMap | None = None ,
324+ otlp_credential_param : Optional [
325+ tuple [str , Union [ChannelCredentials , Session ]]
326+ ] = None ,
232327):
233328 metric_readers = []
234329
@@ -240,7 +335,12 @@ def _init_metrics(
240335 else :
241336 metric_readers .append (
242337 PeriodicExportingMetricReader (
243- exporter_or_reader_class (** exporter_args )
338+ _init_exporter (
339+ "metrics" ,
340+ exporter_args ,
341+ exporter_or_reader_class ,
342+ otlp_credential_param ,
343+ )
244344 )
245345 )
246346
@@ -253,6 +353,9 @@ def _init_logging(
253353 resource : Resource | None = None ,
254354 setup_logging_handler : bool = True ,
255355 exporter_args_map : ExporterArgsMap | None = None ,
356+ otlp_credential_param : Optional [
357+ tuple [str , Union [ChannelCredentials , Session ]]
358+ ] = None ,
256359):
257360 provider = LoggerProvider (resource = resource )
258361 set_logger_provider (provider )
@@ -261,7 +364,14 @@ def _init_logging(
261364 for _ , exporter_class in exporters .items ():
262365 exporter_args = exporter_args_map .get (exporter_class , {})
263366 provider .add_log_record_processor (
264- BatchLogRecordProcessor (exporter_class (** exporter_args ))
367+ BatchLogRecordProcessor (
368+ _init_exporter (
369+ "logs" ,
370+ exporter_args ,
371+ exporter_class ,
372+ otlp_credential_param ,
373+ )
374+ )
265375 )
266376
267377 event_logger_provider = EventLoggerProvider (logger_provider = provider )
@@ -438,15 +548,22 @@ def _initialize_components(
438548 # from the env variable else defaults to "unknown_service"
439549 resource = Resource .create (resource_attributes )
440550
551+ otlp_credential_param = _load_credential_from_envvar (
552+ OTEL_PYTHON_EXPORTER_OTLP_CREDENTIAL_PROVIDER
553+ )
441554 _init_tracing (
442555 exporters = span_exporters ,
443556 id_generator = id_generator ,
444557 sampler = sampler ,
445558 resource = resource ,
559+ otlp_credential_param = otlp_credential_param ,
446560 exporter_args_map = exporter_args_map ,
447561 )
448562 _init_metrics (
449- metric_exporters , resource , exporter_args_map = exporter_args_map
563+ metric_exporters ,
564+ resource ,
565+ otlp_credential_param = otlp_credential_param ,
566+ exporter_args_map = exporter_args_map ,
450567 )
451568 if setup_logging_handler is None :
452569 setup_logging_handler = (
@@ -461,6 +578,7 @@ def _initialize_components(
461578 log_exporters ,
462579 resource ,
463580 setup_logging_handler ,
581+ otlp_credential_param = otlp_credential_param ,
464582 exporter_args_map = exporter_args_map ,
465583 )
466584
0 commit comments