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. Configure and send an event
  2. Send a batch
  3. Run SQL
  4. Retry and failure policy
  5. Verify and troubleshoot

Ruby HTTP Integration

Telemetry's HTTP API works with Ruby's standard library. This keeps the dependency surface small while leaving timeout, retry, and durability policy under application control.

Configure and send an event

require "json"
require "net/http"
require "uri"

api_key = ENV.fetch("TELEMETRY_API_KEY")
uri = URI("https://api.telemetry.sh/log")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = api_key
request["Content-Type"] = "application/json"
request.body = {
  table: "api_request_completed",
  data: {
    event_id: "evt_request_101",
    route_template: "/api/projects/:id",
    method: "GET",
    status_code: 200,
    status: "success",
    latency_ms: 184
  }
}.to_json

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: true,
  open_timeout: 2,
  read_timeout: 10
) { |http| http.request(request) }

unless response.is_a?(Net::HTTPSuccess)
  raise "Telemetry log failed with HTTP #{response.code}"
end

Telemetry adds timestamp_utc. Keep the key server-side and do not send credentials, cookies, headers, request parameters, raw exception messages, or private customer content.

Send a batch

Set data to an array:

request.body = {
  table: "job_completed",
  data: [
    {
      event_id: "evt_job_101",
      job_name: "invoice_sync",
      status: "success",
      duration_ms: 912
    },
    {
      event_id: "evt_job_102",
      job_name: "invoice_sync",
      status: "failed",
      duration_ms: 2401,
      error_type: "provider_timeout"
    }
  ]
}.to_json

Keep a batch bounded and schema-compatible. An application-owned queue also needs a maximum depth, maximum age, overflow rule, retry budget, and shutdown deadline.

Run SQL

Use a read-scoped key:

uri = URI("https://api.telemetry.sh/query")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = api_key
request["Content-Type"] = "application/json"
request.body = {
  query: <<~SQL
    SELECT
      route_template,
      COUNT(*) AS requests,
      ROUND(AVG(latency_ms), 0) AS avg_latency_ms
    FROM api_request_completed
    WHERE timestamp_utc >= now() - INTERVAL '24 hours'
    GROUP BY route_template
    ORDER BY requests DESC;
  SQL
}.to_json

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: true,
  open_timeout: 2,
  read_timeout: 30
) { |http| http.request(request) }

raise "Telemetry query failed with HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)

result = JSON.parse(response.body)
Array(result["data"]).each do |row|
  # Validate expected keys and nulls before using the row.
end

Use the asynchronous Query API for large JSON or Parquet exports.

Retry and failure policy

Net::OpenTimeout means a connection could not be established. Net::ReadTimeout is ambiguous because the server may have accepted the request before the response was lost.

Retry only transient network failures, 429, 502, 503, and 504. Reuse the logical event's event_id, apply exponential backoff with jitter, and cap total elapsed time. Do not retry an unchanged invalid request.

For normal analytics, a telemetry outage should not replace a completed customer response. Persist billing or approved audit events in an application-owned durable outbox when loss is not acceptable.

Verify and troubleshoot

Send synthetic success and failure events, query the newest rows, and inspect GET /tables/<table>/schema.

  • KeyError: configure the API key in the server or worker environment.
  • 401 or 403: replace the key or correct its scope.
  • 400: inspect table naming, JSON shape, and field-type compatibility.
  • Timeout: apply the workflow's documented retry or fallback policy without printing the payload.
  • Process shutdown: direct HTTP calls have no background queue to flush; track required calls or persist events first.

See the Rails integration, Log API, event delivery guide, and ingestion troubleshooting.

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