Mastering Observability: Streamline Java Application Observability with the Oracle JDBC OpenTelemetry Provider — Part 2

Introduction to OpenTelemetry and the Oracle JDBC driver
In today’s complex microservices architectures, pinpointing issues such as performance bottlenecks in Java applications interacting with databases can feel like searching for a needle in a haystack. Traditional logging often falls short, leaving developers struggling to correlate events and understand the entire lifecycle of a database query.
Modern Java applications rely heavily on databases for data storage, retrieval, and processing. As applications become more complex, observability — the ability to monitor and understand system behavior — becomes critical. 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 post will focus on how the Oracle JDBC Open Telemetry Provider enables seamless observability for Java applications interacting with Oracle databases. This tool simplifies tracing and monitoring database interactions via OpenTelemetry, empowering developers to identify bottlenecks, troubleshoot performance issues, and optimize query execution.
It empowers you to optimize performance and troubleshoot issues effectively. We’ll walk through a step-by-step guide to integrate this provider, unlocking a new level of observability for your Java and Oracle Database applications.
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
- Oracle Database Free Release 23ai — Container Image
- Oracle JDBC Driver 23ai (23.7.0.25.01) — Maven Central
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: Project Setup and Dependencies
First, you’ll need to add the necessary dependencies to your project. This includes the OpenTelemetry Java SDK, the Oracle JDBC driver, and the Oracle JDBC OpenTelemetry Provider. Then, using a build tool like Maven or Gradle, add the necessary dependencies to your build.gradle or pom.xml file.
Maven
The provider is distributed as a single jar on the Maven Central Repository. 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>
<!-- OpenTelemetry SDK Trace -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-trace</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>
<!-- Oracle JDBC Driver -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc17</artifactId>
<version>23.7.0.25.01</version>
</dependency>
<!-- Oracle JDBC OpenTelemetry Provider -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc-provider-opentelemetry</artifactId>
<version>1.0.3</version>
</dependency>
NOTE: Use the OpenTelemetry release page to check for the latest versions.
Gradle
Add the required dependencies to your build.gradle
file.
dependencies {
// OpenTelemetry API / SDK / Trace
implementation 'io.opentelemetry:opentelemetry-api:1.47.0'
implementation 'io.opentelemetry:opentelemetry-sdk:1.47.0'
implementation 'io.opentelemetry:opentelemetry-sdk-trace: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'
// Oracle JDBC Driver
implementation 'com.oracle.database.jdbc:ojdbc17:23.7.0.25.01'
// Oracle JDBC OpenTelemetry Provider
implementation 'com.oracle.database.jdbc:ojdbc-provider-opentelemetry:1.0.3'
}
Step 2: Configure OpenTelemetry in Your Application
You need to configure the OpenTelemetry SDK in your Java application. This involves setting up a TracerProvider
and a SpanExporter
. The TracerProvider
is responsible for creating Tracer
instances, which are used to create spans. The SpanExporter
is responsible for exporting the collected spans to an observability backend of your choice (e.g., Jaeger, Zipkin, OTLP).
Note that this blog post does not aim to teach you basic OpenTelemetry but to introduce you to the Oracle JDBC Open Telemetry Provider. If you need a quick introduction to OpenTelemetry with Java, please check this blog post — Mastering Observability: A Step-by-Step Guide to OpenTelemetry for Java Developers — Part 1
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
// ... other imports
// Configure the SDK
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(
// Your OTLP endpoint
OtlpGrpcSpanExporter.builder()
.setEndpoint("http://<YOUR_HOST:PORT>")
.build()))
.build();
// Get a tracer instance
Tracer tracer = tracerProvider.tracerBuilder("<YOUR_INSTRUMENTATION_LIBRARY_NAME>").build();
Step 3: Enable Oracle JDBC Open Telemetry instrumentation
Now, you can instrument your JDBC code to create spans for database operations. The Oracle JDBC OpenTelemetry Provider automatically handles this. You simply need to ensure the provider is on the Java classpath and set the following connection properties to configure the listener; again, as I cited before, this provider implements the Java interface TraceEventListener provided by the Oracle JDBC Driver.
The Oracle JDBC provider for Open Telemetry has several properties that can be configured in two ways, first using system properties. Here’s a breakdown of possible properties:
oracle.jdbc.provider.opentelemetry.enabled
: Ensure it's set totrue
to activate telemetry.oracle.jdbc.provider.traceEventListener
: Must be set toopen-telemetry-trace-event-listener-provider
for OpenTelemetry integration.oracle.jdbc.telemetry.serviceName
: Assign a meaningful service name to identify your application's telemetry data.oracle.jdbc.provider.opentelemetry.sensitive-enabled
: Enable if you wish to include sensitive data in your traces; otherwise, it remains disabled by default.
Or it can be configured as a Java MBean:
The object name is “com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener”, and it exposes two attributes Enabled
and SensitiveDataEnabled
.
So, when your application establishes a database connection, the provider automatically instruments the connection and all subsequent database operations.
The code snippet below shows how to retrieve the value of an attribute:
ObjectName objectName = new ObjectName(
"com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener");
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
boolean isEnabled = Boolean.valueOf(server.getAttribute(objectName, "Enabled").toString())
.booleanValue();
Last, but not least, just focusing a bit on the details of it, it’s important to understand how a listener works, so from the Javadocs we have:
TraceEventListener — A listener that receives application and system tracing events from the Oracle Database JDBC drivers.
If an instance is registered with an OracleConnection, that instance’s roundTrip method will be called before and after each round trip to the database executed by that connection. The roundTrip method has limited access to the Connection but can get some information about the round trip and set a trace ID.
If the isDesiredEvent returns true for a particular event type, the instance’s onExecutionEventReceived method will be called for each execution event.
If the driver understands the type of the trace ID, the driver will use that trace ID in trace records generated by the driver during the round trip. If the driver does not understand the type of the trace id it will use the result of calling toString on the trace id. What trace IDs the driver understands may change from release to release.
So, a listener will be notified whenever events are generated in the driver and will publish these events into OpenTelemetry.
These events include:
- Roundtrips to the database server
- AC begin and success events
- VIP down event
The following attributes are added the the traces for each event:
- Roundtrips: Connection ID, Database Operation, Database User, Database Tenant, SQL ID, Original SQL Text (only present if sensitive data is enabled), and Actual SQL Text (only present if sensitive data is enabled);
- AC begin and success events: Error Message, Error code, SQL state, Current replay retry count;
- VIP down events: Error message, VIP address, Protocol (only present if sensitive data is enabled), Host (only present if sensitive data is enabled), Port (only present if sensitive data is enabled), Service name (only present if sensitive data is enabled), SID (only present if sensitive data is enabled), Connection data (only present if sensitive data is enabled).
It is important to grasp the terms and correctly understand all the benefits of defining a VIP down event. In Oracle JDBC, it refers to a situation where the Virtual IP address (VIP) associated with an Oracle database instance becomes unavailable. This can happen due to various reasons, such as:
- Node failure: The physical server hosting the database instance might have crashed or become unavailable.
- Network issues: There might be problems with the network infrastructure, preventing access to the VIP.
- Planned maintenance: The database administrator might have intentionally taken down the instance for maintenance or upgrades.
When a VIP down event occurs, applications using Oracle JDBC to connect to the database might experience connection failures or disruptions. However, Oracle provides features like Fast Application Notification (FAN) and Transparent Application Continuity (TAC) to minimize the impact of such events. So, let us define some additional terms/acronyms.
OpenTelemetry and High-Availability with the Oracle Database, FAN, TAC, RAC, and DRCP — OMG so many acronyms!
Related to the observability events and signals listed above, it’s far beyond the scope of this tutorial to explain enterprise mission-critical, non-functional requirements and concepts such as high availability, reliability, transparent failover, security, and others.
Nevertheless, in the scope of Oracle Database, the JDBC Driver, and OpenTelemetry, we can cite three (3) core topics, namely TAC (Transparent Application Continuity), Fast Application Notification (FAN), and Oracle RAC (Real Application Clusters).
So, in a nutshell (one short paragraph for each), we have:
- FAN - Fast Application Notification: is a notification mechanism within Oracle RAC that alerts applications about configuration changes, including service availability and instance status. Think of it as a real-time alert system for your application regarding the health of the database. It is the foundation upon which features like Transparent Application Continuity (TAC) are built.
- TAC — Transparent Application Continuity: builds upon FAN to provide a more seamless failover experience. Its goal is to make application failures completely transparent to the user. It does this by automatically recovering sessions and replaying in-flight transactions on a surviving instance. Users should ideally even notice that a failure occurred.
- RAC — Real Application Clusters (RAC): Oracle RAC is a database clustering technology by Oracle that enables multiple servers to run the Oracle RDBMS software. The solution provides high availability, scalability, and fault tolerance. If one server fails, the others continue to operate, ensuring uninterrupted service. RAC also allows for increased processing power and improved performance by distributing the workload across multiple servers. It is widely used in mission-critical environments to minimize downtime and improve fault tolerance, leveraging shared disk storage and an interconnect network for communication between nodes.
- DRCP — Resident Connection Pooling: DRCP is an Oracle Database feature designed to enhance the scalability and efficiency of database connections, particularly for applications with high concurrency. Key features include connection sharing across multiple clients, reduced memory usage on both the database and application side, and support for applications using JDBC. DRCP improves resource utilization and allows the database to handle more concurrent users efficiently as it reduces connection management overhead, improves scalability, and enhances performance by minimizing the number of physical connections to the database.
Step 4: Verify Observability with Traces
Once you’ve instrumented your code, run your application and ensure the OpenTelemetry SDK generates traces for database queries. Use the LoggingSpanExporter to see trace logs in the console and/or configure an exporter (Jaeger, Zipkin, etc) for advanced telemetry data visualization. The generated spans will be exported to your configured observability backend.
You can then use your observability backend UI to visualize the traces and analyze the performance of your database queries. You may see details like query execution time, connection details, and more, all within the context of your application’s request flow.
Below is an example of a simple, hypothetical JDBC query that would generate a trace:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JdbcTelemetryDemo {
public static void main(String[] args) throws Exception {
OpenTelemetry openTelemetry = OpenTelemetryConfig.setupOpenTelemetry();
String url = "jdbc:oracle:thin:@<YOUR_DATABASE_URL>";
String username = "<YOUR_DATABASE_USERNAME>";
String password = "<YOUR_DATABASE_PASSWORD>";
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "SELECT * FROM employees WHERE department_id = ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setInt(1, 10);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("employee_name"));
}
}
}
Oracle Database 23ai
To start a database with a lightweight Docker container, go to Oracle Database 23ai Free container image documentation. You can also get it from the Oracle Container Registry instead (my preferred option), and the summarised steps are below.
First, run the docker pull command below (for Windows):
docker pull container-registry.oracle.com/database/free:latest
Now, you can run the docker images command below to confirm that it was pulled properly:

Oracle Database 23ai — container image
Then, run the command below from the Windows Command Prompt (cmd):
docker run -d -p 1521:1521 -e ORACLE_PWD=<your_password> -v oracle-volume:/opt/oracle/oradata container-registry.oracle.com/database/free:latest
Replace <your password> above with your chosen password as required. The command above will run a new persistent database container (data is kept throughout container lifecycles).
If everything goes well, you can run the command docker ps -al to confirm that your container instance is starting as expected.

Please note that the Oracle Database 23ai will be ready to use when the STATUS field shows (healthy), as below.

There are some additional options if you want to configure environment variables to support your connection details, such as username, password, and other variables. You can also check more details about the specific database user (SYS, SYSTEM, PDBADMIN) you may want to use.
If you want to explore such options, please check the official page for the related container image on the Oracle Container Registry (OCIR).
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.
OpenTelemetry’s flexibility and open-source nature, combined with the power of the Oracle JDBC provider, make it an invaluable tool for any Java developer working with Oracle Databases.
Observability is a key factor in maintaining performant and reliable applications. By integrating the Oracle JDBC Open Telemetry Provider, Java developers gain unprecedented visibility into your database interactions. They can easily monitor and trace database interactions, helping them proactively detect and resolve performance issues.
This allows them to identify performance bottlenecks, optimize database queries, and troubleshoot issues with greater efficiency.
This post walked you through the setup and configuration of this powerful tool. Whether you’re troubleshooting queries, tracking latency, or simply gaining better visibility into your application, the Oracle JDBC Open Telemetry Provider ensures you have the insights you need.
Explore the official documentation and OpenTelemetry resources for further details, and start enhancing your application observability today!
That’s it! With OpenTelemetry, you can stay ahead of the curve and ensure your database systems are always running at their best. Start instrumenting your database 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 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!