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: trueis 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
- OpenTelemetry Java auto-instrumentation -- the canonical upstream reference, including the full list of instrumented frameworks and all configuration options.
- Metrics/logs vs APM traces -- why the agent requires app-side instrumentation for traces.
- Enable traces -- full walkthrough including receiver configuration.