In this article, we’ll demonstrate how to instrument a Java application built with Maven using the OpenTelemetry Java Agent. Observability is a cornerstone of modern application development. OpenTelemetry provides a unified framework to collect and analyze telemetry data such as traces, metrics, and logs. By the end, you’ll have a Spring Boot application configured for tracing, metrics, and logging with minimal manual effort.
Table of Contents
Prerequisites
Before you start, ensure you have the following installed on your system.
- AWS Account with Ubuntu 24.04 LTS EC2 Instance.
- Java Development Kit (JDK), Maven installed.
Step #1:Set Up Ubuntu EC2 Instance
If you don’t have JDK or Maven installed on your system you can install it by using following commands.
First Update the package list.
sudo apt update

Spring Boot requires Java, so install OpenJDK.
sudo apt install openjdk-17-jdk -y

Verify the Java installation.
java -version

You should see the version details of your Java installation.
Now lets install Maven. Maven is the build tool used to manage Java projects.
sudo apt install maven -y

Verify the Maven installation.
mvn -version

Step #2:Create a New Java Application with Maven
Maven follows a standard directory layout, which makes it easier to manage projects. To create a new Maven project, you can use the command line.
Run the following command to create a new project.
mvn archetype:generate -DgroupId=com.example -DartifactId=java-simple -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

- groupId: A unique identifier for your project (usually the package name).
- artifactId: The name of your project.
- archetypeArtifactId: The template for the project;
maven-archetype-quickstart
creates a simple Java project. - interactiveMode: Set to
false
to skip interactive prompts.
Navigate to the project directory.
cd java-simple

Open the pom.xml
file and update the file for Spring Boot dependencies.
The pom.xml
(Project Object Model) file is the core of a Maven project. It contains configuration details, such as dependencies, build settings, and project information.
nano pom.xml

replace its content with the following:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>helloworld</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>helloworld</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Step #3:Create the Java Application and Controller
Create a new file named DiceApplication.java and RestController.java in the src/main/java/com/example
directory with the following content:
For that first navigate to the directory.
cd src/main/java/com/example

Remove the default App.java file.
sudo rm App.java

Create a file named DiceApplication.java
nano DiceApplication.java

Add the following code:
package com.example;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DiceApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DiceApplication.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
}
Explanation of the code:
This is the main application code for a simple Java Spring Boot project, which launches a web application without displaying the Spring Boot banner.
- Package Declaration:
package com.example;
: Defines the package for theDiceApplication
class. In Java, packages help organize classes logically and avoid naming conflicts.
- Import Statements:
- Imports Spring Boot classes for app startup (
SpringApplication
) and configuration (SpringBootApplication
), along withBanner
for optional customization.
- Imports Spring Boot classes for app startup (
- Class Annotation:
- @SpringBootApplication: This annotation marks the main class of the Spring Boot application, enabling features like:
- @Configuration: Allows Java-based configuration in place of XML.
- @EnableAutoConfiguration: Enables automatic configuration of Spring based on dependencies.
- @ComponentScan: Scans the package for Spring components (like controllers and services), making them available to the application.
- @SpringBootApplication: This annotation marks the main class of the Spring Boot application, enabling features like:
- Class and main Method:
- Declares DiceApplication as the main class.
- SpringApplication app = new SpringApplication(DiceApplication.class); – Initializes the application.
- app.setBannerMode(Banner.Mode.OFF); – Disables the banner for cleaner console output.
- app.run(args); – Starts the application, launching the embedded web server.
Create the RollController class to simulate a dice roll.
nano RollController.java

Add the following code.
package com.example;
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;
@RestController
public class RollController {
private static final Logger logger = LoggerFactory.getLogger(RollController.class);
@GetMapping("/rolldice")
public String index(@RequestParam("player") Optional<String> player) {
int result = this.getRandomNumber(1, 6);
if (player.isPresent()) {
logger.info("{} is rolling the dice: {}", player.get(), result);
} else {
logger.info("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);
}
}

Explanation of the code:
This RollController
class handles HTTP requests for rolling a dice. It provides an endpoint (/rolldice
) that simulates rolling a dice and logs the result, optionally associating it with a player name.
- Package Declaration:
- package com.example; – Organizes the class under the
com.example
package.
- package com.example; – Organizes the class under the
- Imports:
java.util.Optional
,java.util.concurrent.ThreadLocalRandom
: For handling optional player input and generating random dice numbers.org.slf4j.Logger
,org.slf4j.LoggerFactory
: For logging the dice roll results.org.springframework.web.bind.annotation.GetMapping
,org.springframework.web.bind.annotation.RequestParam
,org.springframework.web.bind.annotation.RestController
: For defining the RESTful controller and handling GET requests with optional query parameters.
- @RestController Annotation:
- Indicates that the class is a Spring REST controller, capable of handling HTTP requests and returning HTTP responses.
- Logger:
private static final Logger logger = LoggerFactory.getLogger(RollController.class);
– Initializes a logger for the class to log dice roll information.
- index Method:
@GetMapping("/rolldice")
: Maps the/rolldice
URL to this method, allowing HTTP GET requests to trigger the dice roll logic.@RequestParam("player") Optional<String> player
: Captures the optionalplayer
query parameter from the URL (e.g.,/rolldice?player=John
).int result = this.getRandomNumber(1, 6);
: Rolls the dice by generating a random number between 1 and 6.- Logs the dice roll result, either associating it with a player if the name is provided or logging it as an anonymous roll.
- Returns the dice roll result as a string.
- getRandomNumber Method:
- Generates a random number between the specified
min
andmax
values usingThreadLocalRandom.current().nextInt(min, max + 1)
.
- Generates a random number between the specified
Step #4:Build and Run the Java Application
Navigate back to the root directory of the project.
cd ../../../../..

Build the project.
mvn package

The output JAR file will be located in the target
directory.
Run the application.
java -jar ./target/helloworld-1.0-SNAPSHOT.jar

The application is now running, and you can access it at http://<EC2-Instance-IP>:8080/rolldice.

Step #5:Integrate OpenTelemetry Java Agent
Download the OpenTelemetry Java Agent.
curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Set environment variables.
export JAVA_TOOL_OPTIONS="-javaagent:/home/ubuntu/java-simple/opentelemetry-javaagent.jar" \
OTEL_TRACES_EXPORTER=logging \
OTEL_METRICS_EXPORTER=logging \
OTEL_LOGS_EXPORTER=logging \
OTEL_METRIC_EXPORT_INTERVAL=15000

Run the application with OpenTelemetry.
java -jar ./target/helloworld-1.0-SNAPSHOT.jar

The application is now running, lets access it again at http://<EC2-Instance-IP>:8080/rolldice.

When the application runs, you should see telemetry data such as traces, logs, and metrics in the console. The OpenTelemetry agent automatically instruments the application, requiring no code changes for monitoring.


Conclusion:
In this article, we demonstrated how to instrument a Java application built with Maven using the OpenTelemetry Java Agent. Maven is a powerful tool that simplifies the process of building and managing Java projects. This setup allows seamless collection of telemetry data, offering valuable insights into java application performance. By leveraging OpenTelemetry, developers can create resilient and observable applications effortlessly.
Related Articles:
How to Build Spring Boot Project Using Gradle
Reference: