# LevelOps Rust SDK
Ingest SLI events into LevelOps from any Rust application.
## Installation
Add to `Cargo.toml`:
```toml
[dependencies]
levelops-sdk = "0.1"
```
## Quickstart
```rust
use levelops_sdk::{Client, Config, Event};
use std::collections::HashMap;
#[tokio::main]
async fn main() {
let client = Client::new(Config {
api_key: "<tenant_key>".into(),
sli_id: "<uuid>".into(),
..Default::default()
}).unwrap();
let mut fields = HashMap::new();
fields.insert("result".into(), "ok".into());
fields.insert("latency_ms".into(), 120.into());
client.record(Event { fields, ..Default::default() }).await.unwrap();
client.flush().await.unwrap();
}
```
## Usage
### Direct record
```rust
// Auto-generated event_id
client.record(Event {
fields: [("result".into(), "ok".into()), ("latency_ms".into(), 120.into())].into(),
dimensions: [("service".into(), "api".into())].into(),
..Default::default()
}).await?;
// Explicit event_id for idempotent retries
client.record(Event {
event_id: Some("my-trace-id".into()),
fields: [("result".into(), "ok".into())].into(),
..Default::default()
}).await?;
```
### Measure (async closure)
```rust
// Auto-generated event_id
ctx.set_result("ok");
Ok(())
}, MeasureOpts::new([("service", "api")])).await?;
// Explicit event_id
Ok(())
}, MeasureOpts::new([("service", "api")]).event_id("my-trace-id")).await?;
```
## Configuration
| `api_key` | — | Tenant API key (required) |
| `sli_id` | — | Target SLI UUID (required) |
| `base_url` | `https://api.levelops.io` | API base URL |
| `batch_size` | `100` | Flush after N events |
| `flush_interval` | `1s` | Flush every N duration |
## Behaviour
- `event_id` auto-generated (`Uuid::new_v4()`) per `record()` and per `measure()` closure exit. Override via `event_id`.
- `timestamp` auto-set to UTC now if not provided.
- Thread-safe buffer (`Mutex`) with background `tokio::spawn` flush task.
- Retries on HTTP 429 respecting `Retry-After` header (max 3 attempts, exponential backoff).
- Async-first API (`tokio`).