How to Set Up OpenTelemetry Observability and Tracing for the Microsoft Agent Framework
The Microsoft Agent Framework provides a thin wrapper around OpenTelemetry that enables distributed tracing, logging, and metrics through environment variables or programmatic configuration using configure_otel_providers().
The Microsoft Agent Framework ships with built-in observability capabilities that make distributed tracing trivial for agent-based applications. By leveraging the agent_framework.observability module, developers can instrument their agents to emit OpenTelemetry data without boilerplate code. This implementation resides primarily in python/packages/core/agent_framework/observability.py and supports OTLP, Azure Monitor, and console exporters out of the box.
Architecture of the Observability Layer
The framework’s telemetry system is designed as a low-overhead, opt-in wrapper around standard OpenTelemetry SDKs. When ENABLE_INSTRUMENTATION is disabled, the framework skips tracing code paths entirely, ensuring zero performance impact in production builds.
Global Settings Management
The ObservabilitySettings class (lines 632–682 in observability.py) parses environment variables and .env files to store global flags that drive instrumentation. Key variables include:
ENABLE_INSTRUMENTATION– Master switch to activate telemetry collectionENABLE_SENSITIVE_DATA– Allows logging of prompts and responses (disabled by default for privacy)ENABLE_CONSOLE_EXPORTERS– Dumps spans and logs to stdout for local debuggingVS_CODE_EXTENSION_PORT– Enables integration with the VS Code OpenTelemetry extensionOTEL_SERVICE_NAMEandOTEL_EXPORTER_OTLP_ENDPOINT– Standard OpenTelemetry variables
The Bootstrap Function
configure_otel_providers() (lines 979–1020) serves as the one-stop-shop initialization routine. It performs four distinct operations:
- Reads standard OTEL environment variables
- Initializes exporters (OTLP, Azure Monitor, console, or custom)
- Builds the global
TracerProvider,MeterProvider, andLogRecordProcessor - Invokes
enable_instrumentation()to activate the framework’s telemetry layers
Call this function exactly once at application startup, before constructing any Agent or client objects.
Runtime Control
enable_instrumentation() (lines 953–975) toggles the global OBSERVABILITY_SETTINGS without creating exporters. This is useful when you have already configured OpenTelemetry via environment variables or third-party exporters and only need to activate the framework’s internal telemetry hooks.
Distributed Tracing for MCP
When an OpenTelemetry span is active, the framework automatically injects W3C traceparent and tracestate headers into the params._meta field of every MCP (Model Context Protocol) call. This enables end-to-end distributed tracing across agent boundaries and MCP servers without manual header management.
Four Configuration Patterns
The repository’s samples under python/samples/02-agents/observability/ demonstrate four distinct setup approaches.
Environment-Variable Configuration (Recommended)
For most deployments, set environment variables and call configure_otel_providers() with no arguments:
# main.py
from agent_framework.observability import configure_otel_providers
# Set in .env or CI environment:
# ENABLE_INSTRUMENTATION=true
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
# OTEL_SERVICE_NAME=my_agent_app
# ENABLE_SENSITIVE_DATA=true # Optional
# ENABLE_CONSOLE_EXPORTERS=true # Optional
configure_otel_providers()
This pattern automatically reads the standard OTEL variables and initializes the appropriate exporters.
Programmatic Exporter Configuration
For scenarios requiring explicit control over endpoints, compression, or authentication, pass instantiated exporter objects:
# custom_exporters.py
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from agent_framework.observability import configure_otel_providers
exporters = [
OTLPSpanExporter(endpoint="http://otel-collector:4317", compression="gzip"),
OTLPLogExporter(endpoint="http://otel-collector:4317"),
OTLPMetricExporter(endpoint="http://otel-collector:4317"),
]
configure_otel_providers(
exporters=exporters,
enable_sensitive_data=True
)
See the sample file configure_otel_providers_with_parameters.py for the complete working implementation.
Azure Monitor Integration
For Microsoft-centric observability stacks, integrate with Azure Monitor while still using the framework’s resource attributes:
# azure_monitor.py
from azure.monitor.opentelemetry import configure_azure_monitor
from agent_framework.observability import create_resource, enable_instrumentation
# Azure Monitor handles its own provider setup
configure_azure_monitor(
connection_string="InstrumentationKey=YOUR_KEY",
resource=create_resource(), # Inherits OTEL_SERVICE_NAME and version
enable_live_metrics=True,
)
# Activate framework telemetry layers if not using env vars
enable_instrumentation(enable_sensitive_data=False)
The create_resource() helper pulls service metadata from the same environment variables used by ObservabilitySettings, ensuring consistent attributes across custom and framework-generated spans.
Zero-Code Auto-Instrumentation
For DevOps pipelines or legacy codebases where modifying source is undesirable, use the OpenTelemetry CLI:
# Install the CLI tool
pip install opentelemetry-instrumentation
# Run with automatic instrumentation
opentelemetry-instrument python -m my_agent_app
The CLI initializes the global TracerProvider before your application starts. The Agent Framework’s get_tracer() function automatically detects this global provider and begins emitting spans. This pattern requires no code changes and is demonstrated in advanced_zero_code.py.
Step-by-Step Implementation Workflow
Regardless of which configuration pattern you choose, follow this sequence to ensure proper initialization:
- Install dependencies – Include
opentelemetry-api,opentelemetry-sdk, and at least one exporter (OTLP, Azure Monitor, or console) in your requirements. - Configure environment – Set
OTEL_SERVICE_NAMEand eitherOTEL_EXPORTER_OTLP_ENDPOINTor Azure Monitor connection strings. - Bootstrap observability – Call
configure_otel_providers()once at application startup, before creating any Agent instances. - Activate instrumentation – This happens automatically via
configure_otel_providers(), or manually viaenable_instrumentation()if you configured OpenTelemetry separately. - Execute agents – The framework automatically emits spans for Chat, Embedding, and MCP calls. For custom spans, call
get_tracer()and use the standard OpenTelemetrystart_as_current_span()API.
Summary
- The Agent Framework’s observability layer is defined in
python/packages/core/agent_framework/observability.pyand provides zero-overhead telemetry when disabled. configure_otel_providers()handles initialization of exporters, providers, and processors in a single call (lines 979–1020).ObservabilitySettingsmanages configuration throughENABLE_INSTRUMENTATION,ENABLE_SENSITIVE_DATA, and standard OTEL environment variables.- Distributed tracing across MCP servers works automatically via W3C trace context injection into
params._meta. - Four configuration patterns are supported: environment variables, programmatic exporters, Azure Monitor, and zero-code CLI instrumentation.
Frequently Asked Questions
How do I completely disable telemetry in production?
Set ENABLE_INSTRUMENTATION=false or simply do not call configure_otel_providers(). According to the source code in observability.py, when this flag is false, the framework skips all tracing code paths entirely, resulting in zero runtime overhead.
Can I export traces to both OTLP and the console simultaneously?
Yes. Pass multiple exporters to configure_otel_providers() or set ENABLE_CONSOLE_EXPORTERS=true alongside your OTLP endpoint. The function accepts a list of exporter objects and will configure a BatchSpanProcessor for each, writing to both destinations concurrently.
Does the framework log sensitive data like prompts and responses?
Only if explicitly enabled. The ENABLE_SENSITIVE_DATA environment variable (or the enable_sensitive_data=True parameter) controls whether input/output content is attached to spans. By default, this is disabled to prevent PII leakage in production trace data.
How does trace propagation work with external MCP servers?
When a span is active, the framework automatically adds traceparent and tracestate headers to the params._meta dictionary of every MCP request. External servers that support W3C trace context can extract these headers to continue the trace, enabling end-to-end visibility across agent boundaries without manual header manipulation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →