Share via


Agent observability

Important

You need to be part of the Frontier preview program to get early access to Microsoft Agent 365. Frontier connects you directly with Microsoft’s latest AI innovations. Frontier previews are subject to the existing preview terms of your customer agreements. As these features are still in development, their availability and capabilities may change over time.

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.

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. This setting exports logs to the service and requires a token_resolver to be provided. Otherwise, the console exporter is used.

from microsoft_agents_a365.observability.core import configure

def token_resolver(agent_id: str, tenant_id: str) -> str | None:
    # Implement secure token retrieval here
    return "Bearer <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 When True, uses the service-to-service endpoint path. False
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, you must provide a token resolver function that returns an authentication token. When you use the Agent 365 Observability SDK with the Agent Hosting framework, you can generate tokens by using the TurnContext from agent activities.

from microsoft_agents.activity import load_configuration_from_env
from microsoft_agents.authentication.msal import MsalConnectionManager
from microsoft_agents.hosting.aiohttp import CloudAdapter
from microsoft_agents.hosting.core import (
    AgentApplication,
    Authorization,
    MemoryStorage,
    TurnContext,
    TurnState,
)
from microsoft_agents_a365.runtime import (
    get_observability_authentication_scope,
)

agents_sdk_config = load_configuration_from_env(environ)

STORAGE = MemoryStorage()
CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config)
ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER)
ADAPTER.use(TranscriptLoggerMiddleware(ConsoleTranscriptLogger()))
AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config)

AGENT_APP = AgentApplication[TurnState](
    storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config
)

@AGENT_APP.activity("message", auth_handlers=["AGENTIC"])
async def on_message(context: TurnContext, _state: TurnState):
    aau_auth_token = await AGENT_APP.auth.exchange_token(
                        context,
                        scopes=get_observability_authentication_scope(),
                        auth_handler_id="AGENTIC",
                    )
    # cache this auth token and return via token resolver

For the digital worker scenario, if your agent uses the Microsoft Agent 365 Observability Hosting Library package, use AgenticTokenCache to handle token caching automatically. Register the token once per agent and tenant during an activity handler, and pass cache.get_observability_token as the token_resolver in your observability configuration.

from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.hosting.token_cache_helpers import (
    AgenticTokenCache,
    AgenticTokenStruct,
)
from microsoft_agents_a365.runtime import get_observability_authentication_scope

# Create a shared cache instance
token_cache = AgenticTokenCache()

# Use the cache as your token resolver in configure()
configure(
    service_name="my-agent-service",
    service_namespace="my.namespace",
    token_resolver=token_cache.get_observability_token,
)

@AGENT_APP.activity("message", auth_handlers=["AGENTIC"])
async def on_message(context: TurnContext, _state: TurnState):
    token_cache.register_observability(
        agent_id="agent-456",
        tenant_id="tenant-123",
        token_generator=AgenticTokenStruct(
            authorization=AGENT_APP.auth,
            turn_context=context,
        ),
        observability_scopes=get_observability_authentication_scope(),
    )

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.

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 baggage builder. Set 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 baggage builder. Set 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 baggage builder. Set 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

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 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 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, make sure the following requirements are met:

Validate for store 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.

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 a Bearer token for each export request. If the token resolver is missing or returns null, the export is silently skipped. Make sure your code properly 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 or throws an error. Depending on the SDK, the export is either skipped entirely or the request is sent without an authorization header and fails with HTTP 401.

Resolution:

  • The token resolver is required at initialization. If it's missing, the exporter throws an error on startup. Verify that a token resolver is provided and returns a valid Bearer token.
  • Make sure the correct tenant ID and agent ID are used for BaggageBuilder, because these values are passed to the token resolver.
  • For Azure-hosted agents, verify the Managed Identity has the required API permission for the observability scope.

HTTP 401 Unauthorized

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

Resolution:

  • Verify the token audience matches the observability endpoint scope. The default scope is https://api.powerplatform.com/.default for an agentic agent.
  • Ensure the identity (Managed Identity or app registration) has Agent 365 observability permissions.
  • Check that the token resolver isn't returning a delegated user token, a token for an incorrect audience, or an expired token.

Important

Existing agents upgrading to these package versions require an extra step

This step applies only if you're upgrading an existing agent. New agent installations don't require this step. If you're upgrading to the following package versions or newer, you must grant the new Agent365.Observability.OtelWrite permission to your identity (Managed Identity or app registration). Without this permission, telemetry export fails with HTTP 401.

Platform Minimum version requiring this step
.NET 0.3-beta
Node.js 0.2.0-preview.1
Python 0.3.0

For the required steps, see the changelog in the package you're upgrading.

HTTP 403 Forbidden

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

Resolution:

  • Verify whether the Tenant ID is added to the Agent 365 allowed tenant list for trace ingestion.
  • Confirm the agent identity has the required role or permission for the target tenant.

HTTP 429 / 5xx — 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: