Java Instrumentation¶
Subscription required
This section describes functionality which requires an active IAPM subscription. Start your subscription by choosing the plan right for you.
Instrument your Java applications with OpenTelemetry to send traces, metrics, and logs to IAPM. This guide covers the Java agent for auto-instrumentation, Spring Boot setup, and manual SDK usage.
Approach 1: Java Agent (Recommended)¶
The OpenTelemetry Java agent provides automatic instrumentation for most popular frameworks and libraries with zero code changes.
Download the Agent¶
curl -L -o opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
Run with the Agent¶
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.exporter.otlp.endpoint=https://otlp.iapm.app \
-Dotel.exporter.otlp.headers=API-Key=YOUR-API-KEY \
-Dotel.service.name=my-java-app \
-jar your-application.jar
The agent automatically instruments:
- Spring Web MVC, WebFlux
- JAX-RS
- Servlet API
- JDBC, Hibernate
- Kafka, RabbitMQ
- gRPC
- HTTP clients (Apache HttpClient, OkHttp, java.net.HttpClient)
- And many more
Approach 2: Spring Boot Starter¶
For Spring Boot applications, you can use the OpenTelemetry Spring Boot starter instead of the Java agent:
Maven¶
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom</artifactId>
<version>2.12.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>
</dependencies>
Gradle¶
implementation platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.12.0")
implementation "io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter"
Spring Boot Configuration¶
Configure in application.yml:
otel:
exporter:
otlp:
endpoint: https://otlp.iapm.app
headers:
API-Key: YOUR-API-KEY
service:
name: my-spring-boot-app
Or in application.properties:
otel.exporter.otlp.endpoint=https://otlp.iapm.app
otel.exporter.otlp.headers.API-Key=YOUR-API-KEY
otel.service.name=my-spring-boot-app
Approach 3: Manual Instrumentation with SDK¶
For full control, configure the OpenTelemetry SDK programmatically.
Maven Dependencies¶
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.46.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
</dependency>
</dependencies>
Gradle Dependencies¶
implementation platform("io.opentelemetry:opentelemetry-bom:1.46.0")
implementation "io.opentelemetry:opentelemetry-api"
implementation "io.opentelemetry:opentelemetry-sdk"
implementation "io.opentelemetry:opentelemetry-exporter-otlp"
implementation "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure"
SDK Initialization¶
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.semconv.ResourceAttributes;
public class OtelConfig {
public static OpenTelemetry initialize() {
Resource resource = Resource.getDefault()
.merge(Resource.builder()
.put(ResourceAttributes.SERVICE_NAME, "my-java-app")
.put(ResourceAttributes.SERVICE_VERSION, "1.0.0")
.build());
// Trace exporter
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("https://otlp.iapm.app")
.addHeader("API-Key", "YOUR-API-KEY")
.build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.setResource(resource)
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.build();
// Metric exporter
OtlpGrpcMetricExporter metricExporter = OtlpGrpcMetricExporter.builder()
.setEndpoint("https://otlp.iapm.app")
.addHeader("API-Key", "YOUR-API-KEY")
.build();
SdkMeterProvider meterProvider = SdkMeterProvider.builder()
.setResource(resource)
.registerMetricReader(PeriodicMetricReader.builder(metricExporter).build())
.build();
OpenTelemetrySdk sdk = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.setMeterProvider(meterProvider)
.buildAndRegisterGlobal();
// Shut down providers on JVM exit
Runtime.getRuntime().addShutdownHook(new Thread(sdk::close));
return sdk;
}
}
Creating Custom Spans¶
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
public class OrderService {
private static final Tracer tracer =
GlobalOpenTelemetry.getTracer("com.myapp.orders");
public Order processOrder(int orderId) {
Span span = tracer.spanBuilder("processOrder")
.setAttribute("order.id", orderId)
.startSpan();
try (Scope scope = span.makeCurrent()) {
Order order = repository.findById(orderId);
span.setAttribute("order.total", order.getTotal());
paymentService.charge(order);
span.addEvent("payment.completed");
fulfillmentService.fulfill(order);
span.setStatus(StatusCode.OK);
return order;
} catch (Exception e) {
span.setStatus(StatusCode.ERROR, e.getMessage());
span.recordException(e);
throw e;
} finally {
span.end();
}
}
}
Environment Variable Configuration¶
The Java agent and SDK autoconfigure module read these variables:
| Variable | Value | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | https://otlp.iapm.app | OTLP collector endpoint |
OTEL_EXPORTER_OTLP_HEADERS | API-Key=YOUR-API-KEY | Authentication header |
OTEL_SERVICE_NAME | your-service-name | Service name shown in IAPM |
OTEL_EXPORTER_OTLP_PROTOCOL | grpc | Protocol (grpc or http/protobuf) |
OTEL_TRACES_EXPORTER | otlp | Trace exporter type |
OTEL_METRICS_EXPORTER | otlp | Metrics exporter type |
OTEL_LOGS_EXPORTER | otlp | Logs exporter type |
You can also use JVM system properties (prefix with -D and replace underscores with dots in lowercase):
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.exporter.otlp.endpoint=https://otlp.iapm.app \
-Dotel.exporter.otlp.headers=API-Key=YOUR-API-KEY \
-Dotel.service.name=my-java-app \
-jar your-app.jar
Verify It's Working¶
- Run your instrumented application
- Send a few HTTP requests to generate traces
- Open portal.iapm.app and select your Grid
- Click Enter - you should see your service and traces within a few minutes
Quick verification with logging exporter
Add -Dotel.traces.exporter=otlp,logging to see spans in your console output during development.
Troubleshooting¶
Java agent not loading¶
- Ensure
-javaagent:appears before-jarin the command line. - Verify the
opentelemetry-javaagent.jarfile exists at the specified path. - Check that the JAR file is not corrupted (re-download it).
No data appearing in IAPM¶
- Verify the API key by copying a fresh one from portal.iapm.app under Administration > Grids > Instrument.
- Check network connectivity:
curl -v https://otlp.iapm.app. - Look for OpenTelemetry warnings in your application logs.
Spring Boot starter conflicts¶
- Ensure you are not using both the Java agent and the Spring Boot starter at the same time - pick one approach.
- Check for dependency version conflicts using
mvn dependency:treeorgradle dependencies.
High overhead with the Java agent¶
- Use the
otel.instrumentation.[name].enabled=falseproperty to disable instrumentation for libraries you do not need. - Example:
-Dotel.instrumentation.jdbc.enabled=false