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.401or403: 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.