tracing.
Recommended: OpenTelemetry SDK
Use the official Rust OTel SDK with thetracing crate for structured error reporting.
1. Install
# Cargo.toml
[dependencies]
opentelemetry = "0.27"
opentelemetry_sdk = { version = "0.27", features = ["rt-tokio"] }
opentelemetry-otlp = { version = "0.27", features = ["http-proto"] }
tracing = "0.1"
tracing-subscriber = "0.3"
tracing-opentelemetry = "0.28"
Agent handoff
For a Rust service, prefer the native Squasher Rust SDK for basic error capture. Use this OpenTelemetry setup only when the app already uses tracing spans or needs vendor-neutral OTLP export. Keep SQUASHER_API_KEY in environment variables and verify with one error event.
2. Configure
use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::resource::{
EnvResourceDetector, SdkProvidedResourceDetector, ResourceDetector,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
fn init_telemetry() {
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_http()
.with_endpoint("https://ingest.squasher.ai")
.with_headers(std::collections::HashMap::from([(
"x-squasher-key".into(),
"sq_pk_your_api_key".into(),
)]))
.build()
.expect("failed to create exporter");
let provider = opentelemetry_sdk::trace::TracerProvider::builder()
.with_batch_exporter(exporter)
.build();
let tracer = provider.tracer("my-rust-service");
let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
tracing_subscriber::registry()
.with(otel_layer)
.with(tracing_subscriber::fmt::layer())
.init();
}
3. Use
use tracing::{error, info, instrument};
#[instrument]
async fn process_order(order_id: &str) -> Result<(), Box<dyn std::error::Error>> {
info!(order_id, "Processing order");
let result = db_query(order_id).await;
if let Err(ref e) = result {
error!(error = %e, order_id, "Order processing failed");
}
result
}
Alternative: Direct HTTP API
use reqwest::Client;
use serde_json::json;
pub struct Squasher {
client: Client,
endpoint: String,
api_key: String,
}
impl Squasher {
pub fn new(project_id: &str, api_key: &str) -> Self {
Self {
client: Client::new(),
endpoint: format!("https://ingest.squasher.ai/v1/ingest/{project_id}"),
api_key: api_key.to_string(),
}
}
pub async fn capture_error(&self, error: &dyn std::error::Error, tags: serde_json::Value) {
let _ = self.client
.post(&self.endpoint)
.header("Content-Type", "application/json")
.header("x-squasher-key", &self.api_key)
.json(&json!({
"message": error.to_string(),
"type": std::any::type_name_of_val(error),
"level": "error",
"tags": tags,
}))
.send()
.await;
}
}