Skip to content

[draft][VoiceLive] Add OpenTelemetry tracing support with GenAI semantic conventions#45857

Open
xitzhang wants to merge 11 commits intomainfrom
xitzhang/telemetrylog
Open

[draft][VoiceLive] Add OpenTelemetry tracing support with GenAI semantic conventions#45857
xitzhang wants to merge 11 commits intomainfrom
xitzhang/telemetrylog

Conversation

@xitzhang
Copy link
Member

@xitzhang xitzhang commented Mar 23, 2026

Summary

VoiceLive Telemetry — Design Doc

SDK: azure-ai-voicelive 1.2.0b5
Pattern: Monkey-patching (same as azure-ai-agents AgentsInstrumentor)
Service impact: None — purely client-side


Overview

Opt-in OpenTelemetry tracing for VoiceLive WebSocket sessions. When enabled, the SDK automatically emits spans for connect, send, recv, and close — with voice-specific attributes and session-level counters. Follows GenAI Semantic Conventions v1.34.0.

Activation

  • Gated by AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true (matches azure-ai-agents)
  • User calls VoiceLiveInstrumentor().instrument()
  • Content recording (full payloads in span events) controlled by OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true — off by default for privacy

Span Structure

A parent connect span lives for the entire WebSocket session. All send/recv/close operations are child spans:

connect                              ← session lifetime
├── send session.update              ← send spans include event type in name
├── send response.create
├── recv session.created             ← recv spans are renamed to "recv {type}"
├── recv response.audio.delta           after receiving (via span.update_name)
├── recv response.done
├── send input_audio_buffer.append
├── send response.cancel
├── recv error
└── close

What We Track

Session-level (on the connect span, flushed at session close)

Attribute What Source
gen_ai.voice.session_id Voice session ID session.created / session.updated recv
gen_ai.voice.input_audio_format Input codec (e.g., pcm16) session.update send
gen_ai.voice.output_audio_format Output codec session.update send
gen_ai.voice.turn_count Completed response turns Incremented on each response.done recv
gen_ai.voice.interruption_count User interruptions Incremented on each response.cancel send
gen_ai.voice.audio_bytes_sent Total audio payload bytes sent Accumulated from input_audio_buffer.append (base64-decoded)
gen_ai.voice.audio_bytes_received Total audio payload bytes received Accumulated from response.audio.delta (base64-decoded)
gen_ai.voice.first_token_latency_ms Time to first audio/text response response.create send → first delta recv
gen_ai.request.model Model name Set at connect time
server.address / server.port Server endpoint Parsed from URL at connect time

Per-message (on each send/recv span)

Attribute What
gen_ai.voice.event_type Event type string (e.g., "response.done")
gen_ai.voice.message_size JSON payload size in bytes
gen_ai.usage.input_tokens Input token count (from response.done)
gen_ai.usage.output_tokens Output token count (from response.done)

Span events

Event When Data
gen_ai.input.messages Every send System, event type, payload (if content recording on)
gen_ai.output.messages Every recv System, event type, payload (if content recording on)
gen_ai.voice.error Server error event Error code and message
gen_ai.voice.rate_limits.updated Server rate limit event Rate limits JSON

Standard attributes (every span)

az.namespace = "Microsoft.CognitiveServices" · gen_ai.system = "az.ai.voicelive" · gen_ai.operation.name = connect/send/recv/close


Usage Examples

Basic: Console tracing

import os, asyncio
from azure.core.settings import settings
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter

# 1. Configure OpenTelemetry
settings.tracing_implementation = "opentelemetry"
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(tracer_provider)

# 2. Enable VoiceLive instrumentation
os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
from azure.ai.voicelive.telemetry import VoiceLiveInstrumentor
VoiceLiveInstrumentor().instrument()

# 3. Use VoiceLive as normal — spans are emitted automatically
from azure.core.credentials import AzureKeyCredential
from azure.ai.voicelive.aio import connect
from azure.ai.voicelive.models import RequestSession, Modality, ServerVad, UserMessageItem, InputTextContentPart

async def main():
    async with connect(
        endpoint=os.environ["AZURE_VOICELIVE_ENDPOINT"],
        credential=AzureKeyCredential(os.environ["AZURE_VOICELIVE_API_KEY"]),
        model="gpt-4o-realtime-preview",
    ) as conn:
        await conn.session.update(session=RequestSession(
            modalities=[Modality.TEXT],
            instructions="You are a helpful assistant.",
            turn_detection=ServerVad(),
        ))
        await conn.conversation.item.create(
            item=UserMessageItem(content=[InputTextContentPart(text="Hello!")])
        )
        await conn.response.create()
        async for event in conn:
            if getattr(event, "type", None) == "response.done":
                break
    tracer_provider.force_flush()

asyncio.run(main())

Azure Monitor

from azure.core.settings import settings
settings.tracing_implementation = "opentelemetry"

from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor(connection_string=os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"])

import os
os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
from azure.ai.voicelive.telemetry import VoiceLiveInstrumentor
VoiceLiveInstrumentor().instrument()
# ... use VoiceLive as normal — traces appear in Application Insights

Content recording (captures full message payloads)

os.environ["AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING"] = "true"
os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = "true"

VoiceLiveInstrumentor().instrument()
# or:
VoiceLiveInstrumentor().instrument(enable_content_recording=True)

Custom span processing (e.g., add extra attributes)

from opentelemetry.sdk.trace import SpanProcessor

class CustomProcessor(SpanProcessor):
    def on_start(self, span, parent_context=None):
        span.set_attribute("deployment.environment", "staging")
        span.set_attribute("service.version", "1.2.0b5")

tracer_provider.add_span_processor(CustomProcessor())

Full runnable samples: samples/telemetry/

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

General Guidelines and Best Practices

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, see this page.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

Copilot AI review requested due to automatic review settings March 23, 2026 20:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in OpenTelemetry tracing layer to azure-ai-voicelive to provide GenAI-semconv-aligned observability for VoiceLive WebSocket sessions, plus documentation, samples, and unit tests.

Changes:

  • Introduces azure.ai.voicelive.telemetry with a VoiceLiveInstrumentor that monkey-patches connection lifecycle + send/recv/close to emit spans and GenAI/voice attributes.
  • Adds telemetry samples (console, Azure Monitor, custom attributes, content recording) and updates samples README.
  • Adds unit tests and updates changelog for the new preview feature.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
sdk/voicelive/azure-ai-voicelive/azure/ai/voicelive/telemetry/_voicelive_instrumentor.py Implements monkey-patching and span/event/attribute emission for connect/send/recv/close.
sdk/voicelive/azure-ai-voicelive/azure/ai/voicelive/telemetry/_utils.py Defines semantic attribute constants and start_span helper.
sdk/voicelive/azure-ai-voicelive/azure/ai/voicelive/telemetry/init.py Exposes VoiceLiveInstrumentor as public API.
sdk/voicelive/azure-ai-voicelive/azure/ai/voicelive/telemetry/README.md Documents architecture, setup, attributes/events, and troubleshooting.
sdk/voicelive/azure-ai-voicelive/samples/telemetry/sample_voicelive_with_console_tracing.py Console exporter sample showing end-to-end tracing usage.
sdk/voicelive/azure-ai-voicelive/samples/telemetry/sample_voicelive_with_azure_monitor_tracing.py Azure Monitor exporter sample for Application Insights.
sdk/voicelive/azure-ai-voicelive/samples/telemetry/sample_voicelive_with_console_tracing_custom_attributes.py Demonstrates adding custom attributes via a custom span processor.
sdk/voicelive/azure-ai-voicelive/samples/telemetry/sample_voicelive_with_content_recording.py Demonstrates opt-in message content capture into span events.
sdk/voicelive/azure-ai-voicelive/samples/README.md Adds a telemetry samples section and prerequisite installs.
sdk/voicelive/azure-ai-voicelive/tests/test_unit_telemetry.py Adds unit tests for instrumentation state, attributes, events, and counters.
sdk/voicelive/azure-ai-voicelive/CHANGELOG.md Adds release notes entry for tracing support and telemetry attributes/events.

@github-actions
Copy link

github-actions bot commented Mar 23, 2026

API Change Check

APIView identified API level changes in this PR and created the following API reviews

azure-ai-voicelive

xitzhang and others added 4 commits March 23, 2026 14:13
…_voicelive_instrumentor.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…_utils.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…iability

- Attach connect span to OTel context so send/recv/close spans are
  parented under it (bypasses azure-core suppression for CLIENT spans)
- Detach context token in __aexit__ to restore previous context
- Update recv spans to include event type in name (e.g. 'recv session.created')
- Replace brittle MagicMock + del .get pattern with types.SimpleNamespace
  in test_extract_session_id_from_object and test_error_event_with_object_result
@xitzhang xitzhang changed the title [draft][VoiceLive] Add OpenTelemetry tracing support with GenAI seman… [draft][VoiceLive] Add OpenTelemetry tracing support with GenAI semantic conventions Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants