# How to Set Up OpenTelemetry Observability and Tracing for the Microsoft Agent Framework

> Learn to set up OpenTelemetry observability and tracing for the Microsoft Agent Framework. Enhance your application's visibility with distributed tracing, logging, and metrics.

- Repository: [Microsoft/agent-framework](https://github.com/microsoft/agent-framework)
- Tags: how-to-guide
- Published: 2026-04-05

---

**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`](https://github.com/microsoft/agent-framework/blob/main/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`](https://github.com/microsoft/agent-framework/blob/main/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 collection
- `ENABLE_SENSITIVE_DATA` – Allows logging of prompts and responses (disabled by default for privacy)
- `ENABLE_CONSOLE_EXPORTERS` – Dumps spans and logs to stdout for local debugging
- `VS_CODE_EXTENSION_PORT` – Enables integration with the VS Code OpenTelemetry extension
- `OTEL_SERVICE_NAME` and `OTEL_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:

1. Reads standard OTEL environment variables
2. Initializes exporters (OTLP, Azure Monitor, console, or custom)
3. Builds the global `TracerProvider`, `MeterProvider`, and `LogRecordProcessor`
4. 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:

```python

# 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:

```python

# 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`](https://github.com/microsoft/agent-framework/blob/main/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:

```python

# 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:

```bash

# 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`](https://github.com/microsoft/agent-framework/blob/main/advanced_zero_code.py).

## Step-by-Step Implementation Workflow

Regardless of which configuration pattern you choose, follow this sequence to ensure proper initialization:

1. **Install dependencies** – Include `opentelemetry-api`, `opentelemetry-sdk`, and at least one exporter (OTLP, Azure Monitor, or console) in your requirements.
2. **Configure environment** – Set `OTEL_SERVICE_NAME` and either `OTEL_EXPORTER_OTLP_ENDPOINT` or Azure Monitor connection strings.
3. **Bootstrap observability** – Call `configure_otel_providers()` once at application startup, before creating any Agent instances.
4. **Activate instrumentation** – This happens automatically via `configure_otel_providers()`, or manually via `enable_instrumentation()` if you configured OpenTelemetry separately.
5. **Execute agents** – The framework automatically emits spans for Chat, Embedding, and MCP calls. For custom spans, call `get_tracer()` and use the standard OpenTelemetry `start_as_current_span()` API.

## Summary

- The Agent Framework’s observability layer is defined in [`python/packages/core/agent_framework/observability.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/core/agent_framework/observability.py) and provides zero-overhead telemetry when disabled.
- **`configure_otel_providers()`** handles initialization of exporters, providers, and processors in a single call (lines 979–1020).
- **`ObservabilitySettings`** manages configuration through `ENABLE_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`](https://github.com/microsoft/agent-framework/blob/main/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.