Skip to content

Instrument a Java App

The OpenTelemetry Java agent instruments a Java application at launch time, with no code change. It attaches to the JVM, traces the frameworks and libraries your application uses, and sends traces, metrics, and logs to KloudMate. You configure it with environment variables.

1. Download the agent JAR. It contains the agent and every automatic instrumentation:

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

Earlier versions are on the releases page.

2. Set the variables that attach the agent and send its data to KloudMate:

export JAVA_TOOL_OPTIONS="-javaagent:/path/to/opentelemetry-javaagent.jar"
export OTEL_SERVICE_NAME="my-java-app"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"

Replace /path/to with the folder you downloaded the JAR to, and my-java-app with the name you want the service to have in KloudMate.

3. Start your application as usual, from the same shell:

java -jar my-app.jar

You can also attach the agent on the command line instead of through JAVA_TOOL_OPTIONS: java -javaagent:/path/to/opentelemetry-javaagent.jar -jar my-app.jar.

4. Check that the agent loaded. The startup output shows lines from otel.javaagent, including the agent version. Send a few requests to your application, and the service appears in KloudMate within a minute.

The Java agent works the same way for an application that runs inside Tomcat, with no code change. The difference is where you attach it: Tomcat starts the JVM, so you add the agent to Tomcat’s startup options instead of to a java -jar command. The agent then traces every request the server handles. OpenTelemetry tests it on Tomcat 7.0 to 10.1 and TomEE 7.0 to 9.1.

1. Download the agent to a path that Tomcat can read, for example /opt/opentelemetry:

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

2. Add the agent and the KloudMate settings to Tomcat’s startup options. Where they go depends on how Tomcat was installed:

Create or edit <tomcat>/bin/setenv.sh. Tomcat reads it on every start.

CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/opentelemetry/opentelemetry-javaagent.jar"
export OTEL_SERVICE_NAME="my-tomcat-app"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"

Replace my-tomcat-app with the name you want the service to have in KloudMate.

3. Restart Tomcat. On Linux, for a downloaded install:

<tomcat>/bin/shutdown.sh
<tomcat>/bin/startup.sh

For a package install, restart the service instead, for example sudo systemctl restart tomcat.

4. Check that the agent loaded. Tomcat’s log (<tomcat>/logs/catalina.out on Linux) shows lines from otel.javaagent, including the agent version, when the server starts. Send a few requests to your application, and the service appears in KloudMate within a minute.

For a containerized application, add the agent to the image and set the service name and endpoint when the container starts, so the same image works in every environment.

Add the agent to your Dockerfile and attach it with JAVA_TOOL_OPTIONS, which every JVM reads at startup:

FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/my-app.jar app.jar
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar /otel/opentelemetry-javaagent.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/otel/opentelemetry-javaagent.jar"
ENTRYPOINT ["java", "-jar", "app.jar"]

Build the image, then set the service name and endpoint when you run it:

docker build -t my-java-app .
docker run --network host \
  -e OTEL_SERVICE_NAME=my-java-app \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
  my-java-app

Inside a container, localhost is the container itself. --network host puts the container on the host’s network, so localhost:4318 reaches the KloudMate agent on the host, and the application’s ports open directly on the host without -p. On Docker Desktop for Mac or Windows, use http://host.docker.internal:4318 as the endpoint instead.

With Docker Compose, set network_mode: host on the service and the same two variables under its environment: key.

If the KloudMate agent is installed on the host or in your Kubernetes cluster, it can attach the Java agent to your services for you. See Java auto-instrumentation with the KloudMate agent.

Every setting can be given in three ways. If the same setting is given more than once, the first one in this list wins:

  • A system property on the JVM command line, for example -Dotel.service.name=my-service.

  • An environment variable, for example OTEL_SERVICE_NAME=my-service. To get a variable’s name from a property name, uppercase it and replace every . and - with _.

  • A properties file, whose path you give in -Dotel.javaagent.configuration-file or OTEL_JAVAAGENT_CONFIGURATION_FILE. This keeps the settings out of the startup script:

    otel.service.name=my-tomcat-app
    otel.exporter.otlp.endpoint=http://localhost:4318

The agent sends traces, metrics, and logs over OTLP with http/protobuf by default, so the endpoint above is all it needs to reach the KloudMate agent. For every other option, see the OpenTelemetry agent configuration reference, and check which frameworks and libraries are traced on the supported libraries page.

### Name### Description
jvm_classes_loadedThe number of loaded classes
jvm_gc_collections_countThe total number of garbage collections that have occurred
jvm_gc_collections_elapsedThe approximate accumulated collection elapsed time
jvm_memory_heap_initThe initial amount of memory that the JVM requests from the operating system for the heap
jvm_memory_heap_maxThe maximum amount of memory can be used for the heap
jvm_memory_heap_usedThe current heap memory usage
jvm_memory_heap_committedThe amount of memory that is guaranteed to be available for the heap
jvm_memory_nonheap_initThe initial amount of memory that the JVM requests from the operating system for non-heap purposes
jvm_memory_nonheap_maxThe maximum amount of memory can be used for non-heap purposes
jvm_memory_nonheap_usedThe current non-heap memory usage
jvm_memory_nonheap_committedThe amount of memory that is guaranteed to be available for non-heap purposes
jvm_memory_pool_initThe initial amount of memory that the JVM requests from the operating system for the memory pool
jvm_memory_pool_maxThe maximum amount of memory can be used for the memory pool
jvm_memory_pool_usedThe current memory pool memory usage
jvm_memory_pool_committedThe amount of memory that is guaranteed to be available for the memory pool
jvm_threads_countThe current number of threads