@@ -2359,3 +2359,85 @@ def test_the_record_handed_to_the_processor_is_not_mutated(self, monkeypatch):
23592359 assert "gcp.resource_type" not in incoming .resource .attributes
23602360 assert emitted .log_record .attributes ["event.name" ] == "gen_ai.choice"
23612361 provider .shutdown ()
2362+
2363+
2364+ class TestConfiguredOtlpSpanProcessor :
2365+ """Tests for the additive OTEL_EXPORTER_OTLP_ENDPOINT span processor."""
2366+
2367+ _EXPORTER_PATH = (
2368+ "opentelemetry.exporter.otlp.proto.http.trace_exporter.OTLPSpanExporter"
2369+ )
2370+
2371+ @staticmethod
2372+ def _tracer_provider ():
2373+ import opentelemetry .sdk .trace
2374+
2375+ return opentelemetry .sdk .trace .TracerProvider ()
2376+
2377+ @staticmethod
2378+ def _processor_count (tracer_provider ):
2379+ return len (tracer_provider ._active_span_processor ._span_processors )
2380+
2381+ @mock .patch .dict (os .environ , {}, clear = False )
2382+ def test_no_op_when_endpoint_not_set (self ):
2383+ os .environ .pop ("OTEL_EXPORTER_OTLP_ENDPOINT" , None )
2384+ os .environ .pop ("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" , None )
2385+ tracer_provider = self ._tracer_provider ()
2386+ with mock .patch (self ._EXPORTER_PATH ) as mock_exporter :
2387+ adk_template ._maybe_add_configured_otlp_span_processor (tracer_provider )
2388+ mock_exporter .assert_not_called ()
2389+ assert self ._processor_count (tracer_provider ) == 0
2390+
2391+ @pytest .mark .parametrize (
2392+ "env_var" ,
2393+ ["OTEL_EXPORTER_OTLP_ENDPOINT" , "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" ],
2394+ )
2395+ def test_adds_batch_span_processor_when_endpoint_set (self , env_var ):
2396+ import opentelemetry .sdk .trace .export
2397+
2398+ tracer_provider = self ._tracer_provider ()
2399+ with mock .patch .dict (os .environ , {env_var : "http://localhost:4318" }):
2400+ with mock .patch (self ._EXPORTER_PATH ) as mock_exporter :
2401+ adk_template ._maybe_add_configured_otlp_span_processor (
2402+ tracer_provider
2403+ )
2404+ # The exporter is built with no arguments so it reads OTEL_EXPORTER_OTLP_*.
2405+ mock_exporter .assert_called_once_with ()
2406+ processors = tracer_provider ._active_span_processor ._span_processors
2407+ assert len (processors ) == 1
2408+ assert isinstance (
2409+ processors [0 ], opentelemetry .sdk .trace .export .BatchSpanProcessor
2410+ )
2411+ tracer_provider .shutdown ()
2412+
2413+ def test_does_not_remove_existing_processors (self ):
2414+ tracer_provider = self ._tracer_provider ()
2415+ existing = mock .MagicMock ()
2416+ tracer_provider .add_span_processor (existing )
2417+ with mock .patch .dict (
2418+ os .environ , {"OTEL_EXPORTER_OTLP_ENDPOINT" : "http://localhost:4318" }
2419+ ):
2420+ with mock .patch (self ._EXPORTER_PATH ):
2421+ adk_template ._maybe_add_configured_otlp_span_processor (
2422+ tracer_provider
2423+ )
2424+ processors = tracer_provider ._active_span_processor ._span_processors
2425+ assert len (processors ) == 2
2426+ assert processors [0 ] is existing
2427+ tracer_provider .shutdown ()
2428+
2429+ def test_warns_and_skips_when_exporter_not_installed (self ):
2430+ tracer_provider = self ._tracer_provider ()
2431+ with mock .patch .dict (
2432+ os .environ , {"OTEL_EXPORTER_OTLP_ENDPOINT" : "http://localhost:4318" }
2433+ ):
2434+ with mock .patch .dict (
2435+ sys .modules ,
2436+ {"opentelemetry.exporter.otlp.proto.http.trace_exporter" : None },
2437+ ):
2438+ with mock .patch .object (adk_template , "_warn" ) as mock_warn :
2439+ adk_template ._maybe_add_configured_otlp_span_processor (
2440+ tracer_provider
2441+ )
2442+ mock_warn .assert_called_once ()
2443+ assert self ._processor_count (tracer_provider ) == 0
0 commit comments