Skip to main content

Documentation Index

Fetch the complete documentation index at: https://patter-06b046ce-feat-observability-otel-attrs-0-6-1.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Patter ships opt-in OpenTelemetry tracing that covers the four hot spots on the voice pipeline: STT, LLM, TTS, and tool calls. Every span carries the current getpatter.call.id so you can group by call in your backend.

Enable tracing

Tracing is disabled by default. Install the optional dependency and set the env flag:
pip install 'getpatter[tracing]'
export PATTER_OTEL_ENABLED=1
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318   # any OTLP/HTTP collector
Then call init_tracing once at process start — typically from the same module that creates your Patter client:
from getpatter.observability import init_tracing

init_tracing(
    service_name="my-voice-bot",
    otlp_endpoint="http://localhost:4318",
    resource_attributes={"deployment.environment": "staging"},
)
If PATTER_OTEL_ENABLED is not set, init_tracing returns False and every span becomes a no-op — zero cost when disabled.

Emitted spans

Span nameFiresAttributes
getpatter.callOne per call (root span)getpatter.call.id, getpatter.call.direction, getpatter.call.provider_mode
getpatter.sttOne per final transcriptgetpatter.stt.text_len, getpatter.stt.confidence
getpatter.endpointOne per detected end-of-utterancegetpatter.endpoint.silence_ms
getpatter.llmOne per LLM iteration (incl. tool rounds) — wraps the pipeline LLM call so TTFT is measured per turngetpatter.llm.iteration, getpatter.llm.history_size, getpatter.llm.ttft_ms
getpatter.ttsOne per synthesized sentencegetpatter.tts.text_len
getpatter.bargeinOne per barge-in eventgetpatter.bargein.cancelled_text_len
getpatter.toolOne per tool invocationgetpatter.tool.name, getpatter.tool.transport
All TS spans use the same getpatter.* namespace as Python (the legacy patter.* names were normalised in 0.5.3 — both SDKs now emit identical span names so a single dashboard query works across runtimes).

PII hygiene

Patter never exports user utterances, tool payloads, or LLM content as span attributes. Only sizes, counts, and identifiers are emitted — traces are safe to ship to a shared Jaeger / Honeycomb / Grafana Cloud instance.

Cost and latency attributes (patter.*)

Beyond the spans listed above, every billable hot path stamps patter.cost.* and patter.latency.* attributes on its span starting in 0.6.0. External aggregators (e.g. the patter-agent-runner acceptance suite) read these directly to compute per-call USD and latency without touching the SDK’s pricing table.
AttributeTypeWhere it fires
patter.call_id, patter.sidestrEvery cost/latency span (routing tags)
patter.cost.telephony_minutes, patter.telephony, patter.directionfloat / strTwilio + Telnyx adapters on call end
patter.cost.stt_seconds, patter.stt.providerfloat / strEach final transcript (Deepgram, AssemblyAI, Whisper, OpenAI-Transcribe, Soniox, Speechmatics, Cartesia)
patter.cost.tts_chars, patter.tts.providerint / strEach synthesis (ElevenLabs, OpenAI, Cartesia, LMNT, Rime)
patter.cost.llm_input_tokens, patter.cost.llm_output_tokens, patter.llm.providerint / int / strEach completion (OpenAI, Anthropic, Google Gemini, Groq, Cerebras)
patter.cost.realtime_minutes, patter.realtime.providerfloat / strOpenAI Realtime + ElevenLabs ConvAI on session end
patter.latency.ttfb_ms, patter.latency.turn_msfloatPer completed agent turn (pipeline mode)
The two routing tags (patter.call_id, patter.side) propagate via asyncio-safe ContextVars set at the top of the per-call WebSocket bridge, so all spans emitted under a call inherit them automatically — no manual wiring per span.

Attach a custom exporter (Patter._attach_span_exporter)

Embedding tools that observe Patter from the outside can wire their own exporter without touching PATTER_OTEL_ENABLED or init_tracing:
from opentelemetry.sdk.trace.export import SpanExporter
from getpatter import Patter

exporter: SpanExporter = my_exporter()  # any OTel SpanExporter
phone = Patter(...)
phone._attach_span_exporter(exporter, side="driver")  # or side="uut" (default)
side is stamped on every cost/latency span this Patter instance emits during its call lifecycle. It exists to disambiguate two-Patter-instances-in-one-process layouts (e.g. driver vs unit-under-test in agent-to-agent acceptance tests). Default is "uut" if you only have one instance. The leading underscore signals this is not part of the customer-facing API surface — it is a stable, public-but-underscore hook for tooling.

Shutdown

Call shutdown_tracing() during graceful shutdown to flush any pending spans:
from getpatter.observability import shutdown_tracing

shutdown_tracing()

Troubleshooting

No spans appear → confirm PATTER_OTEL_ENABLED=1 is set in the process that calls init_tracing. Quick check:
from getpatter.observability import is_enabled
print(is_enabled())
Collector refuses spans → the endpoint defaults to OTLP/HTTP on port 4318. If you’re running the gRPC-only OTel Collector image, switch to otel/opentelemetry-collector-contrib or enable the HTTP receiver in your collector config.
Tracing has full TypeScript parity since 0.5.3 — span names, attributes, and PII hygiene are identical. See TS Tracing.