Repository navigation
Description
Observed Behavior
configure_otel_providers attaches an OpenTelemetry LoggingHandler to the agent_framework logger (observability.py, _configure_providers), although the adjacent comment says "to the root logger". If the application has also attached an OTel LoggingHandler to the root logger (for example to export its own, httpx and azure logs), every agent_framework.* log record is exported twice: once by the MAF handler and once by the root handler after propagation.
Expected Behavior
Each log record is exported once. When the root logger already has an OTel LoggingHandler, MAF's records already reach the exporter through propagation, so MAF should not add a second handler.
Steps to Reproduce
- Call
configure_otel_providerswith a log exporter. - Attach
LoggingHandler(logger_provider=get_logger_provider())to the root logger. - Emit a record from an
agent_framework.*logger. - Inspect the exported records.
Minimal Reproduction
import logging
from opentelemetry._logs import get_logger_provider
from opentelemetry.sdk._logs import LoggingHandler
from opentelemetry.sdk._logs.export import InMemoryLogRecordExporter
from agent_framework.observability import configure_otel_providers
exporter = InMemoryLogRecordExporter()
configure_otel_providers(exporters=[exporter])
logging.getLogger().addHandler(LoggingHandler(logger_provider=get_logger_provider()))
logging.getLogger().setLevel(logging.INFO)
logging.getLogger("agent_framework.test").warning("hello")
get_logger_provider().force_flush()
print(len(exporter.get_finished_logs())) # prints 2, expected 1Package Versions
agent-framework-core: 1.23.0 (main), opentelemetry-sdk: 1.44.0
Python Version
Python 3.13
Operating System
macOS
Regression
Unknown
Additional Context
Proposed fix: before adding the handler, skip it if the root logger already has an OTel LoggingHandler. This only helps when the application attaches its root handler before calling configure_otel_providers; applications that attach it afterwards still need to remove the MAF handler themselves. The comment should also be corrected to say agent_framework logger. I have a small PR ready if the direction is agreeable.
AI assistance: the issue analysis, reproduction and this write-up were prepared with AI assistance. I ran the reproduction and verified the output myself.
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Oct 30, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
python/packages/core/agent_framework/observability.py::ObservabilitySettings._configure_providersat lines 1353-1361 duplicates exports when log exporters are configured and the root logger also has an OTelLoggingHandler. Minimal repro: configure anInMemoryLogRecordExporter, add a handler using the global provider to root, emit oneagent_framework.testwarning, flush, and observe two records.python/packages/core/tests/core/test_observability.py::test_configure_otel_providers_does_not_duplicate_logs_with_root_otel_handler1.23.01.24.0eavanvalkenburg commentedon Nov 2, 2026
Maintainer direction: this should not change
configure_otel_providers()runtime behavior. Resolve the issue by clarifying the function’s docstring.configure_otel_providers()is a convenience setup for Agent Framework telemetry; it does not inspect, coordinate with, or make assumptions about an application’s other logging handlers. Applications that combine it with their own rootLoggingHandlerconfiguration own that composition and should use manual OpenTelemetry setup when they need custom providers, filters, propagation, or exporters. Point the docstring topython/samples/02-agents/observability/advanced_manual_setup_console_output.pyas the manual setup example.droideronline commentedon Nov 2, 2026
Thanks for the direction. I've reworked #9897 to be docstring only: no runtime change, a note that
configure_otel_providers()does not coordinate with the application's other logging handlers, and a pointer toadvanced_manual_setup_console_output.pyfor manual setup.