Configure Telemetry: Raw OpenTelemetry
For cases where you can’t decorate functions (third-party code, dynamic dispatch) or need fine-grained control over span attributes and events, use the OpenTelemetry tracer directly with Rhesis’s semantic constants.
What You’ll Achieve
- Full control over span names, attributes, and events
- An understanding of the export pipeline so you can wire it manually if needed
- Correctly-shaped spans that pass Rhesis’s span-name validation
Prerequisites
RhesisClientinitialized: see Configuring Telemetry
If you initialize RhesisClient(), the export pipeline below is already wired up for you: skip to Creating Spans Manually. The manual pipeline setup is only needed if you’re bypassing RhesisClient() entirely.
The Export Pipeline
RhesisClient() calls get_tracer_provider(), which creates a singleton TracerProvider with a BatchSpanProcessor wrapping a RhesisOTLPExporter, and registers it as the global OpenTelemetry provider. After that, any trace.get_tracer(...) call returns a tracer that feeds into this pipeline:
Setting up the pipeline manually
If you skip RhesisClient() and wire things yourself:
RhesisOTLPExporter handles authentication, retry with exponential backoff jitter (on 408/429/5xx and connection errors), chunking for batches over max_chunk_size (default 100), conversation context propagation, and span-name validation.
At the end of your process, flush pending spans:
The Semantic Layer
All spans must be named ai.<domain>.<action> or function.<name>. Names like chain, workflow, or pipeline are rejected by the backend with HTTP 422.
See the Semantic Conventions Reference for the complete list.
Creating Spans Manually
Building attribute dicts by hand? create_llm_attributes(...) and create_tool_attributes(...) in rhesis.sdk.telemetry save you from remembering every constant name.
Tracking Multi-Turn Conversations
At the lowest level, you build the synthetic parent context yourself so subsequent turns share a trace_id:
For the full attribute reference (rhesis.conversation.*) and the shared-vs-separate trace_id tradeoff, see Conversation Tracing.
You have full control over span creation. For most applications, Decorators cover the same ground with far less code: reach for raw OpenTelemetry only when you genuinely need it.
Related:
- Custom Spans Reference - every attribute and event in depth
- Semantic Conventions Reference - the complete
ai.*schema - Configuring Telemetry - back to the mode overview