Documentation Index
Fetch the complete documentation index at: https://mintlify.com/iii-hq/sdk/llms.txt
Use this file to discover all available pages before exploring further.
This API requires the otel feature flag. Add features = ["otel"] to your Cargo.toml:[dependencies]
iii-sdk = { version = "0.4.1", features = ["otel"] }
Overview
The III SDK includes comprehensive OpenTelemetry support for distributed tracing, metrics collection, and structured logging. When the otel feature is enabled, telemetry data is exported to the III Engine over a shared WebSocket connection.
Initialization
init_otel
Initialize OpenTelemetry with the given configuration.
pub async fn init_otel(config: OtelConfig)
Configuration for OpenTelemetry including service name, metrics settings, etc.
Example:
use iii_sdk::{III, OtelConfig, init_otel};
let iii = III::new("ws://localhost:49134");
let otel_config = OtelConfig {
enabled: Some(true),
service_name: Some("my-service".to_string()),
service_version: Some("1.0.0".to_string()),
service_namespace: Some("production".to_string()),
engine_ws_url: Some("ws://localhost:49134".to_string()),
metrics_enabled: Some(true),
metrics_export_interval_ms: Some(60_000),
logs_enabled: Some(true),
shutdown_timeout_ms: Some(10_000),
..Default::default()
};
iii.set_otel_config(otel_config);
iii.connect().await?; // Automatically initializes OTel
When using III::set_otel_config() and connect(), OpenTelemetry is automatically initialized. You only need to call init_otel() directly if you’re not using the III client.
shutdown_otel
Shutdown OpenTelemetry and flush all pending data.
pub async fn shutdown_otel()
Example:
use iii_sdk::shutdown_otel;
// At application shutdown
shutdown_otel().await;
Always call shutdown_otel() or iii.shutdown_async() before your application exits to ensure all telemetry data is flushed.
flush_otel
Flush all pending telemetry data without shutting down.
pub async fn flush_otel()
Example:
use iii_sdk::flush_otel;
// Periodically flush telemetry
flush_otel().await;
is_initialized
Check if OpenTelemetry has been initialized.
pub fn is_initialized() -> bool
Example:
use iii_sdk::is_initialized;
if is_initialized() {
println!("OpenTelemetry is active");
}
Configuration
OtelConfig
Configuration structure for OpenTelemetry.
pub struct OtelConfig {
pub enabled: Option<bool>,
pub service_name: Option<String>,
pub service_version: Option<String>,
pub service_namespace: Option<String>,
pub service_instance_id: Option<String>,
pub engine_ws_url: Option<String>,
pub metrics_enabled: Option<bool>,
pub metrics_export_interval_ms: Option<u64>,
pub logs_enabled: Option<bool>,
pub reconnection_config: Option<ReconnectionConfig>,
pub shutdown_timeout_ms: Option<u64>,
pub channel_capacity: Option<usize>,
pub fetch_instrumentation_enabled: Option<bool>,
}
Field Defaults:
enabled: true (can be overridden by OTEL_ENABLED env var)
service_name: "iii-rust-sdk" (can be overridden by OTEL_SERVICE_NAME env var)
service_version: SDK version from Cargo.toml
service_instance_id: Random UUID
engine_ws_url: III client address or ws://localhost:49134
metrics_enabled: true
metrics_export_interval_ms: 60000 (1 minute)
logs_enabled: true
shutdown_timeout_ms: 10000 (10 seconds)
channel_capacity: 10000
fetch_instrumentation_enabled: true
ReconnectionConfig
Configuration for WebSocket reconnection behavior.
pub struct ReconnectionConfig {
pub initial_delay_ms: u64,
pub max_delay_ms: u64,
pub backoff_multiplier: f64,
pub jitter_factor: f64,
pub max_retries: Option<u64>,
pub max_pending_messages: usize,
}
Defaults:
initial_delay_ms: 1000
max_delay_ms: 30000
backoff_multiplier: 2.0
jitter_factor: 0.3
max_retries: None (infinite)
max_pending_messages: 1000
Distributed Tracing
get_tracer
Get a tracer for creating spans manually.
pub fn get_tracer() -> opentelemetry::global::BoxedTracer
Example:
use iii_sdk::get_tracer;
use opentelemetry::trace::{Tracer, SpanKind};
let tracer = get_tracer();
let span = tracer
.span_builder("my_operation")
.with_kind(SpanKind::Internal)
.start(&tracer);
// Do work
span.end();
with_span
Execute a function within a traced span with automatic error handling.
pub async fn with_span<F, Fut, T>(
name: &str,
traceparent: Option<&str>,
kind: Option<SpanKind>,
f: F,
) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
W3C traceparent header to set parent context
Span kind (defaults to Internal)
Async function to execute within the span
Example:
use iii_sdk::{with_span, SpanKind};
let result = with_span(
"process_order",
None,
Some(SpanKind::Internal),
|| async {
// Your code here
Ok("processed")
}
).await?;
Automatic Trace Propagation
Trace context is automatically propagated across function calls:
use iii_sdk::{III, with_span, SpanKind};
use serde_json::json;
let iii = III::new("ws://localhost:49134");
iii.connect().await?;
// Parent span
let result = with_span(
"handle_request",
None,
Some(SpanKind::Server),
|| async {
// This call will be a child span
let user = iii.call("user.get", json!({ "id": "123" })).await?;
// This call will also be a child span
let order = iii.call("order.create", json!({ "user": user })).await?;
Ok(order)
}
).await?;
Trace Context Functions
current_trace_id
Get the current trace ID.
pub fn current_trace_id() -> Option<String>
current_span_id
Get the current span ID.
pub fn current_span_id() -> Option<String>
Example:
use iii_sdk::{current_trace_id, current_span_id};
if let Some(trace_id) = current_trace_id() {
println!("Trace ID: {}", trace_id);
}
if let Some(span_id) = current_span_id() {
println!("Span ID: {}", span_id);
}
inject_traceparent
Inject current trace context into a W3C traceparent header.
pub fn inject_traceparent() -> Option<String>
Extract trace context from a W3C traceparent header.
pub fn extract_traceparent(traceparent: &str) -> OtelContext
Example:
use iii_sdk::{inject_traceparent, extract_traceparent};
// Inject for outbound request
if let Some(traceparent) = inject_traceparent() {
// Add to HTTP headers
headers.insert("traceparent", traceparent);
}
// Extract from inbound request
let traceparent = headers.get("traceparent").unwrap();
let context = extract_traceparent(traceparent);
Baggage
Baggage allows you to propagate key-value pairs across service boundaries.
set_baggage_entry
Set a baggage entry.
pub fn set_baggage_entry(key: &str, value: &str) -> OtelContext
get_baggage_entry
Get a baggage entry.
pub fn get_baggage_entry(key: &str) -> Option<String>
get_all_baggage
Get all baggage entries.
pub fn get_all_baggage() -> HashMap<String, String>
Example:
use iii_sdk::{set_baggage_entry, get_baggage_entry, get_all_baggage};
// Set baggage
let cx = set_baggage_entry("user_id", "123");
let _guard = cx.attach();
// Get baggage
if let Some(user_id) = get_baggage_entry("user_id") {
println!("User ID: {}", user_id);
}
// Get all
let all = get_all_baggage();
for (key, value) in all {
println!("{}: {}", key, value);
}
Metrics
get_meter
Get a meter for creating metrics.
pub fn get_meter() -> opentelemetry::metrics::Meter
Example:
use iii_sdk::get_meter;
let meter = get_meter();
// Create a counter
let counter = meter.u64_counter("requests_total")
.with_description("Total number of requests")
.init();
counter.add(1, &[]);
// Create a histogram
let histogram = meter.f64_histogram("request_duration_seconds")
.with_description("Request duration in seconds")
.init();
let start = std::time::Instant::now();
// ... do work ...
let duration = start.elapsed().as_secs_f64();
histogram.record(duration, &[]);
Metric Types
OpenTelemetry provides several metric types:
Counter:
let counter = get_meter().u64_counter("operation_count").init();
counter.add(1, &[]);
Histogram:
let histogram = get_meter().f64_histogram("latency").init();
histogram.record(0.123, &[]);
Gauge (via UpDownCounter):
let gauge = get_meter().i64_up_down_counter("active_connections").init();
gauge.add(1, &[]); // connection opened
gauge.add(-1, &[]); // connection closed
HTTP Instrumentation
execute_traced_request
Execute an HTTP request with automatic tracing.
pub async fn execute_traced_request(
request: reqwest::Request,
) -> Result<reqwest::Response, reqwest::Error>
Example:
use iii_sdk::execute_traced_request;
let client = reqwest::Client::new();
let request = client
.get("https://api.example.com/users")
.build()?;
// Automatically creates a CLIENT span and injects trace context
let response = execute_traced_request(request).await?;
println!("Status: {}", response.status());
HTTP instrumentation automatically injects traceparent and baggage headers into outbound requests.
Logging
When the otel feature is enabled, the Logger automatically emits OpenTelemetry LogRecords:
use iii_sdk::{III, get_context};
use serde_json::json;
let iii = III::new("ws://localhost:49134");
iii.register_function("process", |input| async move {
let ctx = get_context();
// These logs are exported via OpenTelemetry
ctx.logger.info("Processing started", None);
ctx.logger.debug("Input data", Some(input.clone()));
// Logs include trace context automatically
ctx.logger.warn("Warning message", Some(json!({ "details": "..." })));
ctx.logger.error("Error occurred", None);
Ok(json!({ "status": "ok" }))
});
Log Levels:
logger.debug(message, data)
logger.info(message, data)
logger.warn(message, data)
logger.error(message, data)
Complete Example
use iii_sdk::{
III, OtelConfig, get_tracer, get_meter, with_span,
SpanKind, current_trace_id, set_baggage_entry,
};
use opentelemetry::trace::Tracer;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Configure OpenTelemetry
let otel_config = OtelConfig {
enabled: Some(true),
service_name: Some("order-service".to_string()),
service_version: Some("1.0.0".to_string()),
metrics_enabled: Some(true),
logs_enabled: Some(true),
..Default::default()
};
let iii = III::new("ws://localhost:49134");
iii.set_otel_config(otel_config);
iii.connect().await?;
// Set up metrics
let meter = get_meter();
let order_counter = meter.u64_counter("orders_created").init();
let latency_histogram = meter.f64_histogram("order_latency").init();
// Register function with tracing
iii.register_function("order.create", move |input| {
let order_counter = order_counter.clone();
let latency_histogram = latency_histogram.clone();
async move {
let start = std::time::Instant::now();
// Set baggage for this operation
let cx = set_baggage_entry("tenant_id", "tenant-123");
let _guard = cx.attach();
if let Some(trace_id) = current_trace_id() {
println!("Processing order in trace: {}", trace_id);
}
// Process order
let result = json!({ "order_id": "order-456" });
// Record metrics
order_counter.add(1, &[]);
latency_histogram.record(start.elapsed().as_secs_f64(), &[]);
Ok(result)
}
});
// Call function with tracing
let result = with_span(
"create_order_flow",
None,
Some(SpanKind::Server),
|| async {
iii.call("order.create", json!({
"items": ["item1", "item2"]
})).await
}
).await?;
println!("Order created: {}", result);
// Flush and shutdown
iii.shutdown_async().await;
Ok(())
}
Resource Attributes
The SDK automatically adds these resource attributes:
service.name: Service name from config or OTEL_SERVICE_NAME
service.version: Service version from config or SERVICE_VERSION
service.instance.id: Service instance ID (UUID)
service.namespace: Optional namespace from config
telemetry.sdk.name: "iii-rust-sdk"
telemetry.sdk.language: "rust"
telemetry.sdk.version: SDK version
See Also