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 a query
  4. Production transport boundary
  5. Retry and critical-path policy
  6. Verify the integration
  7. Troubleshooting

Go SDK

Use telemetry-go for direct synchronous event and query calls from a Go service. The published client creates an HTTP request for each method call. It does not expose context, a custom http.Client, an SDK timeout, automatic retries, batching, or a flush queue.

Install and initialize

go get github.com/telemetry-sh/telemetry-go
import (
    "os"

    telemetry "github.com/telemetry-sh/telemetry-go"
)

telemetryClient := telemetry.NewTelemetry()
telemetryClient.Init(os.Getenv("TELEMETRY_API_KEY"))

Initialize one client during application startup. Use a write-scoped key for ingestion and a read-scoped key for query-only automation.

Send a structured event

event := map[string]interface{}{
    "event_id":      eventID,
    "route_template": "/api/projects/:id",
    "method":         "POST",
    "status_code":    201,
    "status":         "success",
    "latency_ms":     float64(time.Since(startedAt).Microseconds()) / 1000,
    "request_id":     requestID,
    "release":        os.Getenv("APP_RELEASE"),
}

response, err := telemetryClient.Log("api_request_completed", event)
if err != nil {
    log.Printf("telemetry delivery failed event_id=%s error_type=transport_error", eventID)
}
_ = response

Do not send raw request paths containing identifiers, headers, cookies, request bodies, credentials, or private customer content. Use a normalized route pattern and controlled error category.

The Go SDK accepts one map[string]interface{} per Log call. Use the HTTP Log API directly if an application-owned worker needs bulk ingestion.

Run a query

query := `
SELECT
  route_template,
  COUNT(*) AS requests
FROM api_request_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY route_template
ORDER BY requests DESC
`

result, err := telemetryClient.Query(query)
if err != nil {
    return fmt.Errorf("query telemetry: %w", err)
}

rows, _ := result["data"].([]interface{})
fmt.Printf("rows=%d\n", len(rows))

The response uses generic maps and slices. Check types, missing fields, API status, and empty results before using a value in automation. Use the asynchronous Query API for large JSON or Parquet exports.

Production transport boundary

The current SDK constructs http.Client{} without a timeout. A stalled network request can therefore outlive the latency budget of an HTTP handler or worker. When a bounded timeout, context cancellation, connection-pool configuration, bulk payload, or explicit status handling is required, wrap the Telemetry HTTP contract in the service's existing http.Client.

Keep the same event schema and authorization rules:

client := &http.Client{Timeout: 2 * time.Second}

Use that client to POST https://api.telemetry.sh/log with a JSON body containing table and data. Check the HTTP status before decoding the response.

Retry and critical-path policy

Retry only transient connection failures, 429, 502, 503, and 504. Apply exponential backoff with jitter, cap elapsed time, and reuse the same event_id. Do not retry an unchanged schema or request error.

For normal application analytics, do not replace a completed customer response because telemetry failed. For billing or approved audit events that require durability, persist an outbox record in the system that owns the business transaction and deliver it from a worker.

See event delivery and idempotency and batching and backpressure.

Verify the integration

Send synthetic success, failure, retry, and timeout events, then run:

SELECT timestamp_utc, event_id, route_template, status, latency_ms, error_type
FROM api_request_completed
ORDER BY timestamp_utc DESC
LIMIT 20;

Confirm the table name, field types, units, and absence of sensitive content. Test process shutdown and a stalled Telemetry request before attaching instrumentation to a high-traffic handler.

Troubleshooting

  • Initialization error: confirm the server-side key is non-empty before the first method call.
  • Request hangs: use the HTTP API through a client with a timeout and request context.
  • Non-success response appears as data: inspect the returned status field; the current SDK decodes the JSON body without enforcing HTTP success.
  • Schema rejection: keep a field's type stable and remove null or unsupported shapes.
  • Duplicate rows after retry: preserve event_id and audit with the duplicate event recipe.

Continue with Go HTTP server structured logging, the Log API, and rate limits and API errors.

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