/docs/opentelemetry-java
Spring Boot + JDBC + Kafka + JVM
free plan / 1 gb-mo
telemtra.io
// java instrumentation

OpenTelemetry Java:
instrument Spring Boot and JVM apps.

Attach the OpenTelemetry Java agent, set four environment variables, and stream traces, logs, and metrics from any Spring Boot, Micronaut, Quarkus, or plain JVM app into Telemtra over OTLP.

Why OpenTelemetry for Java

OpenTelemetry has the most mature Java ecosystem of any OTel implementation. The Java agent is a single JAR you attach with -javaagent: that instruments dozens of frameworks and libraries at class load: Spring Web, Spring WebFlux, Spring Data, JDBC, Hibernate, JDBI, Apache HttpClient, OkHttp, Jetty, Tomcat, gRPC, Kafka, RabbitMQ, Elasticsearch, AWS SDK, and more. You get traces, JVM metrics, and Log4j/Logback log correlation without changing application source.

Because OTLP is the same on every language, the Java services and Python workers and Go gateways all show up in one Service Map in Telemtra with shared trace context.

Use the Java agent (recommended)

Download the latest agent and attach it to the JVM:

curl -L -o opentelemetry-javaagent.jar \
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

java \
  -javaagent:opentelemetry-javaagent.jar \
  -Dotel.service.name=checkout-api \
  -Dotel.resource.attributes=deployment.environment=production \
  -Dotel.exporter.otlp.endpoint=https://ingest.telemtra.io \
  -Dotel.exporter.otlp.protocol=http/protobuf \
  -Dotel.exporter.otlp.headers=x-api-key=$TELEMTRA_API_KEY \
  -jar app.jar

The agent instruments HTTP servers, HTTP clients, JDBC, Kafka, gRPC, and dozens of others automatically. JVM metrics (heap, GC, threads, class loading) are also exported as OTLP without extra config.

Where this goes in your project

With the Java agent path, you do not modify source code or build files. The two changes are: the agent JAR available at runtime, and a JVM startup flag pointing at it.

my-service/
├── src/main/java/...           # your existing Spring Boot app (unchanged)
├── build.gradle / pom.xml      # unchanged
├── opentelemetry-javaagent.jar # NEW: drop into image or sidecar volume
├── Dockerfile                  # ENTRYPOINT adds -javaagent: and otel.* flags
└── deploy/env                  # TELEMTRA_API_KEY

1. Bake the agent into your container image (or mount it from a volume):

# Dockerfile
FROM eclipse-temurin:21-jre
RUN curl -L -o /opt/opentelemetry-javaagent.jar \
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
COPY build/libs/app.jar /opt/app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/opentelemetry-javaagent.jar"
ENV OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.telemtra.io
ENV OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
CMD ["java", "-jar", "/opt/app.jar"]

JAVA_TOOL_OPTIONS is picked up by the JVM automatically — you do not need to change application start scripts. The remaining OTel settings can be passed as env vars or -D flags:

OTEL_SERVICE_NAME=checkout-api
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=${TELEMTRA_API_KEY}
TELEMTRA_API_KEY=tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2. Restart the JVM. On the next boot the agent banner appears in the startup log and instrumentation begins. Nothing in build.gradle or application source changes for the agent path.

If you cannot use a Java agent (sealed runtime, framework conflict), the SDK path below adds a dependency and an autoconfigure call in main.

Or use the SDK directly

If you cannot attach an agent (sealed runtime, framework conflict), the autoconfigure module wires the SDK from environment variables:

dependencies {
  implementation 'io.opentelemetry:opentelemetry-api'
  implementation 'io.opentelemetry:opentelemetry-sdk'
  implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
  implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure'
}
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;

OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk
    .initialize()
    .getOpenTelemetrySdk();

Spring Boot

The agent instruments Spring MVC and WebFlux automatically. For Spring Boot 3, the opentelemetry-spring-boot-starter offers a Spring-idiomatic alternative:

implementation 'io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter'

Controller methods become spans, RestTemplate and WebClient calls produce client spans, and JDBC queries appear under the request that triggered them.

Micrometer bridge

If your team already uses Micrometer, the OTel Micrometer bridge forwards meters to OTLP without rewriting metric definitions:

implementation 'io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5'

This is the easiest path for migrating Spring Boot Actuator metrics from Prometheus scrape to OTLP push.

Logs via Logback and Log4j2

Add the OpenTelemetry appender for your logging framework. Logback example:

<configuration>
  <appender name="OpenTelemetry" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender" />
  <root level="INFO">
    <appender-ref ref="OpenTelemetry" />
  </root>
</configuration>

Log records flow through OTLP, are correlated with the active trace and span IDs, and become searchable in Telemtra alongside the trace itself.

Manual spans for business logic

import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.Span;

private final Tracer tracer = openTelemetry.getTracer("checkout-api");

public void submitOrder(String orderId, long totalCents) {
    Span span = tracer.spanBuilder("checkout.submit_order")
        .setAttribute("order.id", orderId)
        .setAttribute("order.total_cents", totalCents)
        .startSpan();
    try (var scope = span.makeCurrent()) {
        chargeCard(orderId, totalCents);
        writeLedger(orderId);
        sendReceipt(orderId);
    } catch (Exception e) {
        span.recordException(e);
        throw e;
    } finally {
        span.end();
    }
}

Metrics

Meter meter = openTelemetry.getMeter("checkout-api");
LongCounter ordersTotal = meter.counterBuilder("orders_total").build();
DoubleHistogram checkoutLatency = meter.histogramBuilder("checkout_latency_ms").build();

ordersTotal.add(1, Attributes.of(AttributeKey.stringKey("plan"), "team"));
checkoutLatency.record(348);

JVM metrics out of the box

The Java agent exports heap, non-heap, GC pause time, class count, and thread count as standard OTLP metrics. In Telemtra these can power a "JVM health" dashboard without any extra setup.

Troubleshooting

  • Agent silently does nothing. Confirm the -javaagent: path is correct and appears before -jar. Check the JVM logs at startup for "OpenTelemetry Javaagent" banner.
  • 403 from Telemtra. The header is x-api-key, lowercase. Pass it via otel.exporter.otlp.headers as x-api-key=YOUR_KEY.
  • Spans missing from a specific library. Some libraries are instrumented only with experimental features enabled — set OTEL_INSTRUMENTATION_<NAME>_ENABLED=true.
  • Application slow at startup. Class loading via the agent costs a few hundred ms but does not affect steady-state performance.

For OTLP transport details see What is OTLP?. To centralize batching with a Collector sidecar, follow the Collector quickstart. New to Telemtra? The quickstart covers the Java agent path in 60 seconds. Create a workspace to get an API key and see your first JVM span in under a minute.

OpenTelemetry Java FAQ

Does the OpenTelemetry Java agent require code changes?

No. The Java agent is a single JAR you attach to the JVM with -javaagent:. It instruments Spring, JDBC, Hibernate, JDBI, Apache HttpClient, OkHttp, gRPC, Kafka, RabbitMQ, Elasticsearch, AWS SDK, and dozens more at class-load time. No source code, build file, or dependency changes.

Does it work with Spring Boot, Spring WebFlux, and Quarkus?

Yes for Spring Boot and Spring WebFlux out of the box - the agent covers Spring Web, WebFlux, Spring Data, and the embedded Tomcat/Netty/Jetty servers. Quarkus has dedicated OpenTelemetry support via the quarkus-opentelemetry extension; use that instead of the agent on Quarkus.

Will the Java agent slow down my application?

Class loading via the agent costs a few hundred milliseconds at startup. Steady-state performance impact is negligible for HTTP, JDBC, and gRPC instrumentations because OpenTelemetry uses lock-free queues and batches exports. If you measure a problem, narrow instrumentation with OTEL_INSTRUMENTATION_<NAME>_ENABLED=false.

Do JVM metrics export automatically?

Yes. The Java agent exports heap, non-heap, GC pause time, class count, and thread count as standard OTLP metrics out of the box. In Telemtra these can power a JVM health dashboard without any extra configuration.

What if I cannot use a Java agent?

Use the SDK path: add io.opentelemetry:opentelemetry-sdk, opentelemetry-exporter-otlp, and opentelemetry-sdk-extension-autoconfigure to your build, then read OTEL_* environment variables in main. The SDK path requires explicit instrumentation per library.

Further reading