Can I send traces from the OpenTelemetry Python SDK to Rius unchanged?
Yes, Rius accepts traces from the OpenTelemetry Python SDK as they are: you change only the exporter settings, not your instrumentation. Point the OTLP exporter at the Rius ingest endpoint with your API key as a Bearer header, and spans arrive as one trace per run. Rius reads the standard gen_ai.* attributes on each span and computes cost on its side, so you never send a cost value.
How it works
The Rius ingest endpoint is standard OTLP over HTTP, so the Python SDK needs no Rius-specific code. Rius accepts http/protobuf (recommended) or http/json, with gzip allowed. There is no gRPC endpoint, and Rius ingests traces only, not OTLP metrics or logs.
The standard exporter variables carry the whole configuration. The Python exporter you import from opentelemetry.exporter.otlp.proto.http is what selects http/protobuf. Built with no arguments, it reads the variables and appends /v1/traces to the base endpoint itself. If you pass an endpoint in code instead, give it the full path, https://ingest.eu.console.rius-glassflow.com/v1/traces, because the exporter does not append anything then.
What Rius reads from your spans as they are:
- Model, tokens and messages.
gen_ai.request.model,gen_ai.usage.input_tokens,gen_ai.usage.output_tokensand the message attributes make a span a full generation. It gets cost computed by Rius and appears in model analytics. - Other conventions. OpenLLMetry and OpenInference attributes are normalized onto the
gen_ai.*keys when they arrive, so instrumentors that emit those conventions work without changes. - Nesting. Spans nested through normal OpenTelemetry parent context arrive as one trace. The name, duration and status of the root span are what run-level views show.
The hosts here are for the eu region, the only region the docs show. Your workspace’s region appears in the host’s subdomain, and the API key decides which workspace receives the traces.
Set it up
- Create an API key in the Rius console. Keys start with
ri_, and the key decides which workspace the traces land in. - Install
opentelemetry-sdkandopentelemetry-exporter-otlp-proto-http, the packages that provide the tracer provider and thehttp/protobufexporter. - Set the three exporter variables:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.eu.console.rius-glassflow.com"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your API key>"- Register the provider with an exporter that has no endpoint or headers set in code, so it reads those variables:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
# With no arguments, the exporter reads the OTEL_EXPORTER_OTLP_* variables
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(provider)- Raise the span attribute limit by setting
OTEL_SPAN_ATTRIBUTE_COUNT_LIMITto 4096. The OpenTelemetry default of 128 attributes is too low once a span carries messages or tool definitions as one attribute per field, and a span over the limit can arrive without its model or tokens. SetOTEL_SERVICE_NAMEtoo, so the agent has a name. - Run one traced LLM call, open Traces in the console, and check that the LLM span shows a model name, token counts and cost.
The other sender setups are compared on Trace LLM calls with OpenTelemetry, and the full language-neutral version of these steps is on Vanilla OpenTelemetry SDKs.
What you get
-
Traces with no re-instrumentation. Your existing spans, parents and exporter code stay as they are. Only the exporter configuration changes.
-
Cost per call. When a span carries the model and token counts, Rius prices it server-side. Costs are list-price estimates in US dollars from LiteLLM’s public model-price catalog, not billed amounts.
-
What you might still add. A hand-written LLM span needs these attributes to count as a full generation:
gen_ai.operation.namegen_ai.request.modelgen_ai.provider.name- the token counts
gen_ai.output.messages
Also useful:
- a single root span around each agent run
session.idanduser.idon every span, root included. Withoutsession.ida trace is its own session, and withoutuser.idit counts as anonymous. Prefer an opaque user id to an email.
-
A path to the SDK later. Code written against raw OpenTelemetry keeps working unchanged if you adopt the Rius SDK. The SDK adds message normalization, a raised attribute limit, export-time privacy controls, heartbeats and auto-instrumentation on top.
The span attribute reference lists every attribute Rius reads, and the Interoperability section covers OpenLLMetry, OpenInference and the Collector.
When something else fits
- If you have no tracing yet and use Python, the Rius SDK needs one
init()call and auto-instruments the LLM libraries you already use. - If you want content privacy controls applied at export, or heartbeats for the Agents page, the SDK provides them and plain OpenTelemetry does not.
- If you route spans through an OpenTelemetry Collector, use its
otlphttpexporter and nototlp, which speaks gRPC.