Sitemap
KloudMate

KloudMate is an Observability platform for modern Engineering teams, building and managing applications on distributed, microservices based architectures. It provides the fastest route to setting up and achieving Observability.

How to Monitor API and Database Performance in Java Applications Using OpenTelemetry

7 min readMar 6, 2025

--

Press enter or click to view image in full size

Software applications are getting increasingly distributed, complex, and reliant on microservices, monitoring performance has become a non-negotiable aspect of maintaining system reliability and user satisfaction. APIs and databases are fundamental components of most Java applications, serving as the backbone for communication between services and the storage and retrieval of critical data. When these components underperform, the entire application can suffer, leading to slow response times, frustrated users, and potential revenue loss.

Observability allows the ability to understand the internal state of a system by examining its outputs, such as logs, metrics, and traces. OpenTelemetry, an open-source observability framework, has emerged as a game-changer in this space. It provides a standardized way to collect, analyze, and export telemetry data, making it easier to monitor and troubleshoot Java applications.

In this blog, we’ll explore how OpenTelemetry can be used to monitor API and database performance in Java applications. We’ll also discuss why monitoring these components is critical, how OpenTelemetry works, and the best practices for implementing it effectively.

The Importance of Monitoring APIs and Databases

Press enter or click to view image in full size

APIs (Application Programming Interfaces) are the primary means by which different components of a system communicate with each other. Whether it’s a RESTful API, a GraphQL endpoint, or a gRPC service, APIs are responsible for handling requests, processing data, and returning responses. When APIs perform poorly, the entire application can grind to a halt. Common issues include:

  • High Latency: Slow response times can lead to a poor user experience.
  • Errors and Failures: APIs may fail due to incorrect input, network issues, or backend problems.
  • Throttling and Rate Limiting: APIs may become overwhelmed by too many requests, leading to throttling.

Monitoring APIs allows you to identify these issues early, optimize performance, and ensure a seamless user experience.

Databases are where your application stores and retrieves critical data. Whether you’re using a relational database like MySQL or PostgreSQL, or a NoSQL database like MongoDB or Cassandra, database performance is crucial to the overall health of your application. Common database-related issues include:

  • Slow Queries: Poorly optimized queries can lead to slow response times.
  • Connection Pooling Issues: Exhausted connection pools can cause delays or failures.
  • Deadlocks and Contention: Concurrent transactions can lead to deadlocks, causing delays or failures.

Monitoring database performance helps you identify bottlenecks, optimize queries, and ensure that your application can handle increasing loads.

Best Practices for OpenTelemetry in Java

1. Focus on Key Metrics and Traces

When monitoring APIs and databases, it’s important to focus on the metrics and traces that matter most. For APIs, this might include request latency, error rates, and throughput. For databases, this might include query execution time, connection pool usage, and error rates. By focusing on these key metrics, you can quickly identify performance bottlenecks and take corrective action.

2. Use Context Propagation

Context propagation is the process of passing trace context between different components of a system. This is especially important in distributed systems, where a single request might span multiple services. OpenTelemetry provides built-in support for context propagation, making it easy to maintain end-to-end visibility across your system.

3. Implement Sampling

Sampling is the process of selecting a subset of traces to collect and analyze. This is important because collecting every single trace can quickly become overwhelming, both in terms of storage and processing. OpenTelemetry provides several sampling strategies, including head-based sampling and tail-based sampling, allowing you to balance the volume of data with the level of detail you need.

4. Combine Traces, Metrics, and Logs

While traces, metrics, and logs are useful on their own, they are even more powerful when combined. For example, a trace might show that a particular API call is slow, while metrics might show that the database is under heavy load, and logs might reveal a specific error message. By combining these different types of telemetry data, you can gain a more complete understanding of your system’s performance.

5. Monitor for Anomalies

In addition to monitoring key metrics, it’s important to monitor for anomalies. Anomalies are deviations from normal behavior, such as a sudden spike in error rates or a drop in throughput. OpenTelemetry can be integrated with anomaly detection tools to alert you when something unusual happens, allowing you to investigate and resolve issues before they impact users.

Instrumenting Java Applications with OpenTelemetry

Instrumenting a Java application with OpenTelemetry allows you to capture critical telemetry data such as traces, metrics, and logs. This process helps you gain deep insights into your application’s performance, identify bottlenecks, and troubleshoot issues effectively.

In this section, we’ll walk through the steps to instrument a Java application using OpenTelemetry. By the end, you’ll understand how to set up and configure OpenTelemetry to collect and analyze telemetry data, enabling you to optimize your application’s performance and reliability.

Step 1: Prerequisites

Before getting started, ensure your development environment is set up with the following:

  • Java Development Kit (JDK): Required to compile and run Java applications.
  • Gradle: A build automation tool to manage dependencies and build the project.

Step 2: Preparing the Example Application

To demonstrate instrumentation, we’ll use a basic Spring Boot application. While Spring Boot is our framework of choice here, OpenTelemetry is compatible with other Java frameworks like Apache Wicket and Play. You can adapt the steps to suit your preferred framework.

Step 3: Setting Up the Application

To begin, create a new directory named java-simple. Inside this directory, add a file called build.gradle.kts and include the following configuration:

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

sourceSets {
main {
java.setSrcDirs(setOf("."))
}
}

repositories {
mavenCentral()
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
}

This configuration sets up a basic Spring Boot application using Gradle as the build tool. It defines the necessary plugins, source directories, and dependencies to get started.

Step 4: Creating the Application Files

1. Main Application Class

package otel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.Banner;
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);
}
}

This class serves as the entry point for the Spring Boot application, initializing and running the application.

Get Vasavi’s stories in your inbox

Join Medium for free to get updates from this writer.

2. Controller Class

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;

@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);
}
}

This controller simulates a dice-rolling functionality, logging the results for each player or anonymous user.

Step 5: Running the Application

Build and start the application using the following commands:

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

Once the application is running, open http://localhost:8080/rolldice in your browser to verify that it’s working as expected.

Step 6: Instrumenting the Application

Now, let’s integrate OpenTelemetry to automatically capture telemetry data.

1. Download the OpenTelemetry Java Agent

  • Download the opentelemetry-javaagent.jar from the official releases page. This JAR file contains the agent and all necessary automatic instrumentation packages:
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases

2. Configure the Agent

  • Set up environment variables to configure the Java agent and specify the console exporter details. For example:
export JAVA_TOOL_OPTIONS="-javaagent:PATH/TO/opentelemetry-javaagent.jar" \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=otlp \
OTEL_LOGS_EXPORTER=otlp \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.kloudmate.com:4318 \
OTEL_EXPORTER_OTLP_HEADERS="Authorization=<YOUR_SECRET_KEY>"

Replace /path/to/ with the actual path to the downloaded JAR file.

The exporter configuration along with the KloudMate API-Key as the Authorization header sends telemetry data to KloudMate for visualization and analysis.

3. Run the Instrumented Application

  • Start the application with the following command:
$ java -jar ./build/libs/java-simple.jar
...

The OpenTelemetry agent will now automatically capture traces, metrics, and logs as the application runs.

4. Test the Instrumentation

  • Use curl or a browser to send requests to the application:
curl localhost:8080/rolldice

Observe the logs and traces generated by OpenTelemetry to confirm that the instrumentation is working as expected.

5. Stop the Application

  • Stop the application to review the collected metrics and traces.

Conclusion

Monitoring API and database performance is essential for maintaining the health and efficiency of Java applications. OpenTelemetry provides a powerful, standardized way to collect and analyze telemetry data, enabling you to identify and resolve performance issues quickly. By following the steps outlined in this blog, you can instrument your Java application with OpenTelemetry and gain valuable insights into its behavior.

With tools like KloudMate, you can seamlessly visualize and analyze the telemetry data collected by OpenTelemetry, making it easier to monitor your application’s performance in real-time. Whether you’re troubleshooting issues or optimizing workflows, OpenTelemetry and KloudMate together provide a comprehensive observability solution for your Java applications.

Additional Resources:

--

KloudMate
KloudMate

Published in KloudMate

KloudMate is an Observability platform for modern Engineering teams, building and managing applications on distributed, microservices based architectures. It provides the fastest route to setting up and achieving Observability.