Skip to Content
Rius

How does Rius read OpenLLMetry token usage attributes?

Rius reads OpenLLMetry token usage and moves it onto the standard gen_ai.usage.input_tokens and gen_ai.usage.output_tokens keys when spans arrive. Older OpenLLMetry releases spell usage as gen_ai.usage.prompt_tokens and completion_tokens, and current releases already send gen_ai.* attributes. Both end up as the same token counts on the span, and Rius uses them for model analytics and cost.

How it works

OpenLLMetry has used several attribute conventions over its releases. Rius normalizes all of them at ingest, which means it moves the values onto their canonical keys before storage and removes the source keys it mapped.

  • Current releases emit OTel GenAI attributes such as gen_ai.usage.input_tokens. These are stored as sent.
  • Older releases spell usage as gen_ai.usage.prompt_tokens and completion_tokens. Rius moves them to gen_ai.usage.input_tokens and gen_ai.usage.output_tokens.
  • Native keys win. If a span carries both a native gen_ai.* key and an older spelling, the native value stays. Normalization fills gaps and never overwrites.
  • Keys with no canonical equivalent, such as llm.usage.total_tokens, are stored under their own names.

The canonical counts have a defined meaning. gen_ai.usage.input_tokens is prompt tokens including cached ones, and gen_ai.usage.output_tokens is completion tokens including reasoning ones.

Cost comes from these counts. Rius computes it on the server from gen_ai.request.model plus the token counts, so you never send a cost attribute. A span needs the model and at least one count, and a count it leaves out is read as 0. A span with no model, a model the price catalog does not know, or no counts gets no cost.

The full mapping is in the supported-conventions matrix of the span attribute reference.

Set it up

  1. Point OpenLLMetry’s exporter at Rius. The OpenLLMetry page covers it in full.
from traceloop.sdk import Traceloop Traceloop.init( app_name="my-agent", api_endpoint="https://ingest.eu.console.rius-glassflow.com", headers={"Authorization": "Bearer <your API key>"}, )

In Python, remove any old TRACELOOP_BASE_URL or TRACELOOP_HEADERS from the environment, because they override these arguments. Set TRACELOOP_METRICS_ENABLED=false, because Rius ingests traces only and the SDK’s metrics exports otherwise fail with a 404.

  1. Run one traced LLM call from your application.
  2. Open the trace in the console and select the model call. The span shows a model name and token counts.
  3. When you search or filter on usage, use the canonical key. A filter on gen_ai.usage.input_tokens matches. A filter on gen_ai.usage.prompt_tokens matches nothing, because Rius removed that key during normalization.
  4. If you run a long agent loop on an older OpenLLMetry release, raise OpenTelemetry’s per-span attribute limit. Those releases record messages one attribute per field, and a span past the limit can lose its model or usage.
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096

For a wider view of the ways to send traces, see Trace LLM calls with OpenTelemetry and the interoperability overview.

What you get

  • Token counts on each model call, the same whether the app runs a current or an older OpenLLMetry release.
  • Model analytics and per-call cost, computed by Rius from the model name and the token counts. Costs are list-price estimates in US dollars.
  • One key to search on, gen_ai.usage.input_tokens, instead of one per OpenLLMetry version.
  • Your existing OpenLLMetry instrumentation unchanged. You only change where it exports.
  • llm.usage.total_tokens kept on the span under its own name when OpenLLMetry sends it, though it does not feed analytics.

When something else fits

  • If your app emits traces with a vanilla OpenTelemetry SDK or a collector, send the gen_ai.usage.* keys directly. The interoperability overview lists each sender path.
  • If you want to start fresh instead of keeping OpenLLMetry, the glassflow-rius SDK sets the canonical keys for you.

Still stuck? Get help

Last updated on