Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python/packages/core/agent_framework/observability.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions python/packages/core/tests/core/test_observability.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, ReadableLogRecord
from opentelemetry.sdk._logs.export import LogRecordExporter, LogRecordExportResult

from agent_framework.observability import ObservabilitySettings

class _LogExporter(LogRecordExporter):
def export(self, batch: Sequence[ReadableLogRecord]) -> LogRecordExportResult:
return LogRecordExportResult.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


Expand Down
Loading