Kubesense

Java

Send OpenTelemetry traces from Java applications to KubeSense with the OpenTelemetry Java agent.

Java applications are instrumented with the OpenTelemetry Java agent, a single JAR attached at startup. It creates spans for Spring Boot, servlet containers, JDBC, Kafka, gRPC, HTTP clients and many other libraries, with no code changes. It supports Java 8 and later.

Option 1: Kubernetes with the OpenTelemetry Operator (zero code)

If you have set up the OpenTelemetry Operator, add this annotation to the pod template and restart the workload:

spec:
  template:
    metadata:
      annotations:
        instrumentation.opentelemetry.io/inject-java: "kubesense/otel-instrumentation"

Option 2: Auto-instrumentation on VMs (no code changes)

Use this on VMs, or on Kubernetes clusters without the operator. You only attach the Java agent at startup; the application code is not changed.

Step 1: Download the agent

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

For production, pin a specific version instead of latest. Releases are listed at opentelemetry-java-instrumentation releases.

Step 2: Start the application with the agent

Using system properties:

java -javaagent:/opt/otel/opentelemetry-javaagent.jar \
  -Dotel.service.name=payments-service \
  -Dotel.exporter.otlp.endpoint=http://<KUBESENSE_INGEST_HOST>:33443 \
  -Dotel.exporter.otlp.protocol=http/protobuf \
  -Dotel.resource.attributes=kubesense.cluster=<CLUSTER_NAME>,kubesense.env_type=legacy \
  -Dotel.metrics.exporter=none \
  -Dotel.logs.exporter=none \
  -jar payments-service.jar

Or using environment variables, which is easier in containers:

export JAVA_TOOL_OPTIONS="-javaagent:/opt/otel/opentelemetry-javaagent.jar"
export OTEL_SERVICE_NAME=payments-service
export OTEL_EXPORTER_OTLP_ENDPOINT=http://<KUBESENSE_INGEST_HOST>:33443
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_RESOURCE_ATTRIBUTES=kubesense.cluster=<CLUSTER_NAME>,kubesense.env_type=legacy
export OTEL_METRICS_EXPORTER=none
export OTEL_LOGS_EXPORTER=none

java -jar payments-service.jar
SettingValueNotes
OTEL_EXPORTER_OTLP_ENDPOINThttp://<KUBESENSE_INGEST_HOST>:33443Base URL only; the agent appends /v1/traces. Inside the KubeSense cluster, use http://kubesense-kubecol.kubesense.svc.cluster.local:33443
OTEL_EXPORTER_OTLP_PROTOCOLhttp/protobufPort 33443 accepts OTLP over HTTP
OTEL_RESOURCE_ATTRIBUTESkubesense.cluster=...,kubesense.env_type=...Use = between key and value, and , between pairs. Use kubesense.env_type=k8s on Kubernetes

Container image (Kubernetes without the operator)

FROM eclipse-temurin:21-jre
ARG OTEL_JAVA_AGENT_VERSION=<VERSION>
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OTEL_JAVA_AGENT_VERSION}/opentelemetry-javaagent.jar /opt/otel/opentelemetry-javaagent.jar
COPY target/payments-service.jar /app/app.jar

ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/otel/opentelemetry-javaagent.jar" \
    OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
    OTEL_METRICS_EXPORTER=none \
    OTEL_LOGS_EXPORTER=none

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Set OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_RESOURCE_ATTRIBUTES in the Kubernetes manifest.

Step 3: Verify

Startup logs show a line similar to opentelemetry-javaagent - version: .... Generate some traffic, then open APM → Traces in KubeSense and filter by your service name.

Manual instrumentation (SDK)

For Spring Boot applications, you can add OpenTelemetry as a dependency instead of attaching the Java agent. The OpenTelemetry Spring Boot starter instruments Spring web requests, RestTemplate / WebClient calls, JDBC and other common libraries, and is configured with the same OTEL_* environment variables. Use it instead of the Java agent.

For applications that don't use Spring Boot, use the Java agent (Option 1 or Option 2).

Step 1: Add the dependency

Maven:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.opentelemetry.instrumentation</groupId>
      <artifactId>opentelemetry-instrumentation-bom</artifactId>
      <version>${opentelemetry-instrumentation.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-spring-boot-starter</artifactId>
  </dependency>
</dependencies>

Gradle:

implementation platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${otelInstrumentationVersion}")
implementation "io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter"

Use the latest version from opentelemetry-java-instrumentation releases.

Step 2: Configure the endpoints

No setup code is needed: the starter configures itself when the application starts. Set the environment variables from Manual SDK: where to send traces, then build and start the application as usual.

Troubleshooting

Add -Dotel.javaagent.debug=true temporarily to print the agent's activity.

SymptomCheck
No agent line in the startup logs-javaagent must come before -jar. When using JAVA_TOOL_OPTIONS, check that the process sees the variable
Failed to export spans / connection refusedTrace ingestion is not enabled on KubeSense, or port 33443 is not reachable
Resource attributes missing in KubeSenseCheck the format: key=value pairs separated by commas, for example kubesense.env_type=k8s, not kubesense.env_type:k8s
Exporter errors for metrics or logsSet OTEL_METRICS_EXPORTER=none and OTEL_LOGS_EXPORTER=none
Too many spans from one libraryDisable it, for example -Dotel.instrumentation.jdbc.enabled=false. Replace jdbc with the instrumentation's name