From 8f8d0192e4901c97b1ffebdc84161f059d56acbe Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 11:40:12 -0800 Subject: [PATCH 01/11] Creating a OTLPSpanExporter if configured in environment --- .../observability/core/config.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 6c3befdf..6b906c95 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +import os import logging import threading from collections.abc import Callable @@ -10,6 +11,7 @@ from opentelemetry.sdk.resources import SERVICE_NAME, SERVICE_NAMESPACE, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ConsoleSpanExporter +from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from .exporters.agent365_exporter import _Agent365Exporter from .exporters.agent365_exporter_options import Agent365ExporterOptions @@ -154,6 +156,7 @@ def _configure_internal( "max_export_batch_size": exporter_options.max_export_batch_size, } + exporter = None if is_agent365_exporter_enabled() and exporter_options.token_resolver is not None: exporter = _Agent365Exporter( token_resolver=exporter_options.token_resolver, @@ -161,11 +164,19 @@ def _configure_internal( use_s2s_endpoint=exporter_options.use_s2s_endpoint, suppress_invoke_agent_input=suppress_invoke_agent_input, ) + else: - exporter = ConsoleSpanExporter() - self._logger.warning( - "is_agent365_exporter_enabled() not enabled or token_resolver not set.Falling back to console exporter." - ) + + if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"): + exporter = OTLPSpanExporter() + self._logger.warning( + "is_agent365_exporter_enabled() not enabled or token_resolver not set. Falling back to OTLP exporter." + ) + else: + exporter = ConsoleSpanExporter() + self._logger.warning( + "is_agent365_exporter_enabled() not enabled or token_resolver not set.Falling back to console exporter." + ) # Add span processors From f72fbb18e3b3884362dddb68ec58f33a55d61cb4 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 14:13:22 -0800 Subject: [PATCH 02/11] Reformatting --- .../microsoft_agents_a365/observability/core/config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 6b906c95..e98a5694 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -164,9 +164,8 @@ def _configure_internal( use_s2s_endpoint=exporter_options.use_s2s_endpoint, suppress_invoke_agent_input=suppress_invoke_agent_input, ) - - else: + else: if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"): exporter = OTLPSpanExporter() self._logger.warning( From 0517c1e0cee3c6b6d3a9e7c7334e09e28648a9ce Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 14:37:02 -0800 Subject: [PATCH 03/11] Making OTLPSpanExporter be an additional flag rather than only used as a fallback --- .../observability/core/config.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index e98a5694..2f0ca747 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -166,16 +166,10 @@ def _configure_internal( ) else: - if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"): - exporter = OTLPSpanExporter() - self._logger.warning( - "is_agent365_exporter_enabled() not enabled or token_resolver not set. Falling back to OTLP exporter." - ) - else: - exporter = ConsoleSpanExporter() - self._logger.warning( - "is_agent365_exporter_enabled() not enabled or token_resolver not set.Falling back to console exporter." - ) + exporter = ConsoleSpanExporter() + self._logger.warning( + "is_agent365_exporter_enabled() not enabled or token_resolver not set. Falling back to console exporter." + ) # Add span processors @@ -191,6 +185,13 @@ def _configure_internal( self._span_processors["batch"] = batch_processor self._span_processors["agent"] = agent_processor + if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"): + # The OTLPSpanExporter is auto configured from the environment variables + otlp_exporter = OTLPSpanExporter() + tracer_provider.add_span_processor( + _EnrichingBatchSpanProcessor(otlp_exporter, **batch_processor_kwargs) + ) + # Configure logging if logger_name is provided if logger_name: target_logger = logging.getLogger(logger_name) From 213f8827bfeef6150536e4263111e15090510cc0 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 14:38:19 -0800 Subject: [PATCH 04/11] Removing unnecessary line --- .../microsoft_agents_a365/observability/core/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 2f0ca747..48d8fd31 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -156,7 +156,6 @@ def _configure_internal( "max_export_batch_size": exporter_options.max_export_batch_size, } - exporter = None if is_agent365_exporter_enabled() and exporter_options.token_resolver is not None: exporter = _Agent365Exporter( token_resolver=exporter_options.token_resolver, From 3b3cce186d5430ce038bb8f9b42b3f54a15bd486 Mon Sep 17 00:00:00 2001 From: rodrigobr-msft Date: Fri, 27 Feb 2026 14:55:08 -0800 Subject: [PATCH 05/11] Update libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../microsoft_agents_a365/observability/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 48d8fd31..25d56aaf 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -1,8 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -import os import logging +import os import threading from collections.abc import Callable from typing import Any, Optional From b7dbff5b7d852347dbe70eabd7d37edd94e05f6e Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 15:00:01 -0800 Subject: [PATCH 06/11] Adding tests --- tests/observability/core/test_agent365.py | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/observability/core/test_agent365.py b/tests/observability/core/test_agent365.py index 358b9351..9795f711 100644 --- a/tests/observability/core/test_agent365.py +++ b/tests/observability/core/test_agent365.py @@ -201,6 +201,42 @@ def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_i self.assertIn("_EnrichingBatchSpanProcessor", processor_types) self.assertIn("SpanProcessor", processor_types) +class TestOTLPExporterConfiguration(unittest.TestCase): + """Test suite for OTLP exporter configuration based on environment variables.""" + + @patch("microsoft_agents_a365.observability.core.config.OTLPSpanExporter") + @patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False) + @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) + @patch.dict("os.environ", {"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"}, clear=True) + def test_otlp_exporter_initialized_when_env_var_set( + self, mock_is_enabled, mock_otlp_exporter + ): + """Test that OTLPSpanExporter is initialized when OTEL_EXPORTER_OTLP_ENDPOINT is set.""" + + result = configure( + service_name="test-service", + service_namespace="test-namespace", + ) + + self.assertTrue(result, "configure() should return True") + mock_otlp_exporter.assert_called_once() + + @patch("microsoft_agents_a365.observability.core.config.OTLPSpanExporter") + @patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False) + @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) + @patch.dict("os.environ", {}, clear=True) + def test_otlp_exporter_not_initialized_when_env_var_not_set( + self, mock_is_enabled, mock_otlp_exporter + ): + """Test that OTLPSpanExporter is NOT initialized when OTEL_EXPORTER_OTLP_ENDPOINT is not set.""" + + result = configure( + service_name="test-service", + service_namespace="test-namespace", + ) + + self.assertTrue(result, "configure() should return True") + mock_otlp_exporter.assert_not_called() if __name__ == "__main__": unittest.main() From 9844ccbb6de991c888be105fc53268cdfb3e8129 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 15:02:58 -0800 Subject: [PATCH 07/11] Reformatting --- tests/observability/core/test_agent365.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/observability/core/test_agent365.py b/tests/observability/core/test_agent365.py index 9795f711..89c2b3c9 100644 --- a/tests/observability/core/test_agent365.py +++ b/tests/observability/core/test_agent365.py @@ -201,16 +201,18 @@ def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_i self.assertIn("_EnrichingBatchSpanProcessor", processor_types) self.assertIn("SpanProcessor", processor_types) + class TestOTLPExporterConfiguration(unittest.TestCase): """Test suite for OTLP exporter configuration based on environment variables.""" @patch("microsoft_agents_a365.observability.core.config.OTLPSpanExporter") - @patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False) + @patch( + "microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", + return_value=False, + ) @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) @patch.dict("os.environ", {"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"}, clear=True) - def test_otlp_exporter_initialized_when_env_var_set( - self, mock_is_enabled, mock_otlp_exporter - ): + def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_otlp_exporter): """Test that OTLPSpanExporter is initialized when OTEL_EXPORTER_OTLP_ENDPOINT is set.""" result = configure( @@ -222,7 +224,10 @@ def test_otlp_exporter_initialized_when_env_var_set( mock_otlp_exporter.assert_called_once() @patch("microsoft_agents_a365.observability.core.config.OTLPSpanExporter") - @patch("microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False) + @patch( + "microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", + return_value=False, + ) @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) @patch.dict("os.environ", {}, clear=True) def test_otlp_exporter_not_initialized_when_env_var_not_set( @@ -238,5 +243,6 @@ def test_otlp_exporter_not_initialized_when_env_var_not_set( self.assertTrue(result, "configure() should return True") mock_otlp_exporter.assert_not_called() + if __name__ == "__main__": unittest.main() From 999f056c2bb868fa88060640be2d5f8900ec08d0 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 15:11:54 -0800 Subject: [PATCH 08/11] Revised test cases --- tests/observability/core/test_agent365.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tests/observability/core/test_agent365.py b/tests/observability/core/test_agent365.py index 89c2b3c9..6f9b89b0 100644 --- a/tests/observability/core/test_agent365.py +++ b/tests/observability/core/test_agent365.py @@ -201,18 +201,13 @@ def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_i self.assertIn("_EnrichingBatchSpanProcessor", processor_types) self.assertIn("SpanProcessor", processor_types) - -class TestOTLPExporterConfiguration(unittest.TestCase): - """Test suite for OTLP exporter configuration based on environment variables.""" - @patch("microsoft_agents_a365.observability.core.config.OTLPSpanExporter") @patch( "microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False, ) - @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) @patch.dict("os.environ", {"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"}, clear=True) - def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_otlp_exporter): + def test_otlp_exporter_initialized_when_env_var_set(self, mock_otlp_exporter): """Test that OTLPSpanExporter is initialized when OTEL_EXPORTER_OTLP_ENDPOINT is set.""" result = configure( @@ -228,11 +223,8 @@ def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_ "microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False, ) - @patch("microsoft_agents_a365.observability.core.config.TelemetryManager._instance", None) @patch.dict("os.environ", {}, clear=True) - def test_otlp_exporter_not_initialized_when_env_var_not_set( - self, mock_is_enabled, mock_otlp_exporter - ): + def test_otlp_exporter_not_initialized_when_env_var_not_set(self, mock_otlp_exporter): """Test that OTLPSpanExporter is NOT initialized when OTEL_EXPORTER_OTLP_ENDPOINT is not set.""" result = configure( From e948c90e51de5b79aa5db1a58147ef636f9ea317 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 15:16:41 -0800 Subject: [PATCH 09/11] Fixing test cases --- tests/observability/core/test_agent365.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/observability/core/test_agent365.py b/tests/observability/core/test_agent365.py index 6f9b89b0..eb5dd172 100644 --- a/tests/observability/core/test_agent365.py +++ b/tests/observability/core/test_agent365.py @@ -207,7 +207,7 @@ def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_i return_value=False, ) @patch.dict("os.environ", {"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"}, clear=True) - def test_otlp_exporter_initialized_when_env_var_set(self, mock_otlp_exporter): + def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_otlp_exporter): """Test that OTLPSpanExporter is initialized when OTEL_EXPORTER_OTLP_ENDPOINT is set.""" result = configure( @@ -224,7 +224,9 @@ def test_otlp_exporter_initialized_when_env_var_set(self, mock_otlp_exporter): return_value=False, ) @patch.dict("os.environ", {}, clear=True) - def test_otlp_exporter_not_initialized_when_env_var_not_set(self, mock_otlp_exporter): + def test_otlp_exporter_not_initialized_when_env_var_not_set( + self, mock_is_enabled, mock_otlp_exporter + ): """Test that OTLPSpanExporter is NOT initialized when OTEL_EXPORTER_OTLP_ENDPOINT is not set.""" result = configure( From f238a069cee2eb3cefafdf18efc50a32f090238e Mon Sep 17 00:00:00 2001 From: rodrigobr-msft Date: Fri, 27 Feb 2026 15:19:34 -0800 Subject: [PATCH 10/11] Update libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../microsoft_agents_a365/observability/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 25d56aaf..5b3f7a0a 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -8,10 +8,10 @@ from typing import Any, Optional from opentelemetry import trace +from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import SERVICE_NAME, SERVICE_NAMESPACE, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ConsoleSpanExporter -from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from .exporters.agent365_exporter import _Agent365Exporter from .exporters.agent365_exporter_options import Agent365ExporterOptions From a71d05df5c808ed6fd5c5822ab381d6527588b26 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 27 Feb 2026 16:59:04 -0800 Subject: [PATCH 11/11] Changing env var that flags OTLPSpanExporter usage --- .../microsoft_agents_a365/observability/core/config.py | 4 ++-- tests/observability/core/test_agent365.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py index 25d56aaf..02013e84 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/config.py @@ -1,8 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -import logging import os +import logging import threading from collections.abc import Callable from typing import Any, Optional @@ -184,7 +184,7 @@ def _configure_internal( self._span_processors["batch"] = batch_processor self._span_processors["agent"] = agent_processor - if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"): + if os.environ.get("ENABLE_OTLP_EXPORTER", "").lower() == "true": # The OTLPSpanExporter is auto configured from the environment variables otlp_exporter = OTLPSpanExporter() tracer_provider.add_span_processor( diff --git a/tests/observability/core/test_agent365.py b/tests/observability/core/test_agent365.py index eb5dd172..f8c4869c 100644 --- a/tests/observability/core/test_agent365.py +++ b/tests/observability/core/test_agent365.py @@ -206,9 +206,9 @@ def test_configure_uses_existing_tracer_provider(self, mock_get_provider, mock_i "microsoft_agents_a365.observability.core.config.is_agent365_exporter_enabled", return_value=False, ) - @patch.dict("os.environ", {"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"}, clear=True) + @patch.dict("os.environ", {"ENABLE_OTLP_EXPORTER": "true"}, clear=True) def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_otlp_exporter): - """Test that OTLPSpanExporter is initialized when OTEL_EXPORTER_OTLP_ENDPOINT is set.""" + """Test that OTLPSpanExporter is initialized when ENABLE_OTLP_EXPORTER is set.""" result = configure( service_name="test-service", @@ -227,7 +227,7 @@ def test_otlp_exporter_initialized_when_env_var_set(self, mock_is_enabled, mock_ def test_otlp_exporter_not_initialized_when_env_var_not_set( self, mock_is_enabled, mock_otlp_exporter ): - """Test that OTLPSpanExporter is NOT initialized when OTEL_EXPORTER_OTLP_ENDPOINT is not set.""" + """Test that OTLPSpanExporter is NOT initialized when ENABLE_OTLP_EXPORTER is not set.""" result = configure( service_name="test-service",