Skip to content

Commit 9cb4b41

Browse files
Implementing JFR, Logging and Open Telemetry providers for monitoring UCP
1 parent 59f3262 commit 9cb4b41

26 files changed

+1480
-4
lines changed

ojdbc-provider-observability/pom.xml

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222

2323
<dependencies>
2424
<dependency>
25-
<groupId>com.oracle.database.jdbc</groupId>
26-
<artifactId>ojdbc11</artifactId>
25+
<groupId>com.oracle</groupId>
26+
<artifactId>ojdbc</artifactId>
27+
<version>11.2.0.4</version> <!-- Change to your version -->
28+
<scope>system</scope>
29+
<systemPath>/Users/abdessamadelaaissaoui/Desktop/ojdbc11.jar</systemPath>
2730
</dependency>
2831
<dependency>
2932
<groupId>io.opentelemetry</groupId>
@@ -51,16 +54,53 @@
5154
<classifier>tests</classifier>
5255
<type>test-jar</type>
5356
</dependency>
57+
<dependency>
58+
<groupId>com.oracle</groupId>
59+
<artifactId>ucp</artifactId>
60+
<version>11.2.0.4</version>
61+
<scope>system</scope>
62+
<systemPath>/Users/abdessamadelaaissaoui/Desktop/ucp11.jar</systemPath>
63+
</dependency>
64+
<dependency>
65+
<groupId>com.oracle.database.security</groupId>
66+
<artifactId>oraclepki</artifactId>
67+
<version>23.3.0.23.09</version>
68+
</dependency>
69+
<dependency>
70+
<groupId>com.oracle.database.ha</groupId>
71+
<artifactId>ons</artifactId>
72+
<version>23.9.0.25.07</version>
73+
</dependency>
74+
<dependency>
75+
<groupId>io.opentelemetry</groupId>
76+
<artifactId>opentelemetry-api</artifactId>
77+
<version>1.32.0</version>
78+
</dependency>
79+
<dependency>
80+
<groupId>io.opentelemetry</groupId>
81+
<artifactId>opentelemetry-sdk</artifactId>
82+
<version>1.32.0</version>
83+
</dependency>
84+
<dependency>
85+
<groupId>io.opentelemetry</groupId>
86+
<artifactId>opentelemetry-exporter-prometheus</artifactId>
87+
<version>1.32.0-alpha</version>
88+
</dependency>
89+
<dependency>
90+
<groupId>io.opentelemetry</groupId>
91+
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
92+
<version>1.32.0</version>
93+
</dependency>
5494
</dependencies>
5595
<build>
5696
<plugins>
5797
<plugin>
5898
<groupId>org.apache.maven.plugins</groupId>
5999
<artifactId>maven-surefire-plugin</artifactId>
60100
<configuration>
61-
<!--
101+
<!--
62102
ObservabilityConfigurationTest must run first and alone since it depends on
63-
ObservabilityConfiguration being started with system properties set on the
103+
ObservabilityConfiguration being started with system properties set on the
64104
test.
65105
Running tests alphabetical and single threaded ensures that.
66106
-->
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Global configuration
2+
global:
3+
scrape_interval: 15s # Scrape targets every 15 seconds
4+
evaluation_interval: 15s # Evaluate rules every 15 seconds
5+
6+
# Scrape configuration
7+
scrape_configs:
8+
# Job to scrape your UCP application
9+
- job_name: 'ucp-application'
10+
static_configs:
11+
- targets: ['localhost:8080'] # Your app's metrics endpoint
12+
scrape_interval: 5s # Scrape every 5 seconds for testing
13+
metrics_path: '/metrics' # Path to metrics endpoint
14+
15+
# Job to scrape Prometheus itself (optional)
16+
- job_name: 'prometheus'
17+
static_configs:
18+
- targets: ['localhost:9091'] # ✅ Changed from 9090 to 9091
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package oracle.ucp.provider.observability.jfr.core;
2+
3+
import oracle.ucp.events.core.UCPEventContext;
4+
import oracle.ucp.events.core.UCPEventListener;
5+
import oracle.ucp.events.core.UCPEventListenerProvider;
6+
7+
import java.util.Map;
8+
9+
/**
10+
* Provider that supplies a UCP event listener for recording JFR events.
11+
* Integrates UCP events with Java Flight Recorder for low-overhead monitoring.
12+
*/
13+
public final class JFRUCPEventListenerProvider implements UCPEventListenerProvider {
14+
15+
private final UCPEventListener listener;
16+
17+
/**
18+
* Singleton listener that records UCP events as JFR events.
19+
* Thread-safe and optimized for minimal overhead.
20+
*/
21+
public static final UCPEventListener TRACE_EVENT_LISTENER = new UCPEventListener() {
22+
@Override
23+
public void onUCPEvent(EventType eventType, UCPEventContext context) {
24+
UCPEventFactory.recordEvent(eventType, context);
25+
}
26+
};
27+
28+
/**
29+
* Creates a new provider instance.
30+
*/
31+
public JFRUCPEventListenerProvider() {
32+
this.listener = TRACE_EVENT_LISTENER;
33+
}
34+
35+
/**
36+
* Returns the provider's unique identifier.
37+
*
38+
* @return "jfr-ucp-listener"
39+
*/
40+
@Override
41+
public String getName() {
42+
return "jfr-ucp-listener";
43+
}
44+
45+
/**
46+
* Returns the JFR recording listener instance.
47+
*
48+
* @param config configuration map (ignored)
49+
* @return the JFR event listener
50+
*/
51+
@Override
52+
public UCPEventListener getListener(Map<String, String> config) {
53+
return listener;
54+
}
55+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package oracle.ucp.provider.observability.jfr.core;
2+
3+
import jdk.jfr.*;
4+
import oracle.ucp.events.core.UCPEventContext;
5+
6+
import java.util.Objects;
7+
8+
/**
9+
* Abstract base class for UCP JFR events providing common fields and initialization.
10+
* All UCP events extend this class to inherit standard pool metrics and metadata.
11+
*/
12+
@Category("UCP Events")
13+
@Description("Base UCP Event")
14+
public abstract class UCPBaseEvent extends Event {
15+
16+
/** Name of the connection pool */
17+
@Label("Pool Name")
18+
protected String poolName;
19+
20+
/** Event timestamp in milliseconds since epoch */
21+
@Label("Timestamp")
22+
protected long timestamp;
23+
24+
/** Maximum configured pool size */
25+
@Label("Max Pool Size")
26+
protected int maxPoolSize;
27+
28+
/** Minimum configured pool size */
29+
@Label("Min Pool Size")
30+
protected int minPoolSize;
31+
32+
/** Current count of borrowed connections */
33+
@Label("Borrowed Connections")
34+
protected int borrowedConnections;
35+
36+
/** Current count of available connections */
37+
@Label("Available Connections")
38+
protected int availableConnections;
39+
40+
/** Total active connections (borrowed + available) */
41+
@Label("Total Connections")
42+
protected int totalConnections;
43+
44+
/** Lifetime count of closed connections */
45+
@Label("Closed Connections")
46+
protected int closedConnections;
47+
48+
/** Lifetime count of created connections */
49+
@Label("Created Connections")
50+
protected int createdConnections;
51+
52+
/** Average connection wait time in milliseconds */
53+
@Label("Average Wait Time (ms)")
54+
@Timespan(Timespan.MILLISECONDS)
55+
protected long avgWaitTime;
56+
57+
/**
58+
* Initializes common fields from UCP event context.
59+
*
60+
* @param ctx event context containing pool metrics
61+
* @throws NullPointerException if ctx is null
62+
*/
63+
protected void initCommonFields(UCPEventContext ctx) {
64+
Objects.requireNonNull(ctx, "UCPEventContext cannot be null");
65+
66+
this.poolName = ctx.poolName();
67+
this.timestamp = ctx.timestamp();
68+
this.maxPoolSize = ctx.maxPoolSize();
69+
this.minPoolSize = ctx.minPoolSize();
70+
this.borrowedConnections = ctx.borrowedConnectionsCount();
71+
this.availableConnections = ctx.availableConnectionsCount();
72+
this.totalConnections = ctx.totalConnections();
73+
this.closedConnections = ctx.closedConnections();
74+
this.createdConnections = ctx.createdConnections();
75+
this.avgWaitTime = ctx.getAverageConnectionWaitTime();
76+
}
77+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package oracle.ucp.provider.observability.jfr.core;
2+
3+
import jdk.jfr.Event;
4+
import oracle.ucp.events.core.UCPEventContext;
5+
import oracle.ucp.events.core.UCPEventListener;
6+
import oracle.ucp.provider.observability.jfr.events.connection.*;
7+
import oracle.ucp.provider.observability.jfr.events.lifecycle.*;
8+
import oracle.ucp.provider.observability.jfr.events.maintenance.*;
9+
10+
/**
11+
* Factory for creating and recording JFR events from UCP operations.
12+
* Maps UCP event types to specific JFR event classes and handles recording.
13+
*/
14+
public class UCPEventFactory {
15+
16+
/**
17+
* Creates a JFR event instance for the specified UCP event type.
18+
*
19+
* @param type UCP event type
20+
* @param ctx event context with pool metrics
21+
* @return configured JFR event ready for recording
22+
* @throws IllegalStateException if event type is unrecognized
23+
* @throws NullPointerException if parameters are null
24+
*/
25+
public static Event createEvent(UCPEventListener.EventType type, UCPEventContext ctx) {
26+
switch (type) {
27+
// Pool Lifecycle Events
28+
case POOL_CREATED:
29+
return new PoolCreatedEvent(ctx);
30+
case POOL_STARTING:
31+
return new PoolStartingEvent(ctx);
32+
case POOL_STARTED:
33+
return new PoolStartedEvent(ctx);
34+
case POOL_STOPPED:
35+
return new PoolStoppedEvent(ctx);
36+
case POOL_RESTARTING:
37+
return new PoolRestartingEvent(ctx);
38+
case POOL_RESTARTED:
39+
return new PoolRestartedEvent(ctx);
40+
case POOL_DESTROYED:
41+
return new PoolDestroyedEvent(ctx);
42+
43+
// Connection Lifecycle Events
44+
case CONNECTION_CREATED:
45+
return new ConnectionCreatedEvent(ctx);
46+
case CONNECTION_BORROWED:
47+
return new ConnectionBorrowedEvent(ctx);
48+
case CONNECTION_RETURNED:
49+
return new ConnectionReturnedEvent(ctx);
50+
case CONNECTION_CLOSED:
51+
return new ConnectionClosedEvent(ctx);
52+
53+
// Maintenance Operations
54+
case POOL_REFRESHED:
55+
return new PoolRefreshedEvent(ctx);
56+
case POOL_RECYCLED:
57+
return new PoolRecycledEvent(ctx);
58+
case POOL_PURGED:
59+
return new PoolPurgedEvent(ctx);
60+
61+
default:
62+
throw new IllegalStateException("Unexpected event type: " + type);
63+
}
64+
}
65+
66+
/**
67+
* Creates and immediately records a JFR event for the UCP operation.
68+
*
69+
* @param type UCP event type to record
70+
* @param ctx event context with pool metrics
71+
* @throws NullPointerException if parameters are null
72+
*/
73+
public static void recordEvent(UCPEventListener.EventType type, UCPEventContext ctx) {
74+
Event event = createEvent(type, ctx);
75+
event.commit();
76+
}
77+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package oracle.ucp.provider.observability.jfr.events.connection;
2+
3+
import oracle.ucp.provider.observability.jfr.core.UCPBaseEvent;
4+
import jdk.jfr.Category;
5+
import jdk.jfr.Label;
6+
import jdk.jfr.Name;
7+
import oracle.ucp.events.core.UCPEventContext;
8+
9+
@Name("ucp.ConnectionBorrowed")
10+
@Label("Connection Borrowed")
11+
@Category({"UCP Events","Connection Lifecycle Events"})
12+
public class ConnectionBorrowedEvent extends UCPBaseEvent {
13+
public ConnectionBorrowedEvent(UCPEventContext ctx) {
14+
initCommonFields(ctx);
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package oracle.ucp.provider.observability.jfr.events.connection;
2+
3+
import jdk.jfr.Category;
4+
import jdk.jfr.Label;
5+
import jdk.jfr.Name;
6+
import oracle.ucp.provider.observability.jfr.core.UCPBaseEvent;
7+
import oracle.ucp.events.core.UCPEventContext;
8+
9+
@Name("ucp.ConnectionClosed")
10+
@Label("Connection Closed")
11+
@Category({"UCP Events","Connection Lifecycle Events"})
12+
public class ConnectionClosedEvent extends UCPBaseEvent {
13+
public ConnectionClosedEvent(UCPEventContext ctx) {
14+
initCommonFields(ctx);
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package oracle.ucp.provider.observability.jfr.events.connection;
2+
3+
import oracle.ucp.provider.observability.jfr.core.UCPBaseEvent;
4+
import jdk.jfr.Category;
5+
import jdk.jfr.Label;
6+
import jdk.jfr.Name;
7+
import oracle.ucp.events.core.UCPEventContext;
8+
9+
@Name("ucp.ConnectionCreated")
10+
@Label("Connection Created")
11+
@Category({"UCP Events","Connection Lifecycle Events"})
12+
public class ConnectionCreatedEvent extends UCPBaseEvent {
13+
public ConnectionCreatedEvent(UCPEventContext ctx) {
14+
initCommonFields(ctx);
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package oracle.ucp.provider.observability.jfr.events.connection;
2+
3+
import oracle.ucp.provider.observability.jfr.core.UCPBaseEvent;
4+
import jdk.jfr.Category;
5+
import jdk.jfr.Label;
6+
import jdk.jfr.Name;
7+
import oracle.ucp.events.core.UCPEventContext;
8+
9+
@Name("ucp.ConnectionReturned")
10+
@Label("Connection Returned")
11+
@Category({"UCP Events","Connection Lifecycle Events"})
12+
public class ConnectionReturnedEvent extends UCPBaseEvent {
13+
public ConnectionReturnedEvent(UCPEventContext ctx) {
14+
initCommonFields(ctx);
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package oracle.ucp.provider.observability.jfr.events.lifecycle;
2+
3+
import oracle.ucp.provider.observability.jfr.core.UCPBaseEvent;
4+
import jdk.jfr.Category;
5+
import jdk.jfr.Description;
6+
import jdk.jfr.Label;
7+
import jdk.jfr.Name;
8+
import oracle.ucp.events.core.UCPEventContext;
9+
10+
@Name("ucp.PoolCreated")
11+
@Label("Pool Created")
12+
@Category({"UCP Events","Pool Lifecycle Events"})
13+
public class PoolCreatedEvent extends UCPBaseEvent {
14+
public PoolCreatedEvent(UCPEventContext ctx) {
15+
initCommonFields(ctx);
16+
}
17+
}

0 commit comments

Comments
 (0)