Getting Started

Get telemetry for your app in less than 5 minutes!

This page will show you how to get started with OpenTelemetry in Java.

You will learn how you can instrument a simple Java application automatically, in such a way that traces, metrics, and logs are emitted to the console.


Ensure that you have the following installed locally:

Example Application

The following example uses a basic Spring Boot application. You can use another web framework, such as Apache Wicket or Play. For a complete list of libraries and supported frameworks, consult the registry.

For more elaborate examples, see examples.


To begin, set up an environment in a new directory called java-simple. Within that directory, create a file called build.gradle.kts with the following content:

plugins {
  id("org.springframework.boot") version "3.0.6"
  id("io.spring.dependency-management") version "1.1.0"

sourceSets {
  main {

repositories {

dependencies {

Create and launch an HTTP Server

In that same folder, create a file called and add the following code to the file:

package otel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;

public class DiceApplication {
  public static void main(String[] args) {
    SpringApplication app = new SpringApplication(DiceApplication.class);

Create another file called and add the following code to the file:

package otel;

import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

public class RollController {
  private static final Logger logger = LoggerFactory.getLogger(RollController.class);

  public String index(@RequestParam("player") Optional<String> player) {
    int result = this.getRandomNumber(1, 6);
    if (player.isPresent()) {"{} is rolling the dice: {}", player.get(), result);
    } else {"Anonymous player is rolling the dice: {}", result);
    return Integer.toString(result);

  public int getRandomNumber(int min, int max) {
    return ThreadLocalRandom.current().nextInt(min, max + 1);

Build and run the application with the following command, then open http://localhost:8080/rolldice in your web browser to ensure it is working.

gradle assemble
java -jar ./build/libs/java-simple.jar


Next, you’ll use a Java agent to automatically instrument the application at launch time. While you can configure the Java agent in a number of ways, the steps below use environment variables.

  1. Download opentelemetry-javaagent.jar from Releases of the opentelemetry-java-instrumentation repository. The JAR file contains the agent and all automatic instrumentation packages:

    curl -L -O
  2. Set and export variables that specify the Java agent JAR and a console exporter, using a notation suitable for your shell/terminal environment — we illustrate a notation for bash-like shells:

    export JAVA_TOOL_OPTIONS="-javaagent:PATH/TO/opentelemetry-javaagent.jar" \
      OTEL_TRACES_EXPORTER=logging \
      OTEL_LOGS_EXPORTER=logging \
  3. Run your application once again:

    $ java -jar ./build/libs/java-simple.jar

    Note the output from the otel.javaagent.

  4. From another terminal, send a request using curl:

    curl localhost:8080/rolldice
  5. Stop the server process.

At step 4, you should have seen trace & log output from the server and client that looks something like this (trace output is line-wrapped for convenience):

[otel.javaagent 2023-04-24 17:33:54:567 +0200] [http-nio-8080-exec-1] INFO
io.opentelemetry.exporter.logging.LoggingSpanExporter - 'RollController.index' :
 70c2f04ec863a956e9af975ba0d983ee 7fd145f5cda13625 INTERNAL [tracer:
 io.opentelemetry.spring-webmvc-6.0:1.25.0-alpha] AttributesMap{data=
 {,}, capacity=128,
[otel.javaagent 2023-04-24 17:33:54:568 +0200] [http-nio-8080-exec-1] INFO
io.opentelemetry.exporter.logging.LoggingSpanExporter - 'GET /rolldice' :
70c2f04ec863a956e9af975ba0d983ee 647ad186ad53eccf SERVER [tracer:
io.opentelemetry.tomcat-10.0:1.25.0-alpha] AttributesMap{
  net.transport=ip_tcp,, net.sock.peer.addr=,, net.sock.peer.port=53422,
  http.route=/rolldice,,,, http.status_code=200, http.scheme=http,
  net.protocol.version=1.1, http.response_content_length=1,, http.method=GET}, capacity=128, totalAddedValues=17}

At step 5, when stopping the server, you should see an output of all the metrics collected (metrics output is line-wrapped and shortened for convenience):

[otel.javaagent 2023-04-24 17:34:25:347 +0200] [PeriodicMetricReader-1] INFO
io.opentelemetry.exporter.logging.LoggingMetricExporter - Received a collection
 of 19 metrics for export.
[otel.javaagent 2023-04-24 17:34:25:347 +0200] [PeriodicMetricReader-1] INFO
io.opentelemetry.exporter.logging.LoggingMetricExporter - metric:
ImmutableMetricData{resource=Resource{schemaUrl=, attributes={host.arch="aarch64","OPENTELEMETRY", os.description="Mac OS X 13.3.1", os.type="darwin",
process.command_args=[/bin/java, -jar, java-simple.jar],
process.runtime.description="Homebrew OpenJDK 64-Bit Server VM 20","OpenJDK Runtime Environment",
process.runtime.version="20","java-simple","1.25.0", telemetry.sdk.language="java","opentelemetry", telemetry.sdk.version="1.25.0"}},
version=1.25.0, schemaUrl=null, attributes={}},
name=process.runtime.jvm.buffer.limit, description=Total capacity of the buffers
in this pool, unit=By, type=LONG_SUM, data=ImmutableSumData{points=
epochNanos=1682350465326752000, attributes=
{pool="mapped - 'non-volatile memory'"}, value=0, exemplars=[]},
epochNanos=1682350465326752000, attributes={pool="mapped"},
value=0, exemplars=[]},
epochNanos=1682350465326752000, attributes={pool="direct"},
value=8192, exemplars=[]}], monotonic=false, aggregationTemporality=CUMULATIVE}}

What next?

For more: