Java SDK
Full observability for JVM services — HTTP, databases, gRPC, messaging, and logging captured automatically via OpenTelemetry
Installation
Add the dependency to your pom.xml:
Or with Gradle:
Minimum Setup
Two fields are required: apiKey and serviceName. Everything else has defaults.
ObtraceClient implements AutoCloseable, so use try-with-resources to ensure the internal executor shuts down cleanly. The default config also registers a JVM shutdown hook that calls flush() before exit. Disable it with .registerShutdownHook(false) on the builder if you manage lifecycle yourself.
Built on OpenTelemetry
The Java SDK uses the OpenTelemetry Java SDK to export telemetry to the Obtrace ingest endpoint. For Spring Boot applications, the obtrace Spring Boot starter provides full auto-instrumentation of HTTP, databases, messaging, and gRPC with zero manual configuration.
What's Captured Automatically
After creating an ObtraceClient, the SDK configures OpenTelemetry and enables available instrumentations. You don't need to write any extra code for this:
| What | How | Needs code? |
|---|---|---|
| Logging | java.util.logging, Logback, and Log4j2 are captured and mapped to Obtrace levels | No |
| Inbound HTTP | Spring Boot requests are auto-instrumented via the OTel starter | No (Spring Boot) |
| Outbound HTTP | java.net.http.HttpClient via getHttpClient() | Use getHttpClient() |
| JDBC / Hibernate | Database queries instrumented with spans via OTel | No (Spring Boot) |
| gRPC | Client and server calls instrumented via OTel | No (Spring Boot) |
| Kafka / RabbitMQ | Message production and consumption instrumented | No (Spring Boot) |
| Redis | Lettuce and Jedis clients instrumented | No (Spring Boot) |
| Shutdown flush | A JVM shutdown hook flushes pending telemetry before exit (disable with .registerShutdownHook(false)) | No |
Instrumented HTTP Client
The SDK provides an instrumented java.net.http.HttpClient that automatically creates spans for outbound HTTP calls and injects trace propagation headers:
Each call through getHttpClient() emits a span with method, URL, status code, and duration. The traceparent header is injected automatically.
Optional: Custom Telemetry
The automatic log capture covers basic observability. For business-specific events, use the SDK methods directly.
Logging
Use client.log(level, message, ctx) to record events you need to search for later. Good candidates:
- Caught exceptions and error conditions
- Business events (order placed, payment failed, user signed up)
- Audit trail entries (permission changed, API key rotated)
- State transitions (circuit breaker opened, cache eviction)
The level parameter accepts: debug, info, warn, error, fatal. Messages are truncated at 32KB.
The ctx parameter is optional (pass null to skip). When provided, it attaches structured attributes to the log entry. Use attr() on the builder for custom key-value pairs, and the built-in fields (traceId, spanId, method, endpoint, statusCode) to correlate logs with traces.
Metrics
Use client.metric(name, value, unit, ctx) to record measurements you want to graph or alert on. Good candidates:
- Latency measurements (how long did this take?)
- Counters (how many orders per minute?)
- Gauges (current queue depth, active connections, heap usage)
- Business KPIs (revenue per checkout, items per cart)
The unit parameter follows OTLP conventions: "ms" for milliseconds, "By" for bytes, "1" for dimensionless values (counts, ratios), or a currency code.
Tracing / Spans
Use client.span(...) to track a unit of work and its duration. Returns a String[] of {traceId, spanId} so you can propagate context to downstream services. Good candidates:
- HTTP handler execution (request in, response out)
- Database queries
- External API calls
- Background job processing
- Any operation where you need to see where time was spent
Pass null for traceId and spanId to auto-generate them. Pass an existing traceId (from ids[0]) to group spans into the same trace. The statusCode uses OTLP conventions: 0 = unset, 1 = OK, 2 = error.
The 7-argument overload also accepts parentSpanId to build span hierarchies within a single service.
Propagating Trace Context
When using getHttpClient(), trace context is injected automatically. For other HTTP clients, inject manually:
Framework Integration
Spring Boot
For Spring Boot applications, the obtrace Spring Boot starter auto-configures OpenTelemetry with full instrumentation of HTTP requests, JDBC, Hibernate, gRPC, Kafka, RabbitMQ, and Redis. Register the client as a Spring bean and use SpringObtraceFilter to instrument request lifecycle:
Then call afterRequest from a servlet filter or HandlerInterceptor:
Your controllers can still call client.log(), client.metric(), and client.span() directly for business-specific telemetry. The interceptor handles the per-request baseline.
Configuration Reference
All config is set through ObtraceConfig.builder():
| Builder method | Type | Default | Description |
|---|---|---|---|
.apiKey() | String | Required. Your Obtrace API key. | |
.serviceName() | String | Required. Stable name for this service. | |
.serviceVersion() | String | "0.0.0" | Deployment version (git SHA, semver, date). |
.tenantId() | String | null | Scoped ingest identity. |
.projectId() | String | null | Scoped ingest identity. |
.appId() | String | null | Scoped ingest identity. |
.env() | String | null | Environment name (prod, staging, dev). |
.requestTimeoutMs() | int | 5000 | HTTP timeout per OTLP request in milliseconds. |
.maxQueueSize() | int | 1000 | Max queued telemetry items before oldest are dropped. |
.flushTimeoutMs() | int | 30000 | Max time allowed for a single flush cycle. |
.validateSemanticMetrics() | boolean | false | When true + debug, warns on non-canonical metric names. |
.debug() | boolean | false | Enables SDK diagnostic output to stderr. |
.registerShutdownHook() | boolean | true | Registers a JVM shutdown hook that flushes on exit. |
Validation Checklist
After integrating the SDK, verify these before shipping to production:
-
serviceName,env, andserviceVersionare set and survive restarts and deploys - At least one request path emits both a log and a span
-
ObtraceClientis closed on shutdown (try-with-resources, Spring@PreDestroy, or shutdown hook) - No
401or403errors appear during OTLP submission (check with.debug(true)) - Metrics use correct units (
ms,By,1) not free-form strings - Outbound HTTP calls use
getHttpClient()orinjectPropagationif the downstream service also reports to Obtrace - Spring interceptor is registered in
WebMvcConfigurer.addInterceptorsif using Spring
See also: Semantic Metrics