Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Use this article to understand built-in instrumentation, autoinstrumentation, baggage, middleware, and manual scopes in Microsoft OpenTelemetry Distro.
Built-in instrumentation
The Microsoft OpenTelemetry Distro combines standard OpenTelemetry pipelines with Microsoft-curated instrumentation. The Distro can collect application telemetry, infrastructure telemetry, and agent or generative AI telemetry depending on language and configuration.
| Category | What it covers |
|---|---|
| Signal pipelines | Traces, metrics, and logs. |
| Resource detection | Service, host, cloud, and Azure runtime context where supported. |
| Infrastructure instrumentation | HTTP, ASP.NET Core, Azure SDK, database clients, and logging frameworks where supported. |
| Generative AI instrumentation | OpenAI, Azure OpenAI, Semantic Kernel, LangChain, OpenAI Agents SDK, and Agent Framework where supported. |
| Manual agent scopes | Agent invocation, tool execution, inference, and output telemetry where supported. |
| Exporters and processors | Azure Monitor, Microsoft Agent 365, OTLP, console output, span processors, log processors, and metric readers. |
Instrumentation coverage
| Language | Common application instrumentation | Common agent and generative AI instrumentation |
|---|---|---|
| Python | OpenTelemetry resources, processors, readers, logging, metrics, and traces. | Semantic Kernel, OpenAI Agents SDK, Agent Framework, LangChain, Microsoft Agent 365 baggage, and Microsoft Agent 365 scopes. |
| Node.js | HTTP, Azure SDK, Azure Functions, MongoDB, MySQL, PostgreSQL, Redis, Bunyan, and Winston. | OpenAI Agents SDK, LangChain, Microsoft Agent 365 baggage, and Microsoft Agent 365 scopes. |
| .NET | ASP.NET Core, HttpClient, SQL Client, Azure SDK, resource detection, metrics, and logs. | Semantic Kernel, OpenAI and Azure OpenAI, Agent Framework, Microsoft Agent 365 baggage, and Microsoft Agent 365 scopes. |
Automatic instrumentation listens to telemetry signals emitted by supported libraries and frameworks. Manual instrumentation is used when an application needs to describe agent-specific operations, such as invocation, tool execution, inference, or asynchronous output.
Add custom OpenTelemetry sources, meters, processors, or readers when your application emits telemetry that isn't covered by the built-in instrumentations.
Autoinstrumentation
Auto-instrumentation listens to telemetry emitted by supported frameworks and forwards it through the Distro's OpenTelemetry pipeline. For agent scenarios, set baggage such as tenant ID and agent ID before the instrumented framework creates spans.
| Framework | Python | Node.js | .NET |
|---|---|---|---|
| Semantic Kernel | Supported | Not supported | Supported |
| OpenAI and OpenAI Agents SDK | Supported | Supported | Supported |
| Agent Framework | Supported | Not supported | Supported |
| LangChain | Supported | Supported | Not listed |
Semantic Kernel
from microsoft.opentelemetry import use_microsoft_opentelemetry
def token_resolver(agent_id, tenant_id):
return "your-token"
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
instrumentation_options={
"semantic_kernel": {"enabled": True},
},
)
OpenAI
from microsoft.opentelemetry import use_microsoft_opentelemetry
def token_resolver(agent_id, tenant_id):
return "your-token"
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
instrumentation_options={
"openai_agents": {"enabled": True},
},
)
Agent Framework
from microsoft.opentelemetry import use_microsoft_opentelemetry
def token_resolver(agent_id, tenant_id):
return "your-token"
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
instrumentation_options={
"agent_framework": {"enabled": True},
},
)
LangChain
from microsoft.opentelemetry import use_microsoft_opentelemetry
def token_resolver(agent_id, tenant_id):
return "your-token"
use_microsoft_opentelemetry(
enable_a365=True,
a365_token_resolver=token_resolver,
instrumentation_options={
"langchain": {"enabled": True},
},
)
Baggage
Baggage carries contextual attributes through the active OpenTelemetry context so spans created during a request can share identifiers such as tenant ID, agent ID, and conversation ID. Use baggage before starting auto-instrumented framework operations or manual scopes that need that context.
from microsoft.opentelemetry.a365.core import BaggageBuilder
baggage_scope = (
BaggageBuilder()
.tenant_id("tenant-123")
.agent_id("agent-456")
.conversation_id("conv-789")
.build()
)
with baggage_scope:
# Spans created in this context can receive these baggage values.
pass
Baggage values should be set from the authoritative request context for the product surface. Avoid storing secrets or credentials in baggage.
Baggage middleware
Baggage middleware can populate context for incoming requests so application code doesn't need to build baggage manually for every activity. Use hosting middleware when your product surface provides the required tenant, agent, caller, channel, and conversation context.
Register middleware directly on the adapter.
from microsoft.opentelemetry.a365.hosting.middleware import BaggageMiddleware
adapter.use(BaggageMiddleware())
Alternatively, use the hosting manager when you need to configure hosting features together.
from microsoft.opentelemetry.a365.hosting.middleware import (
ObservabilityHostingManager,
ObservabilityHostingOptions,
)
manager = ObservabilityHostingManager()
manager.configure(adapter, ObservabilityHostingOptions(enable_baggage=True))
Middleware should avoid overwriting baggage that was already established by an originating request.
Manual instrumentation
Use manual instrumentation when automatic instrumentation doesn't describe the agent operation with enough detail. Manual scopes let an application describe common agent activities in a consistent way across languages.
| Scope | Use for |
|---|---|
InvokeAgentScope |
The start and completion of an agent invocation. |
ExecuteToolScope |
A tool call made by an agent. |
InferenceScope |
An AI model inference operation. |
OutputScope |
Output that must be recorded after the originating scope has already completed. |
Reuse the same request and agent identity values across scopes in a request so related telemetry can be correlated.
Agent invocation
from microsoft.opentelemetry.a365.core import (
AgentDetails,
Channel,
InvokeAgentScope,
InvokeAgentScopeDetails,
Request,
ServiceEndpoint,
)
agent_details = AgentDetails(
agent_id="agent-456",
agent_name="Email Assistant",
agent_description="An AI agent powered by Azure OpenAI",
agentic_user_id="auid-123",
agentic_user_email="agent@contoso.com",
agent_blueprint_id="blueprint-789",
tenant_id="tenant-123",
)
request = Request(
content="Please help me organize my emails",
session_id="session-42",
conversation_id="conv-xyz",
channel=Channel(name="msteams"),
)
scope_details = InvokeAgentScopeDetails(
endpoint=ServiceEndpoint(hostname="myagent.contoso.com", port=443),
)
with InvokeAgentScope.start(
request=request,
scope_details=scope_details,
agent_details=agent_details,
) as scope:
scope.record_input_messages(["Please help me organize my emails"])
# Run the agent invocation.
invoke_scope.record_output_messages(["I found 15 urgent emails."])
Tool execution
from microsoft.opentelemetry.a365.core import (
ExecuteToolScope,
ServiceEndpoint,
ToolCallDetails,
ToolType,
)
tool_details = ToolCallDetails(
tool_name="email-search",
arguments={"query": "from:manager@contoso.com"},
tool_call_id="tool-call-456",
description="Search emails by criteria",
tool_type=ToolType.FUNCTION.value,
endpoint=ServiceEndpoint(
hostname="tools.contoso.com",
port=8080,
protocol="https",
),
)
with ExecuteToolScope.start(
request=request,
details=tool_details,
agent_details=agent_details,
) as scope:
result = search_emails(tool_details.arguments)
scope.record_response(result)
Inference
from microsoft.opentelemetry.a365.core import (
InferenceCallDetails,
InferenceOperationType,
InferenceScope,
)
inference_details = InferenceCallDetails(
operationName=InferenceOperationType.CHAT,
model="gpt-4o-mini",
providerName="azure-openai",
)
with InferenceScope.start(
request=request,
details=inference_details,
agent_details=agent_details,
) as scope:
scope.record_input_messages(["Summarize the following emails for me."])
response = call_llm()
scope.record_output_messages([response.text])
scope.record_input_tokens(response.usage.input_tokens)
scope.record_output_tokens(response.usage.output_tokens)
scope.record_finish_reasons(["stop"])
Output
from microsoft.opentelemetry.a365.core import OutputScope, Response, SpanDetails
# Capture this before exiting the originating InvokeAgentScope context.
parent_context = invoke_scope.get_span_context()
response = Response(
messages=["Here is your organized inbox."],
)
with OutputScope.start(
request=request,
response=response,
agent_details=agent_details,
user_details=None,
span_details=SpanDetails(parent_context=parent_context),
) as scope:
pass
Product documentation should define any product-specific validation requirements for these scopes.