Telemetry
Browse docs

Use this doc with your coding agent

Open a focused prompt pack for Claude Code, Codex, Cursor, or another coding agent, then adapt it to the workflow covered here.

On this page
  1. Install and initialize
  2. Send a structured event
  3. Run SQL
  4. Blocking and timeout behavior
  5. Retry and shutdown policy
  6. Verify the integration
  7. Troubleshooting

Rust SDK

The telemetry-sh crate provides a small blocking client for event ingestion and interactive queries. Each method constructs a blocking reqwest client and sends one HTTP request. The crate does not expose an asynchronous client, configurable timeout, retry policy, batch queue, or flush method.

Install and initialize

[dependencies]
telemetry-sh = "1.0.0"
serde_json = "1.0"
uuid = { version = "1", features = ["v4"] }
use std::env;
use telemetry_sh::Telemetry;

let mut telemetry = Telemetry::new();
telemetry.init(env::var("TELEMETRY_API_KEY")?);

Keep the key in server-side configuration. Use a write-scoped key for ingestion-only services and a read-scoped key for reports or query automation.

Send a structured event

use serde_json::json;
use uuid::Uuid;

let event_id = Uuid::new_v4().to_string();
let event = json!({
    "event_id": event_id,
    "job_name": "invoice_sync",
    "status": "success",
    "duration_ms": 912,
    "attempt": 1,
    "release": env::var("APP_RELEASE").ok(),
});

match telemetry.log("job_completed", &event) {
    Ok(response) => println!("telemetry response: {response}"),
    Err(error) => eprintln!(
        "telemetry delivery failed event_id={} error_type=transport_error: {}",
        event_id,
        error
    ),
}

Avoid credentials, headers, cookies, raw request bodies, prompts, exception text, and private customer content. Prefer controlled categories and stable internal identifiers.

The SDK accepts one serde_json::Value. An array value can represent a Log API bulk payload, but test the exact crate and API behavior before making batching part of a production delivery contract.

Run SQL

let query = r#"
    SELECT
      status,
      COUNT(*) AS jobs
    FROM job_completed
    WHERE timestamp_utc >= now() - INTERVAL '24 hours'
    GROUP BY status
    ORDER BY jobs DESC
"#;

let result = telemetry.query(query)?;
let rows = result
    .get("data")
    .and_then(|value| value.as_array())
    .cloned()
    .unwrap_or_default();

println!("query rows: {}", rows.len());

The result is dynamic JSON. Validate types, nulls, API status, and empty results before using values in automation. Use the asynchronous Query API directly for long-running JSON or Parquet exports.

Blocking and timeout behavior

Both crate methods use reqwest::blocking. Do not call them directly on an asynchronous executor thread or a latency-sensitive request path without isolating the blocking work.

The published crate does not expose its HTTP client or configure a timeout. If the service needs context cancellation, connection reuse, a fixed timeout, status-specific retries, or a durable queue, implement the documented HTTP request with an application-owned reqwest::Client instead.

Keep the transport policy bounded so a telemetry outage cannot exhaust worker threads.

Retry and shutdown policy

Retry only transient connection failures, 429, 502, 503, and 504. Use exponential backoff with jitter, cap total time, and preserve the same event_id. Do not retry an unchanged invalid request.

The SDK has no background queue to flush. A successful log return means the immediate request produced a decodable response; it is not a promise of exactly-once storage. Track required calls or persist durable events in an application-owned outbox before process shutdown.

For ordinary analytics, do not turn a completed customer action into a failure because telemetry is unavailable. Review event delivery and idempotency.

Verify the integration

Send known success and failure fixtures, then query:

SELECT timestamp_utc, event_id, job_name, status, duration_ms, error_type
FROM job_completed
ORDER BY timestamp_utc DESC
LIMIT 20;

Check table naming, field types, units, null behavior, duplicate event IDs, and sensitive-data boundaries. Exercise a connection timeout and graceful shutdown before relying on the event for an alert.

Troubleshooting

  • Missing-key error: initialize the client from a non-empty server-side environment value.
  • Runtime stalls: move blocking calls off async executor threads or use an application-owned async HTTP client.
  • Error response decodes as JSON: inspect the returned status and message; the crate does not call error_for_status.
  • Duplicate rows: preserve event_id across network attempts and monitor duplicate IDs.
  • Large export: use the HTTP async-query start, status, and download flow.

Continue with the Log API, ingestion troubleshooting, and production instrumentation checklist.

Related product capability

Capture stable event names, typed fields, and privacy-reviewed context.

Ownership and technical references

The Telemetry editorial team owns this explanation; the product team reviews behavior, examples, and boundaries.

Review the editorial standard