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.
The Voice Live SDK includes built-in OpenTelemetry instrumentation that automatically traces connection, send, and receive operations. Use telemetry to monitor session health, diagnose latency issues, and correlate Voice Live operations with your application traces.
What gets traced
When you enable telemetry, the SDK automatically creates OpenTelemetry spans for:
| Operation | Span name prefix | Description |
|---|---|---|
| WebSocket connect | connect |
Connection establishment and lifecycle |
| Send events | send |
Session updates, conversation items, response requests |
| Receive events | recv |
Server events including responses, VAD, and errors |
Prerequisites
- A working Voice Live setup. Complete one of the following quickstarts:
Reference documentation | Package (PyPi) | Additional samples on GitHub
Additional prerequisites
azure-ai-voicelivepackage version 1.2.0 or later.Install the telemetry dependencies:
pip install opentelemetry-sdk azure-core-tracing-opentelemetryFor Azure Monitor export, install instead:
pip install azure-monitor-opentelemetry
Enable console tracing
Add the following code to your application before calling connect(). This is the smallest code change to start seeing Voice Live spans in your terminal.
from azure.core.settings import settings
# Step 1: Tell azure-core to use OpenTelemetry for tracing.
settings.tracing_implementation = "opentelemetry"
# Step 2: Configure a TracerProvider with a console exporter.
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
SimpleSpanProcessor,
ConsoleSpanExporter,
)
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(
SimpleSpanProcessor(ConsoleSpanExporter())
)
trace.set_tracer_provider(tracer_provider)
# Step 3: Enable the VoiceLive instrumentor.
from azure.ai.voicelive.telemetry import VoiceLiveInstrumentor
os.environ.setdefault(
"AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING", "true"
)
VoiceLiveInstrumentor().instrument()
All connect, send, and recv operations now produce spans printed to stdout.
Export traces to Azure Monitor
To send traces to Application Insights instead of the console, replace the console setup with Azure Monitor configuration. Set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable, then add the following code.
from azure.core.settings import settings
# Step 1: Tell azure-core to use OpenTelemetry for tracing.
settings.tracing_implementation = "opentelemetry"
# Step 2: Configure Azure Monitor as the trace exporter.
from opentelemetry import trace
from azure.monitor.opentelemetry import configure_azure_monitor
application_insights_connection_string = os.environ[
"APPLICATIONINSIGHTS_CONNECTION_STRING"
]
configure_azure_monitor(
connection_string=application_insights_connection_string
)
# Step 3: Enable the VoiceLive instrumentor.
from azure.ai.voicelive.telemetry import VoiceLiveInstrumentor
os.environ.setdefault(
"AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING", "true"
)
VoiceLiveInstrumentor().instrument()
View the results in the Tracing tab in your Azure AI Foundry project page or in Application Insights.
Add custom span attributes
To correlate Voice Live traces with your application context (session IDs, user IDs, or request identifiers), create a custom SpanProcessor.
class CustomAttributeSpanProcessor(SpanProcessor):
"""Add application-specific attributes to every span."""
def on_start(self, span: Span, parent_context=None):
# Add a session identifier to all spans.
span.set_attribute(
"app.session_id", "my-session-123"
)
# Tag send spans with extra context.
if span.name and span.name.startswith("send"):
span.set_attribute(
"app.send.context", "user-interaction"
)
# Tag receive spans with a priority level.
if span.name and span.name.startswith("recv"):
span.set_attribute(
"app.recv.priority", "normal"
)
def on_end(self, span: ReadableSpan):
pass
Register the custom processor with the global tracer provider after your standard telemetry setup:
# Register the custom processor with the global provider.
provider = cast(TracerProvider, trace.get_tracer_provider())
provider.add_span_processor(CustomAttributeSpanProcessor())
Enable content recording
Content recording captures full message payloads (send and receive) in span events as gen_ai.event.content attributes. This is useful for debugging but can capture personal data.
Caution
Content recording may capture personal data. Only enable in development or controlled environments.
# Option 1: Enable via environment variable.
# os.environ[
# "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"
# ] = "true"
# Option 2: Enable programmatically.
VoiceLiveInstrumentor().instrument(
enable_content_recording=True
)
Reference documentation | Package (NuGet) | Additional samples on GitHub
Additional prerequisites
Azure.AI.VoiceLivepackage version 1.1.0 or later..NET 10.0 or later.
Install the telemetry dependencies:
dotnet add package OpenTelemetry dotnet add package OpenTelemetry.Exporter.ConsoleFor Azure Monitor export, install instead:
dotnet add package Azure.Monitor.OpenTelemetry.Exporter
Enable console tracing
Register an OpenTelemetry tracer provider that listens to the Azure.AI.VoiceLive activity source before you construct the VoiceLiveClient. The SDK emits spans automatically when a provider is present.
using Azure.AI.VoiceLive;
using Azure.Identity;
using OpenTelemetry;
using OpenTelemetry.Trace;
// Register an OpenTelemetry provider before constructing the VoiceLive client.
using TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("Azure.AI.VoiceLive")
.AddConsoleExporter()
.Build();
string endpoint = Environment.GetEnvironmentVariable("AZURE_VOICELIVE_ENDPOINT")!;
VoiceLiveClient client = new(new Uri(endpoint), new DefaultAzureCredential());
// All connect, send, and receive operations now produce spans on the console.
VoiceLiveSession session = await client.StartSessionAsync("gpt-realtime");
All connect, send, and receive operations now produce spans printed to stdout.
Reference: OpenTelemetry .NET | VoiceLiveClient
Export traces to Azure Monitor
To send traces to Application Insights instead of the console, replace the console exporter with the Azure Monitor exporter. Set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable, then add the following code.
using Azure.AI.VoiceLive;
using Azure.Identity;
using Azure.Monitor.OpenTelemetry.Exporter;
using OpenTelemetry;
using OpenTelemetry.Trace;
string connectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING")!;
using TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("Azure.AI.VoiceLive")
.AddAzureMonitorTraceExporter(options => options.ConnectionString = connectionString)
.Build();
string endpoint = Environment.GetEnvironmentVariable("AZURE_VOICELIVE_ENDPOINT")!;
VoiceLiveClient client = new(new Uri(endpoint), new DefaultAzureCredential());
VoiceLiveSession session = await client.StartSessionAsync("gpt-realtime");
View the results in the Tracing tab in your Foundry project page or in Application Insights.
Reference: Azure Monitor OpenTelemetry exporter for .NET
Add custom span attributes
To correlate Voice Live traces with your application context (session IDs, user IDs, or request identifiers), implement a processor that derives from BaseProcessor<Activity>.
using System.Diagnostics;
using OpenTelemetry;
internal sealed class CustomAttributesProcessor : BaseProcessor<Activity>
{
private readonly string _sessionId;
private readonly string _userId;
public CustomAttributesProcessor(string sessionId, string userId)
{
_sessionId = sessionId;
_userId = userId;
}
public override void OnStart(Activity activity)
{
activity.SetTag("app.session_id", _sessionId);
activity.SetTag("app.user_id", _userId);
}
}
Register the custom processor with the tracer provider builder after adding the Azure.AI.VoiceLive source:
using TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("Azure.AI.VoiceLive")
.AddProcessor(new CustomAttributesProcessor(sessionId: "sess-123", userId: "user-abc"))
.AddConsoleExporter()
.Build();
Enable content recording
Content recording captures full message payloads (send and receive) on span events. This is useful for debugging but can capture personal data.
Caution
Content recording may capture personal data. Only enable in development or controlled environments.
Set the OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT environment variable to true before starting your application. No code changes are required.
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
When enabled, the SDK attaches event payloads as gen_ai.event.content attributes on the corresponding spans.
Reference documentation | Package (Maven) | Additional samples on GitHub
Additional prerequisites
azure-ai-voicelivepackage version 1.0.0 or later.Java Development Kit (JDK) version 8 or later.
Add the OpenTelemetry dependencies to your
pom.xml:<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> <version>1.45.0</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-logging</artifactId> <version>1.45.0</version> </dependency>For Azure Monitor export, add:
<dependency> <groupId>com.azure</groupId> <artifactId>azure-monitor-opentelemetry-exporter</artifactId> <version>1.0.0-beta.31</version> </dependency>
Enable console tracing
Register a global OpenTelemetry instance with a span exporter before constructing the VoiceLiveAsyncClient. The SDK defaults to GlobalOpenTelemetry.getOrNoop(), so tracing is picked up automatically once a global instance exists.
import com.azure.ai.voicelive.VoiceLiveAsyncClient;
import com.azure.ai.voicelive.VoiceLiveClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
// 1. Register a global OpenTelemetry instance BEFORE building any client.
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
.build();
OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();
// 2. Build the client — it picks up GlobalOpenTelemetry automatically.
String endpoint = System.getenv("AZURE_VOICELIVE_ENDPOINT");
VoiceLiveAsyncClient client = new VoiceLiveClientBuilder()
.endpoint(endpoint)
.credential(new DefaultAzureCredentialBuilder().build())
.buildAsyncClient();
All connect, send, and receive operations now produce spans printed to stdout.
Tip
If you attach the OpenTelemetry Java agent (-javaagent:opentelemetry-javaagent.jar), the global instance is registered automatically and no code changes are required.
Reference: OpenTelemetry Java | VoiceLiveClientBuilder
Export traces to Azure Monitor
To send traces to Application Insights instead of the console, replace the logging exporter with the Azure Monitor exporter. Set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable, then add the following code.
import com.azure.ai.voicelive.VoiceLiveAsyncClient;
import com.azure.ai.voicelive.VoiceLiveClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.monitor.opentelemetry.exporter.AzureMonitorExporterBuilder;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
String connectionString = System.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING");
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(
new AzureMonitorExporterBuilder()
.connectionString(connectionString)
.buildTraceExporter())
.build())
.build();
OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();
String endpoint = System.getenv("AZURE_VOICELIVE_ENDPOINT");
VoiceLiveAsyncClient client = new VoiceLiveClientBuilder()
.endpoint(endpoint)
.credential(new DefaultAzureCredentialBuilder().build())
.buildAsyncClient();
View the results in the Tracing tab in your Foundry project page or in Application Insights.
Reference: Azure Monitor OpenTelemetry exporter for Java
Add custom span attributes
To correlate Voice Live traces with your application context (session IDs, user IDs, or request identifiers), implement a custom SpanProcessor that adds attributes when each span starts.
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
final class CustomAttributesProcessor implements SpanProcessor {
private final String sessionId;
private final String userId;
CustomAttributesProcessor(String sessionId, String userId) {
this.sessionId = sessionId;
this.userId = userId;
}
@Override
public void onStart(Context parentContext, ReadWriteSpan span) {
span.setAttribute(AttributeKey.stringKey("app.session_id"), sessionId);
span.setAttribute(AttributeKey.stringKey("app.user_id"), userId);
}
@Override
public boolean isStartRequired() { return true; }
@Override
public void onEnd(ReadableSpan span) { }
@Override
public boolean isEndRequired() { return false; }
}
Register the custom processor with the tracer provider before registering the global OpenTelemetry instance:
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(new CustomAttributesProcessor("sess-123", "user-abc"))
.addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
.build();
OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();
Reference: OpenTelemetry Java
Enable content recording
Content recording captures full message payloads (send and receive) on span events. This is useful for debugging but can capture personal data.
Caution
Content recording may capture personal data. Only enable in development or controlled environments.
Set the OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT environment variable to true before starting your application. No code changes are required.
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
When enabled, the SDK attaches event payloads as gen_ai.event.content attributes on the corresponding spans.
Reference documentation | Package (npm) | Additional samples on GitHub
Additional prerequisites
@azure/ai-voicelivepackage version 1.0.0 or later.Node.js version 18 or later.
Install the telemetry dependencies:
npm install @opentelemetry/api @opentelemetry/sdk-trace-node @azure/core-tracingFor Azure Monitor export, install instead:
npm install @azure/monitor-opentelemetry-exporterFor browser-based applications, use
@opentelemetry/sdk-trace-webinstead of@opentelemetry/sdk-trace-node.
Enable console tracing
First register an OpenTelemetry provider, then bridge @azure/core-tracing into OpenTelemetry via useInstrumenter() so the SDK emits spans. Add this code before constructing the VoiceLiveClient.
import {
NodeTracerProvider,
SimpleSpanProcessor,
ConsoleSpanExporter,
} from "@opentelemetry/sdk-trace-node";
import { useInstrumenter } from "@azure/core-tracing";
import { trace, context } from "@opentelemetry/api";
import { VoiceLiveClient } from "@azure/ai-voicelive";
import { DefaultAzureCredential } from "@azure/identity";
// 1. Configure OpenTelemetry with a console exporter.
const provider = new NodeTracerProvider({
spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())],
});
provider.register();
// 2. Bridge @azure/core-tracing into OpenTelemetry.
useInstrumenter({
startSpan(name, spanOptions) {
const ctx = spanOptions.tracingContext ?? context.active();
const tracer = trace.getTracer(
spanOptions.packageName ?? "@azure/ai-voicelive",
spanOptions.packageVersion,
);
const span = tracer.startSpan(name, { attributes: spanOptions.spanAttributes, kind: 0 }, ctx);
return {
span: {
end() { span.end(); },
setStatus(s) {
if (s.status === "error") span.setStatus({ code: 2, message: String(s.error ?? "") });
},
setAttribute(k, v) { span.setAttribute(k, v); },
isRecording() { return span.isRecording(); },
recordException(e) { span.recordException(e); },
},
tracingContext: trace.setSpan(ctx, span),
};
},
withContext(ctx, fn, ...args) { return context.with(ctx, fn, undefined, ...args); },
parseTraceparentHeader() { return undefined; },
createRequestHeaders() { return {}; },
});
// 3. Use VoiceLive as normal — spans are emitted automatically.
const client = new VoiceLiveClient(
process.env.AZURE_VOICELIVE_ENDPOINT,
new DefaultAzureCredential(),
);
const session = client.createSession("gpt-realtime");
await session.connect();
All connect, send, and receive operations now produce spans printed to stdout.
Note
The samples in this article use useInstrumenter() for ESM compatibility. If your app is CommonJS, you can use the standard createAzureSdkInstrumentation() from @azure/opentelemetry-instrumentation-azure-sdk instead.
Reference: OpenTelemetry JavaScript SDK | VoiceLiveClient
Export traces to Azure Monitor
To send traces to Application Insights instead of the console, replace the console exporter with AzureMonitorTraceExporter. Set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable, then add the following code. The useInstrumenter() bridge from the previous section is still required.
import { NodeTracerProvider, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";
import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";
const exporter = new AzureMonitorTraceExporter({
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
});
const provider = new NodeTracerProvider({
spanProcessors: [new SimpleSpanProcessor(exporter)],
});
provider.register();
// Register the same useInstrumenter() bridge shown in the console tracing section.
View the results in the Tracing tab in your Foundry project page or in Application Insights.
Reference: Azure Monitor OpenTelemetry exporter for JavaScript
Add custom span attributes
To correlate Voice Live traces with your application context (session IDs, user IDs, or request identifiers), implement a custom SpanProcessor that adds attributes when each span starts.
class CustomAttributesProcessor {
constructor(sessionId, userId) {
this._sessionId = sessionId;
this._userId = userId;
}
onStart(span) {
span.setAttribute("app.session_id", this._sessionId);
span.setAttribute("app.user_id", this._userId);
}
onEnd() { }
async shutdown() { }
async forceFlush() { }
}
Register the custom processor on the tracer provider before calling provider.register():
const provider = new NodeTracerProvider({
spanProcessors: [
new CustomAttributesProcessor("sess-123", "user-abc"),
new SimpleSpanProcessor(new ConsoleSpanExporter()),
],
});
provider.register();
Reference: OpenTelemetry JavaScript SDK
Enable browser tracing
For browser-based applications, use WebTracerProvider instead of NodeTracerProvider. The same useInstrumenter() bridge applies. Spans can be exported to an in-page element, the browser console, or any OpenTelemetry-compatible backend.
import { WebTracerProvider, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-web";
import { ConsoleSpanExporter } from "@opentelemetry/sdk-trace-base";
import { useInstrumenter } from "@azure/core-tracing";
import { trace, context } from "@opentelemetry/api";
import { VoiceLiveClient } from "@azure/ai-voicelive";
const provider = new WebTracerProvider({
spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())],
});
provider.register();
// Register the same useInstrumenter() bridge shown in the console tracing section.
// Browsers don't support DefaultAzureCredential. Use AzureKeyCredential instead.
const credential = { key: import.meta.env.VITE_VOICELIVE_API_KEY };
const client = new VoiceLiveClient(import.meta.env.VITE_VOICELIVE_ENDPOINT, credential);
const session = client.createSession("gpt-realtime");
await session.connect();
Note
Browsers don't support DefaultAzureCredential. Use AzureKeyCredential or a bearer-token flow instead.
Enable content recording
Content recording captures full message payloads (send and receive) on span events. This is useful for debugging but can capture personal data.
Caution
Content recording may capture personal data. Only enable in development or controlled environments.
Set the OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT environment variable to true before starting your application. No code changes are required.
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
When enabled, the SDK attaches event payloads as gen_ai.event.content attributes on the corresponding spans.
Production best practices
- Batch export: Use
BatchSpanProcessorinstead ofSimpleSpanProcessorin production to reduce overhead. - Sampling: Configure a sampling strategy to control trace volume at scale.
- Sensitive data: Don't enable content recording in production. Message payloads can contain personal data.
- Correlation: Use custom span attributes to add session or user identifiers so you can filter traces in your observability backend.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| No spans appear | Missing AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING env var |
Set AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true |
| No spans appear | VoiceLiveInstrumentor().instrument() not called |
Call instrument() before connect() |
| Spans missing in Azure Monitor | Missing or invalid connection string | Verify APPLICATIONINSIGHTS_CONNECTION_STRING is set correctly |
| Spans appear in console but not in Azure Monitor | Using ConsoleSpanExporter instead of Azure Monitor |
Switch to configure_azure_monitor() |
| Custom attributes missing | Processor registered after spans are created | Register the custom processor before calling connect() |