Deprecated Agent 365 Observability SDK

Important

This article documents the deprecated Agent 365 Observability SDK. Existing integrations continue to work, but don't use this SDK for new integrations. For new development, use the Microsoft OpenTelemetry Distro. Before you update an existing integration, review the migration guide for your language:

For the underlying data model, identity and authentication, scopes and consent, and limits that apply to every integration path, see Agent 365 observability concepts.

Note

Observability is one of the incremental capability tiers in Get started with Agent 365 development and applies to all agent types.

To participate in the Agent 365 ecosystem, add Agent 365 Observability capabilities to your agent. Agent 365 Observability builds on OpenTelemetry (OTel) and provides a unified framework for capturing telemetry consistently and securely across all agent platforms. By implementing this required component, you enable IT admins to monitor your agent's activity in Microsoft admin center and allow security teams to use Defender and Purview for compliance and threat detection.

Key benefits

  • End-to-end visibility: Capture comprehensive telemetry for every agent invocation, including sessions, tool calls, and exceptions, giving you full traceability across platforms.
  • Security and compliance enablement: Feed unified audit logs into Defender and Purview, enabling advanced security scenarios and compliance reporting for your agent.
  • Cross-platform flexibility: Build on OTel standards and support diverse runtimes and platforms like Copilot Studio, Foundry, and future agent frameworks.
  • Operational efficiency for admins: Provide centralized observability in Microsoft 365 admin center, reducing troubleshooting time and improving governance with role-based access controls for IT teams managing your agent.

Supported agents

The following agent types support Agent 365 observability:

Installation

Use these commands to install the observability modules for the languages supported by Agent 365.

Install the core observability and runtime packages. All agents that use Agent 365 Observability need these packages.

pip install microsoft-agents-a365-observability-core
pip install microsoft-agents-a365-runtime

If your agent uses the Microsoft Agents Hosting package, install the hosting integration package. It provides middleware that automatically populates baggage and scopes from the TurnContext, and includes token caching for the observability exporter.

pip install microsoft-agents-a365-observability-hosting

If your agent uses one of the supported AI frameworks, install the corresponding auto-instrumentation extension to automatically capture telemetry without manual instrumentation code. For configuration details, see Auto-instrumentation.

# For Semantic Kernel
pip install microsoft-agents-a365-observability-extensions-semantic-kernel

# For OpenAI Agents SDK
pip install microsoft-agents-a365-observability-extensions-openai

# For Microsoft Agent Framework
pip install microsoft-agents-a365-observability-extensions-agent-framework

# For LangChain
pip install microsoft-agents-a365-observability-extensions-langchain

Configuration

Use the following settings to enable and customize Agent 365 Observability for your agent.

Set the ENABLE_A365_OBSERVABILITY_EXPORTER environment variable to true for observability. In Agent 365 SDK 2.0 and later, the exporter always uses the service-to-service (S2S) route and authenticates with the configured app-only token_resolver. If you enable the exporter without a resolver, Python keeps the console exporter fallback and doesn't send telemetry to Agent 365.

from microsoft_agents_a365.observability.core import configure

def token_resolver(agent_id: str, tenant_id: str) -> str | None:
    # Return a validated app-only observability token for this agent and tenant.
    return "<app-only-observability-token>"

configure(
    service_name="my-agent-service",
    service_namespace="my.namespace",
    token_resolver=token_resolver,
)

The token resolver is excluded from logging to the console.

You can customize the exporter behavior by passing an Agent365ExporterOptions instance to exporter_options. When exporter_options is provided, it takes precedence over the token_resolver and cluster_category parameters.

from microsoft_agents_a365.observability.core import configure, Agent365ExporterOptions

configure(
    service_name="my-agent-service",
    service_namespace="my.namespace",
    exporter_options=Agent365ExporterOptions(
        cluster_category="prod",
        token_resolver=token_resolver,
    ),
    suppress_invoke_agent_input=True,
)

The following table describes the optional parameters for configure().

Parameter Description Default
logger_name Name of the Python logger used for debugging and console log output. microsoft_agents_a365.observability.core
exporter_options An Agent365ExporterOptions instance that configures the token resolver and cluster category together. None
suppress_invoke_agent_input When True, suppresses input messages on InvokeAgent spans. False

The following table describes the optional properties for Agent365ExporterOptions.

Property Description Default
use_s2s_endpoint Deprecated and ignored. Agent 365 SDK 2.0 and later always uses the S2S route, even when this value is False. False (ignored)
max_queue_size Maximum queue size for the batch processor. 2048
scheduled_delay_ms Delay in milliseconds between export batches. 5000
exporter_timeout_ms Timeout in milliseconds for the export operation. 30000
max_export_batch_size Maximum batch size for export operations. 512

Baggage attributes

Use BaggageBuilder to set contextual information that flows through all spans in a request. The SDK implements a SpanProcessor that copies all nonempty baggage entries to newly started spans without overwriting existing attributes.

from microsoft_agents_a365.observability.core import BaggageBuilder

with (
    BaggageBuilder()
    .tenant_id("tenant-123")
    .agent_id("agent-456")
    .conversation_id("conv-789")
    .build()
):
    # Any spans started in this context will receive these as attributes
    pass

To auto-populate the BaggageBuilder from the TurnContext, use the populate helper in the microsoft-agents-a365-observability-hosting package. This helper automatically extracts caller, agent, tenant, channel, and conversation details from the activity.

from microsoft_agents.hosting.core.turn_context import TurnContext
from microsoft_agents_a365.observability.core import BaggageBuilder
from microsoft_agents_a365.observability.hosting.scope_helpers.populate_baggage import populate

builder = BaggageBuilder()
populate(builder, turn_context)

with builder.build():
    # Baggage is auto-populated from the TurnContext activity
    pass

Baggage middleware

If your agent uses the hosting integration package, register baggage middleware to automatically populate baggage for every incoming request. This step removes the need to call BaggageBuilder manually in each activity handler.

Register BaggageMiddleware on the adapter middleware set. It automatically extracts caller, agent, tenant, channel, and conversation details from every incoming TurnContext and wraps the request in a baggage scope.

from microsoft_agents_a365.observability.hosting import BaggageMiddleware

adapter.use(BaggageMiddleware())

Alternatively, use ObservabilityHostingManager to configure baggage middleware along with other hosting features:

from microsoft_agents_a365.observability.hosting import ObservabilityHostingManager, ObservabilityHostingOptions

options = ObservabilityHostingOptions(enable_baggage=True)
ObservabilityHostingManager.configure(adapter.middleware_set, options)

The middleware skips baggage setup for async replies (ContinueConversation events) to avoid overwriting baggage that the originating request already set.

Token resolver

When you use the Agent 365 exporter in Agent 365 SDK 2.0 and later, provide a token resolver that returns the final app-only observability token for the exporting agent instance. The exporter always sends telemetry to the S2S route and doesn't fall back to the delegated route. An Agent 365-registered agent instance doesn't need the Agent365.Observability.OtelWrite permission or admin consent to export on this route.

Use the two-step Federated Managed Identity (FMI) exchange to get the app-only token:

  1. Get a blueprint client_credentials token for api://AzureADTokenExchange/.default with fmi_path set to the agent instance client ID.
  2. Get an agent-instance client_credentials token for api://9b975845-388f-4429-889e-eab1ef63949c/.default. Pass the step 1 token as client_assertion, and set client_assertion_type to urn:ietf:params:oauth:client-assertion-type:jwt-bearer.

For the full authentication setup, see Agent 365-enabled using S2S. For complete token service implementations, see the Agent 365 samples for Node.js, Python, and .NET.

Your resolver must:

  • Return an app-only token for the exporting agent instance and tenant. Never return the intermediate blueprint assertion, a blueprint token, a user token, or an OBO token.
  • Validate the token before it returns it. Accept idtyp=app. If idtyp is absent, accept only a token that has a non-empty roles claim or a non-empty oid claim equal to sub. Reject tokens that have an scp claim or another idtyp value, expired tokens, and tokens whose aud isn't 9b975845-388f-4429-889e-eab1ef63949c or api://9b975845-388f-4429-889e-eab1ef63949c.
  • Cache the token and refresh it before it expires. The exporter calls the resolver once for each tenant and agent identity in every export batch.

Note

Migrate from SDK 1.x: SDK 2.0 removes the delegated token exchange for observability export. Replace the delegated token code in your agent with an app-only resolver, as shown in the following examples. Agents that stay on SDK 1.x and export on the delegated route still need the delegated Agent365.Observability.OtelWrite permission and admin consent. The a365 setup all command doesn't configure that permission for blueprint agents. To grant it, see Grant the permission.

Call AgenticTokenCache.refresh_observability_token(agent_id, tenant_id, acquire_app_only_obs_token) from your token_resolver. The cache passes the observability /.default scope to your acquisition callback and returns the cached token.

from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.hosting.token_cache_helpers import AgenticTokenCache

cache = AgenticTokenCache()

async def acquire_app_only_obs_token(
    agent_id: str,
    tenant_id: str,
    scopes: list[str],
) -> str:
    # Run the FMI exchange described earlier, validate the token, and return it.
    return "<app-only-observability-token>"

async def token_resolver(agent_id: str, tenant_id: str) -> str:
    return await cache.refresh_observability_token(
        agent_id, tenant_id, acquire_app_only_obs_token
    )

configure(
    service_name="my-agent-service",
    service_namespace="my.namespace",
    token_resolver=token_resolver,
)

Python also supports a synchronous resolver that returns a token from a thread-safe cache. The Agent 365 samples use that pattern, which avoids the constraints of running an async resolver on the exporter thread.

To migrate from SDK 1.x, remove the AGENT_APP.auth.exchange_token call that requested the observability scope and the AgenticTokenCache.register_observability call that passed an AgenticTokenStruct. In SDK 2.0, register_observability is a deprecated no-op.

Auto-instrumentation

Auto-instrumentation automatically listens to agentic frameworks (SDKs) existing telemetry signals for traces and forwards them to Agent 365 observability service. This feature eliminates the need for developers to write monitoring code manually, simplifies setup, and ensures consistent performance tracking.

Important

Auto-instrumentation populates standard OTel attributes only. You must add Microsoft-specific attributes through BaggageBuilder. To see which attributes are missing, validate your console span output against the store logs for the diff set.

Multiple SDKs and platforms support auto-instrumentation:

Platform Supported SDKs / Frameworks
.NET Semantic Kernel, OpenAI, Agent Framework
Python Semantic Kernel, OpenAI, Agent Framework, LangChain
Node.js OpenAI, LangChain

Note

Support for auto-instrumentation varies by platform and SDK implementation.

Semantic Kernel

Auto instrumentation requires the use of a baggage builder. Set the agent ID and tenant ID by using BaggageBuilder.

Install the package.

pip install microsoft-agents-a365-observability-extensions-semantic-kernel

Configure observability.

from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.semantickernel.trace_instrumentor import SemanticKernelInstrumentor

# Configure observability
configure(
    service_name="my-semantic-kernel-agent",
    service_namespace="ai.agents"
)

# Enable auto-instrumentation
instrumentor = SemanticKernelInstrumentor()
instrumentor.instrument()

# Your Semantic Kernel code is now automatically traced

OpenAI

Auto instrumentation requires the use of a baggage builder. Set the agent ID and tenant ID by using BaggageBuilder.

Install the package.

pip install microsoft-agents-a365-observability-extensions-openai

Configure observability.

from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.openai import OpenAIAgentsTraceInstrumentor

# Configure observability
configure(
    service_name="my-openai-agent",
    service_namespace="ai.agents"
)

# Enable auto-instrumentation
instrumentor = OpenAIAgentsTraceInstrumentor()
instrumentor.instrument()

# Your OpenAI Agents code is now automatically traced

Agent Framework

Auto instrumentation requires the use of a baggage builder. Set the agent ID and tenant ID by using BaggageBuilder.

Install the package.

pip install microsoft-agents-a365-observability-extensions-agent-framework

Configure observability.

from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.agentframework import (
    AgentFrameworkInstrumentor,
)

# Configure observability
configure(
    service_name="AgentFrameworkTracingWithAzureOpenAI",
    service_namespace="AgentFrameworkTesting",
)

# Enable auto-instrumentation
AgentFrameworkInstrumentor().instrument()

LangChain Framework

Note

Auto-instrumentation for the LangChain framework also supports LangGraph and Deep Agents. The same extension automatically captures telemetry for agents built with any of these frameworks.

Auto-instrumentation requires the use of baggage builder. Set agent ID and tenant ID by using BaggageBuilder.

Install the package.

pip install microsoft-agents-a365-observability-extensions-langchain

Configure observability.

from microsoft_agents_a365.observability.core.config import configure
from microsoft_agents_a365.observability.extensions.langchain import CustomLangChainInstrumentor

# Configure observability
configure(
    service_name="my-langchain-agent",
    service_namespace="ai.agents"
)

# Enable auto-instrumentation
CustomLangChainInstrumentor()

# Your LangChain code is now automatically traced

Manual instrumentation

Use the Agent 365 observability SDK to understand the internal working of the agent. The SDK provides scopes that you can start: InvokeAgentScope, ExecuteToolScope, InferenceScope, and OutputScope.

Agent invocation

Use this scope at the start of your agent process. By using the invoke agent scope, you can capture properties like the current agent being invoked, agent user data, and more.

from microsoft_agents_a365.observability.core import (
    InvokeAgentScope,
    InvokeAgentScopeDetails,
    AgentDetails,
    CallerDetails,
    UserDetails,
    Channel,
    Request,
    ServiceEndpoint,
)

agent_details = AgentDetails(
    agent_id="agent-456",
    agent_name="My Agent",
    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",
)

scope_details = InvokeAgentScopeDetails(
    endpoint=ServiceEndpoint(hostname="myagent.contoso.com", port=443),
)

request = Request(
    content="User asks a question",
    session_id="session-42",
    conversation_id="conv-xyz",
    channel=Channel(name="msteams"),
)

caller_details = CallerDetails(
    user_details=UserDetails(
        user_id="user-123",
        user_email="jane.doe@contoso.com",
        user_name="Jane Doe",
    ),
)

with InvokeAgentScope.start(request, scope_details, agent_details, caller_details):
    # Perform agent invocation logic
    response = call_agent(...)

Tool execution

The following examples show how to add observability tracking to your agent's tool execution. This tracking captures telemetry for monitoring and auditing purposes.

from microsoft_agents_a365.observability.core import (
    ExecuteToolScope,
    ToolCallDetails,
    Request,
    ServiceEndpoint,
)

# Use the same agent_details and request instances from the InvokeAgentScope example above

tool_details = ToolCallDetails(
    tool_name="summarize",
    tool_type="function",
    tool_call_id="tc-001",
    arguments="{'text': '...'}",
    description="Summarize provided text",
    endpoint=ServiceEndpoint(hostname="tools.contoso.com", port=8080),
)

with ExecuteToolScope.start(request, tool_details, agent_details) as scope:
    result = run_tool(tool_details)
    scope.record_response(result)

Inference

The following examples show how to instrument AI model inference calls with observability tracking to capture token usage, model details, and response metadata.

from microsoft_agents_a365.observability.core import (
    InferenceScope,
    InferenceCallDetails,
    InferenceOperationType,
)

# Use the same agent_details and request instances from the InvokeAgentScope example above

inference_details = InferenceCallDetails(
    operationName=InferenceOperationType.CHAT,
    model="gpt-4o-mini",
    providerName="azure-openai",
    inputTokens=123,
    outputTokens=456,
    finishReasons=["stop"],
)

with InferenceScope.start(request, inference_details, agent_details) as scope:
    completion = call_llm(...)
    scope.record_output_messages([completion.text])
    scope.record_input_tokens(completion.usage.input_tokens)
    scope.record_output_tokens(completion.usage.output_tokens)

Output

Use this scope for asynchronous scenarios where InvokeAgentScope, ExecuteToolScope, or InferenceScope can't capture output data synchronously. Start OutputScope as a child span to record the final output messages after the parent scope finishes.

from microsoft_agents_a365.observability.core import (
    OutputScope,
    Response,
    SpanDetails,
)

# Use the same agent_details and request instances from the InvokeAgentScope example above

# Get the parent context from the originating scope
parent_context = invoke_scope.get_context()

response = Response(messages=["Here is your organized inbox with 15 urgent emails."])

with OutputScope.start(
    request,
    response,
    agent_details,
    span_details=SpanDetails(parent_context=parent_context),
):
    # Output messages are recorded automatically from the response
    pass

Validate locally

To verify that you successfully integrated with the observability SDK, examine the console logs generated by your agent and logs from the observability SDK.

Set the environment variable ENABLE_A365_OBSERVABILITY_EXPORTER to false. This setting exports spans (traces) to the console.

To investigate export failures, enable verbose logging by setting ENABLE_A365_OBSERVABILITY_EXPORTER to true and configuring debug logging in your application startup:

import logging

logging.basicConfig(level=logging.DEBUG)
logging.getLogger("microsoft_agents_a365.observability.core").setLevel(logging.DEBUG)

# Or target only the exporter:
logging.getLogger(
    "microsoft_agents_a365.observability.core.exporters.agent365_exporter"
).setLevel(logging.DEBUG)

Key log messages:

DEBUG  Token resolved for agent {agentId} tenant {tenantId}
DEBUG  Exporting {n} spans to {url}
DEBUG  HTTP 200 - correlation ID: abc-123
ERROR  Token resolution failed: {error}
ERROR  HTTP 401 exporting spans - correlation ID: abc-123
INFO   No spans with tenant/agent identity found; nothing exported.

Viewing exported logs

To view agent telemetry in Microsoft Purview or Microsoft Defender, ensure you meet the following requirements:

Validate for store publishing

Important

For successful store validation, your agent must implement the InvokeAgentScope, InferenceScope, and ExecuteToolScope scopes. These three scopes are required for publishing.

Before publishing, use console logs to validate your observability integration for the agent by implementing the required invoke agent, execute tool, inference, and output scopes. Then compare your agent's logs against the following attribute lists to verify all required attributes are present. Capture attributes on each scope or through the baggage builder, and include optional attributes at your discretion.

For more information about store publishing requirements, see store validation guidelines.

InvokeAgentScope attributes

The following list summarizes the required and optional telemetry attributes recorded when you start an InvokeAgentScope.

"attributes": {
        "error.type": "Optional",
        "microsoft.a365.agent.blueprint.id": "Required",
        "gen_ai.agent.description": "Optional",
        "gen_ai.agent.id": "Required",
        "gen_ai.agent.name": "Required",
        "microsoft.a365.agent.platform.id": "Optional",
        "microsoft.agent.user.email": "Required",
        "microsoft.agent.user.id": "Required",
        "gen_ai.agent.version": "Optional",
        "microsoft.a365.caller.agent.blueprint.id": "Optional",
        "microsoft.a365.caller.agent.id": "Optional",
        "microsoft.a365.caller.agent.name": "Optional",
        "microsoft.a365.caller.agent.platform.id": "Optional",
        "microsoft.a365.caller.agent.user.email": "Optional",
        "microsoft.a365.caller.agent.user.id": "Optional",
        "microsoft.a365.caller.agent.version": "Optional",
        "client.address": "Required",
        "user.id": "Required",
        "user.name": "Optional",
        "user.email": "Required",
        "microsoft.channel.link": "Optional",
        "microsoft.channel.name": "Required",
        "gen_ai.conversation.id": "Required",
        "microsoft.conversation.item.link": "Optional",
        "gen_ai.input.messages": "Required",
        "gen_ai.operation.name": "Required",
        "gen_ai.output.messages": "Required",
        "server.address": "Required",
        "server.port": "Required",
        "microsoft.session.id": "Optional",
        "microsoft.session.description": "Optional",
        "microsoft.tenant.id": "Required"
    }

ExecuteToolScope attributes

The following list summarizes the required and optional telemetry attributes recorded when you start an ExecuteToolScope.

"attributes": {
        "error.type": "Optional",
        "microsoft.a365.agent.blueprint.id": "Required",
        "gen_ai.agent.description": "Optional",
        "gen_ai.agent.id": "Required",
        "gen_ai.agent.name": "Required",
        "microsoft.a365.agent.platform.id": "Optional",
        "microsoft.agent.user.email": "Required",
        "microsoft.agent.user.id": "Required",
        "gen_ai.agent.version": "Optional",
        "client.address": "Required",
        "user.id": "Required",
        "user.name": "Optional",
        "user.email": "Required",
        "microsoft.channel.link": "Optional",
        "microsoft.channel.name": "Required",
        "gen_ai.conversation.id": "Required",
        "microsoft.conversation.item.link": "Optional",
        "gen_ai.operation.name": "Required",
        "gen_ai.tool.call.arguments": "Required",
        "gen_ai.tool.call.id": "Required",
        "gen_ai.tool.call.result": "Required",
        "gen_ai.tool.description": "Optional",
        "gen_ai.tool.name": "Required",
        "gen_ai.tool.type": "Required",
        "server.address": "Optional",
        "server.port": "Optional",
        "microsoft.session.id": "Optional",
        "microsoft.session.description": "Optional",
        "microsoft.tenant.id": "Required"
    }

InferenceScope attributes

The following list summarizes the required and optional telemetry attributes recorded when you start an InferenceScope.

"attributes": {
        "error.type": "Optional",
        "microsoft.a365.agent.blueprint.id": "Required",
        "gen_ai.agent.description": "Optional",
        "gen_ai.agent.id": "Required",
        "gen_ai.agent.name": "Required",
        "microsoft.a365.agent.platform.id": "Optional",
        "microsoft.a365.agent.thought.process": "Optional",
        "microsoft.agent.user.email": "Required",
        "microsoft.agent.user.id": "Required",
        "gen_ai.agent.version": "Optional",
        "client.address": "Required",
        "user.id": "Required",
        "user.name": "Optional",
        "user.email": "Required",
        "microsoft.channel.link": "Optional",
        "microsoft.channel.name": "Required",
        "gen_ai.conversation.id": "Required",
        "microsoft.conversation.item.link": "Optional",
        "gen_ai.input.messages": "Required",
        "gen_ai.operation.name": "Required",
        "gen_ai.output.messages": "Required",
        "gen_ai.provider.name": "Required",
        "gen_ai.request.model": "Required",
        "gen_ai.response.finish_reasons": "Optional",
        "gen_ai.usage.input_tokens": "Optional",
        "gen_ai.usage.output_tokens": "Optional",
        "server.address": "Optional",
        "server.port": "Optional",
        "microsoft.session.description": "Optional",
        "microsoft.session.id": "Optional",
        "microsoft.tenant.id": "Required"
    }

OutputScope attributes

The following list summarizes the required and optional telemetry attributes recorded when you start an OutputScope. Use this scope for asynchronous scenarios where the parent scope can't capture output data synchronously.

"attributes": {
        "microsoft.a365.agent.blueprint.id": "Required",
        "gen_ai.agent.description": "Optional",
        "gen_ai.agent.id": "Required",
        "gen_ai.agent.name": "Required",
        "microsoft.a365.agent.platform.id": "Optional",
        "microsoft.agent.user.email": "Required",
        "microsoft.agent.user.id": "Required",
        "gen_ai.agent.version": "Optional",
        "client.address": "Required",
        "user.id": "Required",
        "user.name": "Optional",
        "user.email": "Required",
        "microsoft.channel.link": "Optional",
        "microsoft.channel.name": "Required",
        "gen_ai.conversation.id": "Required",
        "microsoft.conversation.item.link": "Optional",
        "gen_ai.operation.name": "Required",
        "gen_ai.output.messages": "Required",
        "microsoft.session.id": "Optional",
        "microsoft.session.description": "Optional",
        "microsoft.tenant.id": "Required"
    }

Test your agent with observability

After you implement observability in your agent, test it to make sure it captures telemetry correctly. Follow the testing guide to set up your environment. Then, focus primarily on the View observability logs section to validate your observability implementation is working as expected.

Verification:

  • Go to: https://admin.cloud.microsoft/#/agents/all
  • Select your agent > Activity
  • You see sessions and tool calls

Troubleshooting

This section describes common problems when implementing and using observability.

Problem Description
Observability data doesn't appear No telemetry is visible because exporting isn't enabled, config is incorrect, or token resolution fails.
Missing tenant ID or agent ID - spans skipped Spans are dropped before export when identity attributes required for partitioning are missing.
Token resolution failure - export skipped or unauthorized Export fails when the resolver returns no token or encounters an exception.
HTTP 401 Unauthorized Authentication succeeds syntactically but the token is invalid for ingestion because of scope, type, or expiration.
HTTP 403 Forbidden Access is denied because of tenant licensing gaps, a missing Agent 365 registration, or a missing observability permission where one is required.
HTTP 403 Forbidden - Agent ID mismatch The request is rejected when the agent identity in the URL doesn't match the identity represented by the token.
HTTP 429 or 5xx errors - Transient errors Temporary throttling or service-side failures interrupt export and may require retry tuning.
Export timeout Telemetry batches exceed configured timeout windows because of network latency or endpoint responsiveness.
Export succeeds but telemetry doesn't appear in Defender or Purview Ingestion completes, but downstream visibility is delayed or blocked by product prerequisites.

Tip

Agent 365 Troubleshooting Guide contains high-level troubleshooting recommendations, best practices, and links to troubleshooting content for each part of the Agent 365 development lifecycle.

Observability data doesn't appear

Symptoms:

  • Agent is running
  • No telemetry in admin center
  • Can't see agent activity

Root cause:

  • Observability isn't enabled
  • Configuration errors
  • Token resolver problems

Solutions: Try the following steps to resolve the problem:

  • Verify observability exporter is enabled

    You must explicitly enable the Agent 365 exporter. When disabled, the SDK falls back to a console exporter and telemetry isn't sent to the service. For configuration details, see Configuration.

  • Check token resolver configuration

    The exporter requires a valid token resolver that returns an app-only observability token for each export request. If the resolver is missing, returns no token, or throws, export doesn't send a request. Make sure your code implements the token resolver. For details, see Token resolver.

  • Check for errors in logs

    Enable verbose logging and use the az webapp log tail command to search logs for observability-related errors. For details on how to enable logging per platform, see Validate locally.

    # Look for observability-related errors
    az webapp log tail --name <your-app-name> --resource-group <your-resource-group> | Select-String "observability"
    
  • Verify telemetry export

    Confirm telemetry is generated and exported as expected.

    • Add a console exporter and check if telemetry is generated locally. For details on how to use the console exporter and validate output, see Validate locally.

Missing tenant ID or agent ID — spans skipped

Symptoms: The system silently drops spans and never exports them. Some SDKs log a count of skipped spans or a message such as "No spans with tenant/agent identity found." Others drop them without logging.

Resolution:

  • Before export, the SDK partitions spans by tenant and agent identity. The system drops spans that lack either a tenant ID or agent ID and never sends them to the service.
  • Ensure BaggageBuilder is set up with the tenant ID and agent ID before creating spans. These values propagate through the OpenTelemetry context and attach to all spans created within the baggage scope. For the platform-specific API, see Baggage attributes.
  • Confirm the TurnContext activity has a valid recipient with agent identity if you use the baggage middleware or turn context helper from the hosting integration package to populate those IDs.

Token resolution failure — export skipped or unauthorized

Symptoms: The token resolver returns null, returns an empty token, or throws an error. The export fails without sending a request, and the exporter doesn't fall back to the delegated route.

Resolution:

  • Provide a resolver that returns the final app-only observability token for the exporting agent instance and tenant.
  • Make sure the correct tenant ID and agent ID are used for BaggageBuilder, because these values are passed to the token resolver.
  • Check the language-specific startup behavior. Node.js fails configuration when the Agent 365 exporter is enabled without a resolver, .NET fails exporter construction, and Python falls back to the console exporter when no resolver is configured.
  • Verify that your resolver validates the token before returning it. It must reject delegated tokens with an scp claim and tokens issued for the wrong audience.

HTTP 401 Unauthorized

Symptoms: Export fails with HTTP 401. The exporter doesn't retry this error.

Resolution:

  • Verify that the token audience is 9b975845-388f-4429-889e-eab1ef63949c or api://9b975845-388f-4429-889e-eab1ef63949c.
  • Check that the token resolver isn't returning a delegated user token, a token with an scp claim, a token for an incorrect audience, or an expired token.
  • Confirm that the resolver returns the final agent-instance token, not the intermediate blueprint assertion.

HTTP 403 Forbidden

Symptoms: Export fails with HTTP 403. The exporter doesn't retry this error.

Root cause: An HTTP 403 error can have different causes. Check the following resolutions in order.

Resolution:

  • Missing license — Verify that your tenant has one of the following licenses assigned in Microsoft 365 admin center:

    • Test - Microsoft 365 E7
    • Microsoft 365 E7
    • Microsoft Agent 365 Frontier
  • Agent instance isn't registered — The S2S route accepts an app-only token without the Agent365.Observability.OtelWrite role only from an Agent 365-registered agent instance. Otherwise, it returns HTTP 403 insufficient_scope. For blueprint agents, a365 setup all registers the agent instance. To retry a failed registration, run a365 setup all --agent-registration-only. Creating a Microsoft Entra identity alone doesn't register the agent instance.

  • Token isn't app-only — Verify that the token doesn't include an scp claim. The S2S route requires an app-only token.

  • Unregistered identity lacks the app role — Unregistered identities, including the standard app registrations that custom engine agents use, need the Agent365.Observability.OtelWrite app role. To grant it, see Grant the permission.

  • SDK 1.x agent on the delegated route — The delegated route needs the delegated Agent365.Observability.OtelWrite permission and admin consent, which a365 setup all doesn't configure for blueprint agents. Upgrade to SDK 2.0, or grant the permission.

  • Agent ID doesn't match the token — See HTTP 403 Forbidden - Agent ID mismatch.

HTTP 403 Forbidden — Agent ID mismatch

Symptoms: Export fails with HTTP 403 and a server message similar to 403 Forbidden with agent-ID-mismatch failures calling Agent 365 traces endpoints.

Root cause: This error occurs when you use the blueprint client ID instead of the agent instance client ID when setting the agent details. The agent ID in the export URL doesn't match the identity authorized by the token, so the traces endpoint rejects the request.

Resolution:

  • Verify whether the tenant ID is added to the Agent 365 allowed tenant list.
  • Set the agent details with the agent instance client ID (not the blueprint client ID).
  • Verify the export URL that's generated - it's logged if you enable your logger. Confirm the agent ID in the URL matches the agent instance client ID.
  • To enable diagnostic logging per SDK, see Validate locally.

HTTP 429 or 5xx errors - Transient errors

Symptoms: Export fails with a transient HTTP status code such as 429 or 5xx.

Resolution:

  • These errors are usually transient and resolve on their own. The Python and JavaScript SDKs automatically retry on HTTP 408, 429, and 5xx status codes up to three times with exponential backoff. The .NET SDK doesn't retry automatically.
  • If errors persist, check the service health dashboard.
  • Consider reducing export frequency by increasing the scheduled delay between batches or increasing the max export batch size. For configuration options per platform, see the Agent365ExporterOptions table in Configuration.

Export timeout

Symptoms: Export attempts time out.

Resolution:

  • Check network connectivity to the observability endpoint.
  • Timeout defaults vary by platform. The default HTTP request timeout is 30 seconds. Some SDKs also have a separate overall exporter timeout that covers the entire export cycle including retries. For the exact properties and defaults per platform, see the Agent365ExporterOptions table in Configuration.
  • If timeouts occur frequently, increase the relevant timeout value in your exporter options.

Export succeeds but telemetry doesn't appear in Defender or Purview

Symptoms: Logs show a successful export but telemetry isn't visible in Microsoft Defender or Microsoft Purview.

Resolution:

  • Verify that you meet the prerequisites for viewing exported logs. For Purview, auditing must be turned on. For Defender, you must configure advanced hunting. For more information, see Viewing exported logs.
  • Telemetry can take several minutes to populate after a successful export. Wait for the data to appear before investigating further.

To learn more about testing observability, see: