Skip to Content
Rius

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_tokens and 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

  1. Create an API key in the Rius console. Keys start with ri_, and the key decides which workspace the traces land in.
  2. Install opentelemetry-sdk and opentelemetry-exporter-otlp-proto-http, the packages that provide the tracer provider and the http/protobuf exporter.
  3. 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>"
  1. 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)
  1. Raise the span attribute limit by setting OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT to 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. Set OTEL_SERVICE_NAME too, so the agent has a name.
  2. 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.name
    • gen_ai.request.model
    • gen_ai.provider.name
    • the token counts
    • gen_ai.output.messages

    Also useful:

    • a single root span around each agent run
    • session.id and user.id on every span, root included. Without session.id a trace is its own session, and without user.id it 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 otlphttp exporter and not otlp, which speaks gRPC.

Still stuck? Get help

Last updated on