How does Rius read OpenInference span kind attributes?
Rius reads the openinference.span.kind attribute as the span’s kind and uses it to classify the span in trace views and per-kind analytics. The attribute is stored as sent, and Rius derives the matching gen_ai.operation.name from it. Kinds that Rius has no category for are handled as described below, so you know what to expect in the console.
How it works
OpenInference instrumentors write one attribute for the kind, openinference.span.kind, a string the OpenInference spec makes required on every span it defines. Rius classifies these values: AGENT, LLM, TOOL, RETRIEVER, EMBEDDING and CHAIN, plus RERANKER. Its registry entry lists them. The spec also defines GUARDRAIL, EVALUATOR, PROMPT and DECISION, which the Rius docs give no category, so do not rely on them for classification.
- Kind and operation are paired. Set either
openinference.span.kindorgen_ai.operation.nameand Rius derives the other.chat,text_completionandgenerate_contentmap toLLM.invoke_agentandcreate_agentmap toAGENT.execute_toolmaps toTOOL,embeddingstoEMBEDDINGandretrievaltoRETRIEVER.invoke_workflowandplanmap toCHAIN. CHAINgets no operation back. The GenAI conventions define no operation for a generic step, so aCHAINspan has a kind and nogen_ai.operation.name.- The key is stored as sent. Rius does not rename
openinference.span.kind, so you search and filter on that exact key. RERANKERhas no category yet. A reranking span shows asLLMwhen it carriesgen_ai.request.model, and as Other when it does not.- LLM calls follow the kind. The console and alerts count a span as an LLM call when its kind is
LLM, set directly or derived from an operation. A span with neither a kind nor an operation counts when it carriesgen_ai.request.model. Agent, tool, retrieval and embedding spans are not LLM calls even when they carry a model. Their cost still appears in the per-model breakdown and the cost totals.
The other OpenInference attributes are handled separately. The llm.* attributes, such as llm.model_name and llm.token_count.*, are normalized at ingest onto their gen_ai.* keys, which is what makes model analytics and cost work. input.value and output.value are kept as span content. Where a native gen_ai.* key is already present, it wins.
Set it up
- Point an OpenInference instrumentor at the Rius ingest endpoint. This example uses the OpenAI instrumentor. The exporter class is the protobuf-over-HTTP one, and the span attribute limit is raised to 4096 because OpenInference writes one attribute per message field and per tool field, and OpenTelemetry keeps only 128 by default.
from opentelemetry import trace
from opentelemetry.sdk.trace import SpanLimits, TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from openinference.instrumentation.openai import OpenAIInstrumentor
# Raise the attribute limit: see "Raise the span attribute limit" below.
provider = TracerProvider(span_limits=SpanLimits(max_span_attributes=4096))
provider.add_span_processor(
BatchSpanProcessor(
OTLPSpanExporter(
endpoint="https://ingest.eu.console.rius-glassflow.com/v1/traces",
headers={"Authorization": "Bearer <your API key>"},
)
)
)
trace.set_tracer_provider(provider)
OpenAIInstrumentor().instrument(tracer_provider=provider)
# ... run your agent ...
provider.shutdown() # flush queued spans before the process exits- Make a model call. The instrumentor sets
openinference.span.kindtoLLMon the span for that call, and Rius classifies it from there. - If you emit spans by hand instead, set either
openinference.span.kindorgen_ai.operation.nameon each span. Name spans the way the GenAI conventions ask, the operation followed by what it acted on, such asexecute_tool get_weatherorretrieval product-kb. - When you search or filter, use
gen_ai.usage.input_tokensrather thanllm.token_count.prompt, because the normalized values are stored under thegen_ai.*keys.
The full wiring is on the OpenInference page. The Span attribute reference has the complete kind and operation table. For every way to send traces, see Trace LLM calls with OpenTelemetry.
What you get
- Each span is classified by its kind in trace views, so model calls, tool calls, agent steps, retrievals, embeddings and generic chain steps are told apart.
- Per-kind analytics and kind filters work for OpenInference spans the same way they do for spans from the Rius SDKs.
- You set one attribute and get both: Rius fills in the matching
gen_ai.operation.name, except forCHAIN. - Model calls get model analytics, token usage and server-side cost, because the
llm.*attributes are normalized ontogen_ai.*keys at ingest. Costs are list-price estimates in US dollars. - Reranking spans stay visible. They show as
LLMwhen they carry a request model and as Other when they do not. - The Interoperability section lists the other conventions Rius reads, if your fleet mixes senders.
When something else fits
- If your app is Python, the Rius SDK ships the same OpenInference instrumentors as integrations. It sets both the kind and the operation, and it wires the exporter and the attribute limit for you.
- If you want a reranking step counted in its own category, note that Rius has no reranker category yet.
- If your instrumentation follows another convention, such as OpenLLMetry, see the supported-conventions table in the attribute reference for what each one gets.