SDK
Rust SDK
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();| Option | Default | Description |
|---|---|---|
token | INTROSPECTION_TOKEN env var | API token |
service_name | INTROSPECTION_SERVICE_NAME or "introspection-client" | Service name for trace attribution |
base_url | INTROSPECTION_BASE_URL or "https://otel.introspection.dev" | API endpoint |
flush_interval_ms | 5000 | How often buffered events are sent (ms) |
max_batch_size | 100 | Max 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.