Mastering Observability: A Step-by-Step Guide to OpenTelemetry for Java Developers — Part 1
Introduction to OpenTelemetry
In today’s complex microservice architectures, understanding the performance and behavior of your Java applications is paramount, so ensuring observability is more crucial than ever. In such a regard, it’s important to emphasize that traditional logging and debugging methods often fall short when tracing requests across multiple (micro)services.
That’s where OpenTelemetry comes in. OpenTelemetry offers a robust, vendor-neutral, open-source observability framework that makes it easier for engineers to monitor and understand their applications by providing a standardized way to instrument, generate, collect, and export telemetry data (metrics, logs, and traces).
This blog post will guide you through leveraging OpenTelemetry with Java, exploring its key features, and demonstrating how to get started with this indispensable tool. It will empower you to gain deep insights into your application’s telemetry signals, so I’ll enable you to troubleshoot issues effectively.
We’ll explore the core concepts, walk through a step-by-step implementation, and highlight the benefits of using OpenTelemetry. For all things OpenTelemetry with Java, please check the links provided in the References section at the bottom of this blog post.
So, without further ado, let’s get started!
Prerequisites
- JDK — Java Development Kit
- Your preferred Java IDE — Eclipse, IntelliJ, VS Code
- Apache Maven or Gradle
Step-by-Step Guide: Instrumenting Your Java Application with OpenTelemetry
Follow all the steps below to configure your Java application with Maven or Gradle.
Step 1: Setting Up OpenTelemetry for Java
Begin by setting up OpenTelemetry in your Java application. First, include the necessary dependencies in your build.gradle or pom.xml file.
Maven
Add the OpenTelemetry dependencies to your pom.xml
file. Below is an example of including the OpenTelemetry API, SDK, and the OTLP exporter:
<dependencies>
<!-- OpenTelemetry API -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.47.0</version>
</dependency>
<!-- OpenTelemetry SDK -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
<version>1.47.0</version>
</dependency>
<!-- OTLP Exporter -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<version>1.47.0</version>
</dependency>
<!-- OpenTelemetry Java Agent (for automatic instrumentation) -->
<dependency>
<groupId>io.opentelemetry.javaagent</groupId>
<artifactId>opentelemetry-javaagent</artifactId>
<version>1.47.0</version>
</dependency>
</dependencies>
Gradle
Add the required dependencies to your build.gradle
file. Below is an example of including the OpenTelemetry API, SDK, and the OpenTelemetry Protocol (OTLP) exporter:
dependencies {
// OpenTelemetry API
implementation 'io.opentelemetry:opentelemetry-api:1.47.0'
// OpenTelemetry SDK
implementation 'io.opentelemetry:opentelemetry-sdk:1.47.0'
// OTLP Exporter
implementation 'io.opentelemetry:opentelemetry-exporter-otlp:1.47.0'
// OpenTelemetry Java Agent (for automatic instrumentation)
implementation 'io.opentelemetry.javaagent:opentelemetry-javaagent:1.47.0'
}
Use the OpenTelemetry release page to check for the latest versions.
Step 2: Instrumenting your Java application
You can instrument your application either automatically using the Java Agent or manually using the OpenTelemetry Java API.
Automatic Instrumentation:
- Java Agent: for many common libraries and frameworks, you can leverage the OpenTelemetry Java Agent for automatic instrumentation. As shown below, the Java Agent can collect telemetry data without any code changes ( zero-code instrumentation) as it dynamically injects bytecode to capture telemetry from many popular libraries and frameworks.
- Configuration: if required, configure the Java Agent to enable instrumentation for specific libraries by checking the official documentation.
java -javaagent:/path/to/opentelemetry-javaagent.jar -jar <YOUR_JAVA_APP_NAME>.jar
Manual Instrumentation:
Alternatively, for finer control and customizations, manually implement the configuration and instrumentation code as shown below:
// Step 2: Manually instrumenting your Java application
SdkTracerProvider tracerProvider = SdkTracerProvider.builder().build();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build();
Tracer tracer = openTelemetry.getTracer("example-tracer");
Span span = tracer.spanBuilder("example-operation").startSpan();
try (Scope scope = span.makeCurrent()) {
// Your application logic here...
System.out.println("This is an example operation.");
} finally {
span.end();
}
Step 3: Exporting Telemetry Data
Telemetry data is most useful when exported to an observability backend for analysis. OpenTelemetry supports various exporters, such as OTLP, Jaeger, and Zipkin. Below is an example of configuring the OTLP exporter:
// Step 4: Exporting Telemetry Data
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder().setEndpoint("http://<YOUR_HOST:PORT>").build();
tracerProvider.addSpanProcessor(SimpleSpanProcessor.create(spanExporter));
The HTTP port 4317 in the configuration for the OtlpGrpcSpanExporter is the default gRPC endpoint for the OTLP receiver in many observability backends or telemetry collection services, so the telemetry data (traces, metrics, and logs) is sent in the OTLP format to an observability backend for analysis. The http://localhost:4317 endpoint is commonly associated with the following backends:
- OpenTelemetry Collector: This endpoint has the most typical use case. It is a vendor-agnostic service that receives, processes, and exports telemetry data to various observability backends like Jaeger, Zipkin, Prometheus, or cloud observability platforms. The Collector often listens on port 4317 for gRPC-based OTLP data and port 4318 for HTTP-based OTLP data.
- Other OTLP-Compatible Services: If you use a specific Application Performance Management (APM) tool or observability platform that supports OTLP, you may configure their local agent or receiver to listen on port 4317. These platforms integrate with OpenTelemetry to ingest telemetry data seamlessly.
If you’re not using the Collector or another configured OTLP receiver locally, ensure that your target observability backend or service supports OTLP on this port or adjust the endpoint accordingly.
Code sample (config, instrumentation, export/publish
Below is a complete code sample so you can test it all.
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
public class OpenTelemetryExample {
public static void main(String[] args) {
// Step 2: Manually instrumenting your Java application
SdkTracerProvider tracerProvider = SdkTracerProvider.builder().build();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build();
Tracer tracer = openTelemetry.getTracer("example-tracer");
Span span = tracer.spanBuilder("example-operation").startSpan();
try (Scope scope = span.makeCurrent()) {
// Your application logic here...
System.out.println("This is an example operation.");
} finally {
span.end();
}
// Step 3: Exporting Telemetry Data
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder().setEndpoint("http://localhost:4317").build();
tracerProvider.addSpanProcessor(SimpleSpanProcessor.create(spanExporter));
}
}
As we can see, again, the code sample above shows the most basic steps as required. First, it sets up OpenTelemetry in a Java application; second, it instruments a simple operation; third, it configures an exporter to export/send telemetry data to an observability backend system (again, Jaeger, Zipkin, etc) or a cloud provider’s observability platform and the respective dashboards.
With such tools, you can visualize and analyze your telemetry data, identifying issues and extracting valuable insights into the application’s behavior. Now you have a basic understanding of how OpenTelemetry can be used in Java applications!
Last but not least, note that the official OpenTelemetry examples have plenty of additional examples. Just check them and clone the OpenTelemetry Java Examples repository as listed in the References section below to explore other ready-to-run configurations.
git clone https://github.com/open-telemetry/opentelemetry-java-examples.git
Wrapping it up
OpenTelemetry is a game-changer for software engineers looking to enhance their application’s observability. Following the steps outlined in this guide, you can seamlessly integrate OpenTelemetry into your Java applications and start reaping the benefits of comprehensive telemetry data.
This blog post has provided a starting point for your OpenTelemetry journey. Explore the official documentation and examples as listed in the References section below to investigate the features and integrations available:
That’s it! With OpenTelemetry, you can stay ahead of the curve and ensure your systems are always running at their best. Start instrumenting your applications today and unlock the power of observability!
I will soon post more examples of scenarios involving LangChain4J, the OracleEmbeddingStore, GraalVM, Micronaut, Quarkus, and other GenAI / Agentic AI-related topics!
We hope you liked this blog post. Stay tuned!
References
OpenTelemetry Concepts
OpenTelemetry Java API — Javadocs
OpenTelemetry API / API Extensions
Oracle Database Free Release 23ai — Container Image
Oracle® Database JDBC Java API Reference, Release 23ai
Develop Java applications with Oracle Database
IntelliJ IDEA — Database Tools and SQL plugin with Oracle Databases
Oracle Developers and Oracle OCI Free Tier
Join our Oracle Developers channel on Slack to discuss Java, JDK, JDBC, GraalVM, Microservices with Spring Boot, Helidon, Quarkus, Micronaut, Reactive Streams, Cloud, DevOps, IaC, and other topics!
Build, test, and deploy your applications on Oracle Cloud — for free! Get access to OCI Cloud Free Tier!