Skip to content

implementing UCP Observability Providers, JFR and Open telemetry providers to monitor UCP#246

Closed
elaaissaouiabdessamad wants to merge 10 commits intomainfrom
feature/ucp-observability-providers
Closed

implementing UCP Observability Providers, JFR and Open telemetry providers to monitor UCP#246
elaaissaouiabdessamad wants to merge 10 commits intomainfrom
feature/ucp-observability-providers

Conversation

@elaaissaouiabdessamad
Copy link
Copy Markdown
Member

Implementing JFR, OTEL Providers for monitoring UCP.

Add the new module entry so Maven includes it in the multi-module build.
…endencies

Sets up the Maven module with:
- UCP 23.26.1.0.0 as the primary dependency
- OpenTelemetry API 1.44.1 for metric instrumentation
- JUnit 5 and Mockito for unit testing
- Compiler source/target pinned to Java 11 (required for JFR API)
- Surefire configured for sequential, alphabetical test execution
…CPEventFactory, JFRUCPEventListenerProvider)

UCPBaseEvent — abstract JFR Event subclass that captures the common pool
snapshot fields (pool name, sizes, borrowed/available counts, wait time)
from UCPEventContext. All concrete JFR event types extend this class.

UCPEventFactory — static factory that maps every UCPEventListener.EventType
to its concrete JFR event class and calls event.commit(). Unknown event types
are logged at FINE level and silently skipped.

JFRUCPEventListenerProvider — UCPEventListenerProvider implementation
registered under the name "jfr-ucp-listener". Holds a single stateless
listener singleton (TRACE_EVENT_LISTENER) that delegates to UCPEventFactory.
Adds 11 concrete JFR event classes, each extending UCPBaseEvent:

Connection lifecycle (4):
  ConnectionBorrowedEvent  — ucp.ConnectionBorrowed
  ConnectionClosedEvent    — ucp.ConnectionClosed
  ConnectionCreatedEvent   — ucp.ConnectionCreated
  ConnectionReturnedEvent  — ucp.ConnectionReturned

Pool lifecycle (5):
  PoolCreatedEvent         — ucp.PoolCreated
  PoolStartingEvent        — ucp.PoolStarting
  PoolStartedEvent         — ucp.PoolStarted
  PoolStoppedEvent         — ucp.PoolStopped
  PoolDestroyedEvent       — ucp.PoolDestroyed

Maintenance operations (3):
  PoolPurgedEvent          — ucp.PoolPurged
  PoolRecycledEvent        — ucp.PoolRecycled
  PoolRefreshedEvent       — ucp.PoolRefreshed

Every class carries @name, @Label, @description, and @category JFR
annotations to make events discoverable in JDK Mission Control.
OtelUCPEventListenerProvider registers as "otel-ucp-listener" and exposes
UCP connection pool state as OTel metrics following the semantic conventions
for database client connection pools.

Metrics published:
  db.client.connection.usage   (LongGauge, state=used|idle) — live snapshot
  db.client.connection.max     (LongGauge) — max pool size, on lifecycle events
  db.client.connection.idle.min(LongGauge) — min pool size, on lifecycle events
  db.client.connection.wait_time(DoubleHistogram, s) — avg borrow wait, on
    CONNECTION_BORROWED when > 0
  db.client.connection.established (LongGauge) — cumulative connections opened
  db.client.connection.closed      (LongGauge) — cumulative connections closed

Design decisions:
  - OTel instruments are instance fields (not static) so they bind to whichever
    SDK is registered at pool activation time, not at class-load time.
  - Per-pool Attributes objects are cached in a ConcurrentHashMap (PoolState)
    to avoid allocations on high-frequency connection events.
  - POOL_DESTROYED removes the pool's PoolState entry before recording the
    final snapshot, avoiding a computeIfAbsent + immediate remove pattern.
  - Serialization is explicitly blocked: UCPEventListener extends Serializable
    but OTel instruments are not — a clear NotSerializableException is thrown
    rather than an opaque failure.
…oader

Adds META-INF/services/oracle.ucp.events.core.UCPEventListenerProvider so
UCP discovers both providers automatically at runtime without any explicit
registration code:
  - jfr-ucp-listener  (JFRUCPEventListenerProvider)
  - otel-ucp-listener (OtelUCPEventListenerProvider)
Tests cover:
  - Provider name and non-null listener contract
  - isDesiredEvent() returns true for all EventType values
  - UCPEventFactory null-safety (NPE on null type or null context)
  - recordEvent() does not throw for all known EventTypes
  - recordEvent() handles zero/default values and null pool name gracefully
  - onUCPEvent() reads every UCPEventContext field for pool lifecycle,
    connection, and maintenance event categories
Tests cover:
  - Provider name, non-null listener, null config tolerance, singleton contract
  - isDesiredEvent() returns true for all EventType values
  - Null safety: null eventType, null context, both null, null pool name
  - robustness: all EventTypes, zero/default context values
  - Context field access contract:
      · poolName() read exactly once per event
      · borrowedConnectionsCount() / availableConnectionsCount() read on all events
      · maxPoolSize() / minPoolSize() read only on pool lifecycle events,
        NOT on connection or maintenance events
      · getAverageConnectionWaitTime() read only on CONNECTION_BORROWED,
        and recording suppressed when value is 0
      · totalConnections() never read (not used by the OTel provider)
  - Pool state lifecycle: POOL_DESTROYED without prior registration, double
    POOL_DESTROYED, events after destruction
  - NotSerializableException on serialization attempt
  - Multi-pool independence and 8-thread concurrency stress test
…Java 11

The root pom's javac-release profile forces --release 8 for all modules.
This module uses jdk.jfr which requires Java 11+, so both plugins need
an explicit override:
  - maven-compiler-plugin: <release>11</release>
  - maven-javadoc-plugin:  <release>11</release>

Without the javadoc override the plugin inherits --release 8 from the
parent profile's @options file, causing javadoc generation to fail with
"package jdk.jfr does not exist".
@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Apr 1, 2026
@elaaissaouiabdessamad elaaissaouiabdessamad self-assigned this Apr 1, 2026
@elaaissaouiabdessamad elaaissaouiabdessamad deleted the feature/ucp-observability-providers branch April 16, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant