Skip to content

OpenTelemetry

View as Markdown

OpenTelemetry is a common standard for tracing, which means recording what your app does. A trace is made of spans, and a span is one traced unit of work, like one AI call. If your app already sends traces, point them at ai-tally. It reads the AI calls in them and works out what each one cost.

Set these where your app sends its traces:

Terminal window
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://ingest.ai-tally.com/v1/otlp/traces"
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="authorization=Bearer%20${TALLY_KEY}"

Three things to get right:

  • Use the _TRACES_ settings. The shorter OTEL_EXPORTER_OTLP_ENDPOINT adds /v1/traces to the URL, so set the full traces address with OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.
  • Send OTLP over HTTP. ai-tally reads both encodings, http/protobuf and http/json, plain or gzip-compressed. The standard HTTP exporters for Python and Go, and the Collector’s otlphttp exporter, send http/protobuf by default. Use HTTP rather than gRPC.
  • Collector users: use the otlphttp exporter with its default settings.

The API key needs write scope.

These attributes, the named values on a span, tell ai-tally what a call was:

Attribute Example Why
gen_ai.system openai The AI provider. Needed for a price.
gen_ai.request.model or gen_ai.response.model gpt-4o-mini The model. Needed for a price.
gen_ai.operation.name chat The kind of call (see below).
gen_ai.usage.input_tokens 12 Tokens sent in. Needed for a price.
gen_ai.usage.output_tokens 5 Tokens sent back. Needed for a price, except for embeddings.
gen_ai.usage.cached_input_tokens 8 Input tokens the provider served from its cache, which cost less.
gen_ai.feature_tag support-chat Which feature made the call.
gen_ai.account_id_hash 64-character code Which customer, as a hashed customer id that cannot be traced back. Make it with python -m aitally.hash_account your-customer-id.
gen_ai.session_id sess_42 Groups calls from one user session.
  • The provider attribute. ai-tally reads the provider from gen_ai.system. If your library sets the newer gen_ai.provider.name, set gen_ai.system as well.
  • Missing values. If a price value is missing, the call is still saved, with a blank cost instead of $0.

gen_ai.operation.name decides where a call is counted in the dashboard:

Value Counted as
chat LLM
embeddings Embeddings
tool Tool calls. Send the cost in gen_ai.tool.cost_micro_usd, in whole micro-dollars.
vector Vector DB. Send the cost in gen_ai.tool.cost_micro_usd.
  • Text stays out. Attributes that hold text are dropped before anything is saved: any whose name ends in prompt, completion, messages, content, text or body.
  • Hash personal details before you send them. ai-tally accepts hashed ids, and refuses a span holding an email address or an attribute named like email, user_id or phone.
  • Span size. Each span can be up to 64 KiB.
  • Sending too fast. A 429 reply means slow down. Wait the number of seconds in its Retry-After header, then send again.