Skip to Content
SDKRust SDK

Rust SDK

Track AI events and traces in your Rust app.

Installation

Add the crate to your Cargo.toml:

[dependencies] introspection-sdk = "0.1" tokio = { version = "1", features = ["full"] }

Optional features:

[dependencies] introspection-sdk = { version = "0.1", features = ["openai"] }

Configuration

The client reads INTROSPECTION_TOKEN from the environment by default. You can also pass config explicitly:

use introspection_sdk::{IntrospectionClient, ClientConfig, AdvancedOptions}; // From environment let client = IntrospectionClient::new( ClientConfig::from_env().unwrap() ).unwrap(); // Explicit config let client = IntrospectionClient::new( ClientConfig::builder() .token("intro_xxx") .service_name("my-app") .advanced(AdvancedOptions { base_url: Some("https://otel.introspection.dev".to_string()), flush_interval_ms: Some(5000), max_batch_size: Some(100), ..Default::default() }) .build() .unwrap() ).unwrap();
OptionDefaultDescription
tokenINTROSPECTION_TOKEN env varAPI token
service_nameINTROSPECTION_SERVICE_NAME or "introspection-client"Service name for trace attribution
base_urlINTROSPECTION_BASE_URL or "https://otel.introspection.dev"API endpoint
flush_interval_ms5000How often buffered events are sent (ms)
max_batch_size100Max events per batch

Quick Start

Track an event, identify a user, and send feedback:

use introspection_sdk::{IntrospectionClient, ClientConfig, FeedbackOptions}; let client = IntrospectionClient::new( ClientConfig::from_env().unwrap() ).unwrap(); // Track an event client.track("query_submitted", None); // Set user and conversation context, then send feedback { let _user = client.set_user_id("user_123"); let _conv = client.set_conversation_id("conv_456"); client.feedback( "thumbs_up", FeedbackOptions::new() .with_comments("Great response!") .with_previous_response_id("msg_123"), ); } // Context automatically cleared on drop client.shutdown().unwrap();

Context guards (set_user_id, set_conversation_id) use Rust’s drop semantics. The context is cleared when the guard goes out of scope.

Identifying Users

let _user = client.set_user_id("user_123"); client.identify("user_123", Some(traits));

Tracking Events

client.track("query_submitted", Some(properties));

Feedback

client.feedback( "thumbs_down", FeedbackOptions::new().with_comments("Answer was off-topic"), );

Observation API

Use the Observation API when you want explicit control over span boundaries, generation metadata, and nested pipeline structure:

use introspection_sdk::{ GenerationUpdate, InputMessage, Observation, ObservationConfig, OutputMessage, }; let mut obs = Observation::start( &tracer, ObservationConfig::generation("chat", "gpt-4o-mini") .with_input(vec![InputMessage::user("Hello!")]), ); obs.update_generation( GenerationUpdate::new() .with_response_model("gpt-4o-mini") .with_response_id("chatcmpl-abc123") .with_output(vec![OutputMessage::assistant("Hello!")]) .with_usage(12, 8), ); obs.set_ok();

You can represent non-LLM steps explicitly:

let _pipeline = Observation::start(&tracer, ObservationConfig::span("rag-pipeline")); let _retrieval = Observation::start(&tracer, ObservationConfig::span("retrieval"));

Observations are automatically ended when dropped. Nest them using Rust’s scoping rules for clean pipeline traces.

OpenTelemetry

Use IntrospectionSpanProcessor with an OpenTelemetry provider:

use introspection_sdk::{IntrospectionSpanProcessor, SpanProcessorConfig}; use opentelemetry_sdk::trace::SdkTracerProvider; let processor = IntrospectionSpanProcessor::new( SpanProcessorConfig::with_token("your-token") ).unwrap(); let provider = SdkTracerProvider::builder() .with_span_processor(processor) .build();

If you already export traces to another backend, you can add IntrospectionSpanProcessor as an additional processor alongside your existing one. See Dual Export for details.

OpenAI Helpers

With the openai feature enabled, the SDK provides wrappers around async-openai calls:

use introspection_sdk::openai::traced_chat_completion; let response = traced_chat_completion(&tracer, &client, request).await?;

Shutdown

Call shutdown() before your process exits to flush any buffered events:

client.shutdown().unwrap();

For the span processor, call shutdown() on the processor or the tracer provider.

Error Handling

The SDK is designed to never panic in your application’s hot path. Events are buffered and sent asynchronously. Constructor methods return Result so you can handle initialization errors explicitly.

Last updated on