# Java

> Zero-code instrumentation for JVM services with the OpenTelemetry agent

The OpenTelemetry Java agent instruments a running JVM without touching your source. It
hooks more than a hundred libraries — servlets, Spring, JDBC, Kafka, gRPC, the HTTP
clients — and emits traces, metrics and logs.

Works with Spring Boot, Quarkus, Micronaut, Dropwizard and plain Tomcat or Jetty.

## Install the agent

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

The `latest` URL always resolves to the current release. Pin a version in production if
you want reproducible builds.

## Configure

```bash
export OTEL_SERVICE_NAME="my-java-service"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingress.rocketlog.io"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer rg_live_xxxxxx"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_LOGS_EXPORTER="otlp"
export OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_LOG_ATTRIBUTES="true"
```

The last line attaches MDC values and exception stack traces to exported log records,
which is what makes a log line searchable by trace id later.

## Run

```bash
java -javaagent:./opentelemetry-javaagent.jar -jar my-app.jar
```

> **Warning:** `-javaagent` must come **before** `-jar`. Anything after `-jar` is passed to your
  application rather than the JVM, which is the usual reason the agent appears to do
  nothing at all.

## In a container

```dockerfile
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/javaagent.jar

ENV OTEL_SERVICE_NAME=my-java-service \
    OTEL_EXPORTER_OTLP_ENDPOINT=https://ingress.rocketlog.io \
    OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
    OTEL_LOGS_EXPORTER=otlp

# Pass the key at runtime — never bake it into the image.
ENTRYPOINT ["java", "-javaagent:/otel/javaagent.jar", "-jar", "app.jar"]
```

## Custom spans

The agent covers framework and library calls. Add spans by hand only for business
operations worth naming.

```java
// build.gradle: implementation("io.opentelemetry:opentelemetry-api:1.+")
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;

Tracer tracer = GlobalOpenTelemetry.getTracer("payments");

Span span = tracer.spanBuilder("settle-transfer").startSpan();
try (var scope = span.makeCurrent()) {
    span.setAttribute("transfer.id", transferId);
    settle(transferId);
} catch (Exception e) {
    span.recordException(e);
    throw e;
} finally {
    span.end();
}
```

> **Note:** Depend on `opentelemetry-api` only. The agent supplies the implementation at runtime —
  adding the SDK as well gives you two providers and no data.
