otel-livekit-style

star 10

LiveKit Agents OpenTelemetry style: entrypoint/session lifecycle spans, shutdown callbacks, session metrics, and LLM turn token counters.

superloglabs By superloglabs schedule Updated 5/11/2026

name: otel-livekit-style description: "LiveKit Agents OpenTelemetry style: entrypoint/session lifecycle spans, shutdown callbacks, session metrics, and LLM turn token counters."

OTel LiveKit Style

LiveKit session lifecycle begins in entrypoint(ctx) and cleanup ends in ctx.add_shutdown_callback(on_shutdown).

Whole-Session Span

It is okay for a voice.session span to end in on_shutdown, because the operation crosses a framework callback boundary. Make it active while child work is registered and started.

async def entrypoint(ctx: agents.JobContext) -> None:
    await ctx.connect()
    started_at = asyncio.get_running_loop().time()
    session_span = tracer.start_span(
        "voice.session",
        attributes={
            "tenant.id": tenant_id,
            "user.id": user_id,
            "voice.room_name": room_name,
        },
    )

    with trace.use_span(session_span, end_on_exit=False):
        voice_sessions_started.add(1, {
            "tenant.id": tenant_id,
            "voice.room_name.present": room_name != "unknown",
        })

        async def on_shutdown() -> None:
            duration_ms = int((asyncio.get_running_loop().time() - started_at) * 1000)
            session_span.set_attribute("voice.duration_ms", duration_ms)
            voice_session_duration.record(duration_ms, {
                "tenant.id": tenant_id,
                "voice.disconnect_reason": disconnect_reason,
                "outcome": "success",
            })
            session_span.end()

        ctx.add_shutdown_callback(on_shutdown)
        await _deliver_initial_greeting(...)

Do not replace this with a short voice.session.end span inside shutdown.

Bounded Session Work

Bounded operations still get their own decorators.

@tracer.start_as_current_span("voice.deliver_initial_greeting")
async def _deliver_initial_greeting(...):
    ...

Session Metrics

Use both:

  • voice.sessions.started counter at entrypoint start
  • voice.session.duration_ms histogram in shutdown

Add product metrics for important voice events, e.g. voice.greetings.delivered.

Smoke Checks

For a minimal LiveKit fixture, a good smoke path imports the agent and executes one tiny instrumented function or starts a span/log record with a local OTLP endpoint. Checking that tracer/meter objects are non-None is not enough.

LLM Turns

Every LLM provider/call site in the voice agent needs:

  • span around the call
  • token counters (llm.tokens.input, llm.tokens.output)
  • tenant/provider/model/use case/call site/outcome attributes

Do not add llm.cost_usd metrics; Superlog estimates cost centrally from provider/model/token data.

Name the span for the product operation, not the provider transport call. For example, prefer llm.voice_response or llm.generate_copy over llm.anthropic.messages.create.

attrs = {
    "tenant.id": tenant_id,
    "llm.provider": "anthropic",
    "llm.model": model,
    "llm.use_case": "voice.initial_greeting",
    "llm.call_site": "_call_mug_copy_llm",
    "outcome": "success",
}
llm_tokens_input.add(input_tokens, attrs)
llm_tokens_output.add(output_tokens, attrs)
Install via CLI
npx skills add https://github.com/superloglabs/skills --skill otel-livekit-style
Repository Details
star Stars 10
call_split Forks 3
navigation Branch main
article Path SKILL.md
More from Creator
superloglabs
superloglabs Explore all skills →