OpenTelemetry Java for Uptrace
This document explains how to configure the OpenTelemetry Java Agent to export spans, metrics, and logs to Uptrace using OTLP/gRPC.
OpenTelemetry Java Agent
The OpenTelemetry Java Agent provides automatic instrumentation and tracing capabilities for Java applications without requiring any code changes. It works by attaching to a Java application at runtime and intercepting method calls to collect telemetry data.
The agent simplifies the process of instrumenting your Java applications by eliminating the need to modify your application's source code.
Quickstart
Follow this guide to instrument your Java application and send telemetry data to Uptrace.
Step 0: Create Uptrace Project
Create an Uptrace project to obtain a DSN (connection string), for example: https://<secret>@api.uptrace.dev?grpc=4317
.
Step 1: Download Java Agent
Download the latest pre-compiled Java agent JAR:
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
Step 2: Configure Environment Variables
Configure the agent to export data to Uptrace using environment variables:
export OTEL_RESOURCE_ATTRIBUTES=service.name=myservice,service.version=1.0.0
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.uptrace.dev:4317
export OTEL_EXPORTER_OTLP_HEADERS="uptrace-dsn=<FIXME>"
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA
export OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
Step 3: Run Your Application
Enable the agent by providing the -javaagent
flag when starting your application:
java -javaagent:path/to/opentelemetry-javaagent.jar \
-jar myapp.jar
That's it! The agent supports a huge number of libraries and frameworks and most popular application servers.
Configuration
The agent can be configured using environment variables, system properties, or a configuration file.
Environment Variables
Use environment variables to configure OpenTelemetry:
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.uptrace.dev:4317
export OTEL_EXPORTER_OTLP_HEADERS="uptrace-dsn=<FIXME>"
export OTEL_RESOURCE_ATTRIBUTES=service.name=myservice,service.version=1.0.0
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA
export OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
System Properties
Instead of environment variables, you can use system properties:
java -javaagent:path/to/opentelemetry-javaagent.jar \
-jar myapp.jar \
-Dotel.exporter.otlp.endpoint=https://api.uptrace.dev:4317 \
-Dotel.exporter.otlp.headers=uptrace-dsn=<FIXME> \
-Dotel.resource.attributes=service.name=myservice,service.version=1.0.0 \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=otlp \
-Dotel.logs.exporter=otlp \
-Dotel.exporter.otlp.compression=gzip \
-Dotel.exporter.otlp.metrics.temporality.preference=DELTA \
-Dotel.exporter.otlp.metrics.default.histogram.aggregation=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
Configuration File
You can save system properties to a file, for example uptrace.properties
:
otel.exporter.otlp.endpoint=https://api.uptrace.dev:4317
otel.exporter.otlp.headers=uptrace-dsn=<FIXME>
otel.resource.attributes=service.name=myservice,service.version=1.0.0
otel.traces.exporter=otlp
otel.metrics.exporter=otlp
otel.logs.exporter=otlp
otel.exporter.otlp.compression=gzip
otel.exporter.otlp.metrics.temporality.preference=DELTA
otel.exporter.otlp.metrics.default.histogram.aggregation=BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
Pass the configuration file to the agent using the otel.javaagent.configuration-file
system property:
java -javaagent:path/to/opentelemetry-javaagent.jar \
-Dotel.javaagent.configuration-file=path/to/uptrace.properties \
-jar myapp.jar
Micrometer Metrics
Micrometer is a metrics collection library for Java applications that provides a simple way to instrument code with various metrics such as timers, gauges, counters, histograms, and distributions.
Popular frameworks like Spring Boot provide dependency management and auto-configuration for Micrometer out-of-the-box. For other frameworks, you need to enable Micrometer metrics first. For example, to monitor JVM metrics:
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.ProcessorMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
new ClassLoaderMetrics().bindTo(Metrics.globalRegistry);
new JvmMemoryMetrics().bindTo(Metrics.globalRegistry);
new JvmGcMetrics().bindTo(Metrics.globalRegistry);
new ProcessorMetrics().bindTo(Metrics.globalRegistry);
new JvmThreadMetrics().bindTo(Metrics.globalRegistry);
OpenTelemetry Bridge for Micrometer
The OpenTelemetry Java agent automatically detects if the instrumented application is using Micrometer and injects a special MeterRegistry implementation to collect Micrometer meters.
To export metrics with the Java agent, add a dependency on the micrometer-core
library:
Maven:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.10.5</version>
</dependency>
Gradle:
implementation("io.micrometer:micrometer-core:1.10.5")
Custom Metrics
To create custom metrics with Micrometer, use meter factory methods provided by the Metrics
class, or use meter builders and register them in the Metrics.globalRegistry
:
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
class MyClass {
private final Counter myCounter = Metrics.counter("my_custom_counter");
private final Timer myTimer = Timer.builder("my_custom_timer").register(Metrics.globalRegistry);
int foo() {
myCounter.increment();
return myTimer.recordCallable(this::fooImpl);
}
private int fooImpl() {
// Your business logic here
return 42;
}
}
Sampling
You can reduce the number of created (sampled) spans by configuring head-based sampling.
For example, to sample 20% of traces:
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.2
See the documentation for more details.
Disabling the Java Agent
To disable the agent entirely, pass -Dotel.javaagent.enabled=false
or use the OTEL_JAVAAGENT_ENABLED=false
environment variable.
You can also disable specific instrumentations by passing -Dotel.instrumentation.[name].enabled=false
or using the OTEL_INSTRUMENTATION_[NAME]_ENABLED=false
environment variable. See the documentation for the list of instrumentation names.
Troubleshooting
Common Issues
Agent not starting:
- Verify the path to the
opentelemetry-javaagent.jar
file is correct - Check that Java has read permissions for the JAR file
- Ensure you're using a supported Java version
No data in Uptrace:
- Verify your DSN is correctly configured in
OTEL_EXPORTER_OTLP_HEADERS
- Check that the endpoint URL is correct:
https://api.uptrace.dev:4317
- Ensure your application is generating spans (check application logs for errors)
Performance issues:
- Adjust sampling rate to reduce overhead:
OTEL_TRACES_SAMPLER_ARG=0.1
(10% sampling) - Disable unused instrumentations to reduce memory usage
What's next?
Check available OpenTelemetry Java agent configuration options