Skip to Content
ContributeTracing SystemOverview

Tracing System

Technical documentation for the Rhesis tracing system architecture and implementation.

For SDK Users: See the Tracing documentation for usage guides. This section covers the internal architecture and design for developers and contributors.

Overview

The tracing system captures OpenTelemetry-compliant traces from SDK-instrumented applications. It supports two operating modes:

  • Test Mode: Traces linked to test runs, test cases, and test results
  • Production Mode: Traces from live application monitoring

High-Level Architecture

Key Technologies

ComponentTechnologyPurpose
SDK TracerOpenTelemetry PythonSpan creation with AI semantic conventions
Batch ProcessorOTEL BatchSpanProcessorBatches spans, exports every 5 seconds
TransportOTLP/HTTPChunked (100 spans/request), retried with backoff, to /telemetry/traces
StoragePostgreSQL + JSONBFlexible span storage, GIN-indexed attributes
Post-processingCeleryTest-result linking, cost/anomaly enrichment, metric evaluation
LinkingService layerHybrid strategy for test-context linking

Communication Channels

The SDK uses two independent channels:

ChannelProtocolPurposeUsed By
TracingHTTP POSTExport OpenTelemetry spans@observe, @endpoint
TestingWebSocketRemote test invocation@endpoint only

Design Principles

  1. OpenTelemetry Standard - Industry-standard OTLP protocol for interoperability
  2. Hybrid Linking - Two strategic linking points to handle race conditions
  3. Idempotent Operations - Safe to call linking multiple times
  4. Cache Enrichment - Enrichment is skipped when every span in a trace is already processed
  5. Async Post-Processing - Ingestion never blocks on linking, enrichment, or metric evaluation
  6. Fire-and-Forget Dispatch - If the Celery broker is unreachable at dispatch time, ingestion still succeeds; post-processing for that batch is skipped and logged as a warning

Performance Characteristics

OperationTimingNotes
Span creation (SDK)~0.1msPer span, negligible overhead
BatchProcessor delay5000msFixed by OpenTelemetry design
Span export (OTLP)~10msNetwork call
Backend ingestion~10-20msSpans stored before async dispatch
Linking + enrichment~50-100msBackground (Celery, post_ingest_link)
Trace query~10msCached enrichment
End-to-end~5 secondsTest start to queryable trace

Key Files

SDK

FilePurpose
sdk/src/rhesis/sdk/telemetry/tracer.pyTracer class — creates spans via the shared OTEL provider
packages/rhesis/src/rhesis/telemetry/provider.pyTracerProvider + BatchSpanProcessor setup
packages/rhesis/src/rhesis/telemetry/exporter.pyRhesisOTLPExporter — chunked, retrying OTLP HTTP export
packages/rhesis/src/rhesis/telemetry/schemas.pyCanonical span schema, span-name validation
sdk/src/rhesis/sdk/telemetry/attributes.pyAI semantic convention attribute constants
sdk/src/rhesis/sdk/decorators/observe.py@observe decorator
sdk/src/rhesis/sdk/decorators/endpoint.py@endpoint decorator

Backend

FilePurpose
apps/backend/.../routers/telemetry.pyIngestion (POST /telemetry/traces) and query endpoints
apps/backend/.../tasks/telemetry/post_ingest.pypost_ingest_link — linking + enrichment dispatch
apps/backend/.../services/telemetry/linking_service.pyTraceLinkingService
apps/backend/.../services/telemetry/enrichment/Cost/anomaly enrichment (core.py, processor.py)
apps/backend/.../models/trace.pyTrace SQLAlchemy model
apps/backend/.../crud.pycreate_trace_spans(), update_traces_with_test_result_id(), get_trace_by_id(), mark_trace_processed()

Next Steps