Skip to main content

Instrument a Java app for traces

The AtherOps agent receives traces over OTLP -- it does not inject tracing into running JVM processes on its own. You attach the OpenTelemetry Java agent to your JVM at startup, and it auto-instruments common frameworks (Spring, Tomcat, gRPC, JDBC, and others) without code changes.

If you haven't read Metrics/logs vs APM traces yet, that page explains why detection of a Java process does not automatically produce traces.

Prerequisites

  • The AtherOps agent is installed and running on the host.
  • collection.traces.enabled: true is set in /etc/atherops/config.yaml (this is the default).
  • Java 8 or later.

Step 1: Download the OTel Java agent

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

Place the jar somewhere stable, for example /opt/opentelemetry-javaagent.jar.

Step 2: Attach the agent at JVM startup

Add -javaagent to your startup command:

java \
-javaagent:/opt/opentelemetry-javaagent.jar \
-Dotel.exporter.otlp.endpoint=http://localhost:4318 \
-Dotel.exporter.otlp.protocol=http/protobuf \
-Dotel.service.name=my-java-service \
-jar your-app.jar

Or set the equivalent environment variables instead of system properties:

export JAVA_TOOL_OPTIONS="-javaagent:/opt/opentelemetry-javaagent.jar"
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_SERVICE_NAME=my-java-service

JAVA_TOOL_OPTIONS is picked up by the JVM automatically, which is useful for containers and managed runtimes where you cannot edit the command line directly.

Step 3: Verify spans are reaching AtherOps

Generate some traffic, then query the traces API:

curl -s \
-H "Authorization: Bearer $ATHEROPS_JWT" \
"https://api.atherops.com/query/traces?service=my-java-service&limit=10"

A non-empty JSON array means spans are flowing. An empty array means nothing has arrived yet -- generate more traffic and check again (the default window is the last hour).

See Enable traces: verify spans reached AtherOps for details on the query parameters and how to obtain the bearer token.

Choosing the OTLP endpoint

Both gRPC (port 4317) and HTTP/protobuf (port 4318) work. HTTP is often easier in environments with firewalls or proxies. The examples above use HTTP; to switch to gRPC:

-Dotel.exporter.otlp.endpoint=http://localhost:4317
-Dotel.exporter.otlp.protocol=grpc

Troubleshooting

No spans appear after startup. Check the agent log for errors:

journalctl -u atherops-otel-agent --since "5 min ago" | grep -i error

A forward traces failed line means the agent is receiving spans but cannot reach the AtherOps backend. An absence of error lines while spans are missing usually means the JVM is not sending -- confirm JAVA_TOOL_OPTIONS is set in the correct environment and that the JAR path is correct.

javaagent causes a startup error or ClassNotFoundException. Ensure you are using the opentelemetry-javaagent.jar (the full agent JAR from the releases page), not the SDK JARs. The agent JAR is self-contained.

The JAR works locally but not in a container. Mount the JAR into the container and ensure the JAVA_TOOL_OPTIONS environment variable is set on the container, not just the host.

Further reading