How do I attach an end user to a trace with OpenLLMetry?
Rius reads the end user from the user.id attribute, so you attach a user to an OpenLLMetry trace by setting user.id on the spans of that request. Rius’s mapping of OpenLLMetry attributes does not produce a user id, so spans arrive anonymous until you set one. Once user.id is on the spans, each user shows with their traces, failures, cost and time to first token.
How it works
Rius groups traces by user from a span attribute, not from a setting on the exporter.
user.idis the attribute Rius reads. If it is absent, Rius readsenduser.id, thenenduser.pseudo.id. A span with none of them counts as anonymous.- Rius maps OpenLLMetry’s attributes onto its own keys at ingest: the span taxonomy from
traceloop.span.kind, model, token usage, messages, and input and output. A user id is not in that list, so OpenLLMetry’s instrumentation does not give you one by default. - Rius reads the user per span, and the trace list shows each trace under the user of its root span, so the root span must carry
user.id. Set it on the other spans of the request too; a span without it is anonymous even if its parent has one. - There is no environment variable for the user, by design. The value changes per request, so it belongs on the spans of that request.
- Rius computes cost from the model and token counts on each span. You send no cost attribute for a user. Rius attributes the cost of the spans that carry that user.
The Span attribute reference lists the user and session attributes Rius reads, and the OpenLLMetry page covers what Rius maps from OpenLLMetry.
Set it up
-
Point OpenLLMetry at Rius if you have not already. This is the only exporter step, and 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>"}, ) -
Choose the value for
user.id. Use an opaque identifier from your own system, such as an internal account id, rather than an email address. Rius stores the value as you send it. -
In your request handler, add
user.idto every span that request produces, from the outermost span down to the model calls. Rius needs the key to be exactlyuser.id. The value is your own, as in this span attribute:user.id = "u_8123"Set it with the OpenTelemetry API inside your outermost
@workflowor@agent, the function that starts the trace:from opentelemetry import trace trace.get_current_span().set_attribute("user.id", user_id)Do not use
Traceloop.set_association_properties({"user_id": ...})for this. Association properties arrive astraceloop.association.properties.user_id, which you can inspect but which Rius does not read as the user. -
Run one traced request for a known user. Open the trace in the console and check the spans carry
user.id, then check that user appears in the list of users. -
If the user still shows as anonymous, look for a span in the trace that was created outside the code where you set the attribute. Rius reads the attribute span by span, so each span needs it.
For how the exporter and the other senders connect, see Trace LLM calls with OpenTelemetry.
What you get
- Each end user your agent served, listed with their traces, failures, cost and time to first token.
- A clear split between identified and anonymous traffic, because spans with no user id count as anonymous.
- User attribution that works across OpenLLMetry releases, because Rius maps the older and current OpenLLMetry attribute spellings onto its own keys for model, usage and messages. The user id is yours to set under the same key either way.
- Cost per user that stays a list-price estimate in US dollars, computed by Rius from the models and token counts on the spans.
When something else fits
- If you use the Rius SDK instead of OpenLLMetry, its user scope (
rius.userin Python,withUserin TypeScript) stampsuser.idon the spans in scope for you. - If you also want to group a conversation or an agent run, set
session.idon the spans in the same way. The attribute reference describes both keys.