From f874953cf6fd44aa85fa00789c21d78ad8400647 Mon Sep 17 00:00:00 2001 From: Xuyang Cao Date: Thu, 6 Aug 2026 18:36:45 +0800 Subject: [PATCH 1/3] test: cover process-wide OpenTelemetry logging Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3020b2f8-94aa-4a19-a9df-82d0ba4b160b --- .../core/tests/core/test_observability.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/python/packages/core/tests/core/test_observability.py b/python/packages/core/tests/core/test_observability.py index 4256e62b2d..2b9a559409 100644 --- a/python/packages/core/tests/core/test_observability.py +++ b/python/packages/core/tests/core/test_observability.py @@ -3185,6 +3185,65 @@ def test_configure_providers_with_span_exporters(monkeypatch): mock_set_tracer.assert_called_once() +def test_configure_providers_with_log_exporters_attaches_root_handler(monkeypatch): + """Test _configure_providers attaches the OpenTelemetry handler to the root logger.""" + from unittest.mock import patch + + from opentelemetry.sdk._logs import LoggingHandler + from opentelemetry.sdk._logs.export import LogExportResult, LogRecordExporter + + from agent_framework.observability import ObservabilitySettings + + class _LogExporter(LogRecordExporter): + def export(self, batch): + return LogExportResult.SUCCESS + + def shutdown(self) -> None: + return None + + def force_flush(self, timeout_millis: int = 30000) -> bool: + return True + + monkeypatch.setenv("ENABLE_INSTRUMENTATION", "true") + for key in [ + "OTEL_EXPORTER_OTLP_ENDPOINT", + "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", + "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", + "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", + ]: + monkeypatch.delenv(key, raising=False) + + settings = ObservabilitySettings() + root_logger = logging.getLogger() + agent_logger = logging.getLogger("agent_framework") + original_root_handlers = list(root_logger.handlers) + original_agent_handlers = list(agent_logger.handlers) + added_root_handlers: list[logging.Handler] = [] + added_agent_handlers: list[logging.Handler] = [] + + try: + with patch("opentelemetry._logs.set_logger_provider"): + settings._configure_providers([_LogExporter()]) + + added_root_handlers = [handler for handler in root_logger.handlers if handler not in original_root_handlers] + added_agent_handlers = [handler for handler in agent_logger.handlers if handler not in original_agent_handlers] + + assert len(added_root_handlers) == 1 + assert isinstance(added_root_handlers[0], LoggingHandler) + assert added_agent_handlers == [] + finally: + for current_logger, handlers in ( + (root_logger, added_root_handlers), + (agent_logger, added_agent_handlers), + ): + for handler in handlers: + current_logger.removeHandler(handler) + logger_provider = getattr(handler, "_logger_provider", None) + if logger_provider is not None: + logger_provider.shutdown() + handler.close() + + # region Test histograms From f51c27689b08dea7b77e27124955a539e31d4370 Mon Sep 17 00:00:00 2001 From: Xuyang Cao Date: Thu, 6 Aug 2026 18:39:10 +0800 Subject: [PATCH 2/3] fix: attach OpenTelemetry handler to root logger Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3020b2f8-94aa-4a19-a9df-82d0ba4b160b --- python/packages/core/agent_framework/observability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/packages/core/agent_framework/observability.py b/python/packages/core/agent_framework/observability.py index 063947d365..41e81a1830 100644 --- a/python/packages/core/agent_framework/observability.py +++ b/python/packages/core/agent_framework/observability.py @@ -996,7 +996,7 @@ def _configure_providers( logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter)) # Attach a handler with the provider to the root logger handler = LoggingHandler(logger_provider=logger_provider) - logger.addHandler(handler) + logging.getLogger().addHandler(handler) set_logger_provider(logger_provider) # metrics From af4b22d667df2e7e1c3de84fd5907e02f2f7a514 Mon Sep 17 00:00:00 2001 From: Xuyang Cao Date: Fri, 7 Aug 2026 10:23:12 +0800 Subject: [PATCH 3/3] test: align log exporter stub with OTel types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3020b2f8-94aa-4a19-a9df-82d0ba4b160b --- python/packages/core/tests/core/test_observability.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/packages/core/tests/core/test_observability.py b/python/packages/core/tests/core/test_observability.py index 2b9a559409..a637f9e7d4 100644 --- a/python/packages/core/tests/core/test_observability.py +++ b/python/packages/core/tests/core/test_observability.py @@ -3189,14 +3189,14 @@ def test_configure_providers_with_log_exporters_attaches_root_handler(monkeypatc """Test _configure_providers attaches the OpenTelemetry handler to the root logger.""" from unittest.mock import patch - from opentelemetry.sdk._logs import LoggingHandler - from opentelemetry.sdk._logs.export import LogExportResult, LogRecordExporter + from opentelemetry.sdk._logs import LoggingHandler, ReadableLogRecord + from opentelemetry.sdk._logs.export import LogRecordExporter, LogRecordExportResult from agent_framework.observability import ObservabilitySettings class _LogExporter(LogRecordExporter): - def export(self, batch): - return LogExportResult.SUCCESS + def export(self, batch: Sequence[ReadableLogRecord]) -> LogRecordExportResult: + return LogRecordExportResult.SUCCESS def shutdown(self) -> None: return None