Skip to Content

How do I group spans into sessions with OpenInference instrumentors?

Rius groups OpenInference spans into sessions by the session.id attribute, which you set on every span of a conversation or run. The standard OpenInference wiring for Rius does not set it, so until you add it each trace counts as its own session. Once every span carries the same session.id, Rius groups those traces into one session.

How it works

  • Rius reads session.id exactly as sent on OpenInference spans. It does not rename or rewrite it.
  • Rius reads it per span, so set it on every span of the trace, not only the root. A span without it is not grouped with the rest.
  • If a span has no session.id, Rius uses gen_ai.conversation.id, the OpenTelemetry GenAI conventions’ session key. If neither is present, the span is grouped by its trace id, so each trace is its own session.
  • The instrumentor code on the OpenInference page only builds the tracer provider and the exporter. It sets no session value, so the session is yours to add.
  • The Rius SDKs ship the same OpenInference instrumentors as integrations. They also offer session scopes that stamp the attribute for you.

Set it up

  1. Choose a session id: any string that stays the same for one conversation or agent run and differs between them. Use an opaque value, such as a generated id, not personal data.

  2. Send your OpenInference spans to Rius. This is the wiring from the OpenInference page, shown here for OpenAI:

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>"}, ) ) ) OpenAIInstrumentor().instrument(tracer_provider=provider)
  1. Add session.id to every span of the trace, the root and every LLM or tool span under it, with the same value for the whole conversation. In a plain OpenTelemetry setup like the one above, you do this yourself with your own OpenTelemetry code. Start your own spans from the same provider, with provider.get_tracer(__name__), or register it first with trace.set_tracer_provider(provider): a tracer from the unregistered global provider exports nothing. Setting it only on the root span is not enough. If your spans already follow the GenAI conventions, you can set gen_ai.conversation.id instead, and Rius reads it as the session when session.id is absent.

  2. If you use the Rius SDK instead of your own provider, let it stamp the value. In Python, rius.session sets session.id for the code inside its scope. In TypeScript, withSession does the same. To give a whole process one session, set RIUS_SESSION_ID. Every trace from that process then lands in the same session, so use it only when one process is one session. Install the SDK with the extra for your library, for example:

pip install "glassflow-rius[openai]" openai
  1. Keep all attributes on each span. OpenInference writes one attribute per message field and per tool field, and OpenTelemetry keeps only 128 attributes per span by default. Beyond that, a span silently loses attributes. The code above raises the limit in the provider. For any language you can set it through the environment instead:
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096

The Rius SDKs already set 4096. For the full list of attributes Rius reads, including user.id, see the span attribute reference. For the other ways to send traces, see Trace LLM calls with OpenTelemetry.

What you get

  • Traces that share a session.id are grouped as one session, so a multi-turn conversation or a long agent run reads as one unit instead of separate traces.
  • Model, token and cost analytics stay in place. Rius normalizes the OpenInference model and token attributes into their gen_ai.* keys at ingest and computes cost on the server, so adding a session id changes grouping only.
  • A predictable fallback. Spans without a session id are still ingested and shown, each trace on its own.

When something else fits

  • If you want each trace to stand alone, set no session value. Every trace is already its own session.
  • If you would rather not stamp attributes by hand, run the instrumentors through the Rius SDK and use its session scope, or RIUS_SESSION_ID when one process is one session.
  • If your instrumentation follows the OpenTelemetry GenAI conventions, gen_ai.conversation.id already groups spans into sessions without a separate session.id.

Still stuck? Get help

Last updated on