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. Create one shared client
  2. Send one structured event
  3. Run SQL
  4. Failure and retry policy
  5. Verify the integration

Java HTTP Integration

Telemetry does not publish a native Java SDK. Use the HTTP API through one application-owned java.net.http.HttpClient when a Java or JVM service needs structured event ingestion or SQL queries.

This boundary keeps connection reuse, timeouts, retries, serialization, and failure policy under the control of the service.

Create one shared client

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

HttpClient telemetryHttp = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(2))
    .build();

Create the client once during application startup. Use a server-side, write-scoped API key for ingestion and a separate read-scoped key for reports or query automation.

Send one structured event

Use the JSON library already approved by the application. This example assumes eventJson was serialized from an allowlisted object rather than assembled from a request body:

String eventJson = objectMapper.writeValueAsString(Map.of(
    "table", "api_request_completed",
    "data", Map.of(
        "event_id", eventId,
        "route_template", "/api/projects/:id",
        "method", "POST",
        "status_code", 201,
        "status", "success",
        "latency_ms", latencyMs,
        "request_id", requestId,
        "release", release
    )
));

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.telemetry.sh/log"))
    .timeout(Duration.ofSeconds(3))
    .header("Authorization", telemetryApiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(eventJson))
    .build();

HttpResponse<String> response = telemetryHttp.send(
    request,
    HttpResponse.BodyHandlers.ofString()
);

if (response.statusCode() < 200 || response.statusCode() >= 300) {
    recordDeliveryFailure(response.statusCode(), eventId);
}

Use route templates and controlled error categories. Do not serialize headers, cookies, credentials, request bodies, SQL parameters, stack traces, prompts, generated content, or unrestricted exception messages.

Run SQL

POST a JSON body containing query to https://api.telemetry.sh/query with a read-scoped key:

String queryJson = objectMapper.writeValueAsString(Map.of(
    "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
        """
));

HttpRequest queryRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.telemetry.sh/query"))
    .timeout(Duration.ofSeconds(15))
    .header("Authorization", telemetryReadApiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(queryJson))
    .build();

Check the HTTP status and the response status, data, and key_order fields. Treat an empty result as a valid state rather than a parsing failure.

Failure and retry policy

Retry only bounded transient failures such as connection errors, 429, 502, 503, and 504. Use exponential backoff with jitter, cap elapsed time, and preserve the same event_id across attempts. Do not retry unchanged 400, 401, or 403 responses.

For ordinary product analytics, a telemetry failure should not replace a completed customer response. If a billing or approved audit event must be durable, write an outbox record in the same transaction as the business state and deliver it from a worker.

Verify the integration

Send controlled success, failure, retry, and timeout fixtures, then inspect recent rows:

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 event grain, table name, field types, units, UTC time, and privacy boundary. Test a Telemetry timeout and process shutdown before putting delivery on a high-traffic path.

Continue with the Spring Boot integration, Log API, rate limits and errors, and event delivery and idempotency.

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