From 6db2af28b30124b79e9316e89cde0931b6a13d9d Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Thu, 23 Jan 2025 11:41:28 +0100 Subject: [PATCH 01/25] First commit --- ojdbc-provider-observability/pom.xml | 44 +++++ .../ObservabilityTraceEventListener.java | 67 +++++++ ...servabilityTraceEventListenerProvider.java | 71 ++++++++ .../ObservabilityConfiguration.java | 67 +++++++ .../ObservabilityConfigurationMBean.java | 12 ++ .../observability/tracers/JFRTracer.java | 89 ++++++++++ .../observability/tracers/OTelTracer.java | 167 ++++++++++++++++++ .../tracers/ObservabilityTracer.java | 13 ++ pom.xml | 15 ++ 9 files changed, 545 insertions(+) create mode 100644 ojdbc-provider-observability/pom.xml create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml new file mode 100644 index 00000000..2bec1e23 --- /dev/null +++ b/ojdbc-provider-observability/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + com.oracle.database.jdbc + ojdbc-extensions + 1.0.2 + + + com.oracle.database.jdbc + ojdbc-provider-observability + 1.0.2 + + + 1.44.1 + 11 + 11 + + + + + com.oracle.database.jdbc + ojdbc11 + + + io.opentelemetry + opentelemetry-api + ${opentelemetry.version} + + + org.mockito + mockito-core + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + \ No newline at end of file diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java new file mode 100644 index 00000000..d68c7a8a --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -0,0 +1,67 @@ +package oracle.jdbc.provider.observability; + +import java.util.EnumMap; + +import oracle.jdbc.TraceEventListener; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.tracers.JFRTracer; +import oracle.jdbc.provider.observability.tracers.OTelTracer; +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; + +public class ObservabilityTraceEventListener implements TraceEventListener { + + + public enum Tracers { + OTEL(new OTelTracer()), + JFR(new JFRTracer()); + + private ObservabilityTracer tracer; + + Tracers(ObservabilityTracer tracer) { + this.tracer = tracer; + } + + public ObservabilityTracer getTracer() { + return tracer; + } + } + + @Override + public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { + EnumMap currentUserContext = getCurrentUserContext(userContext); + for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + Object newUserContext = tracer.getTracer().traceRoudtrip(sequence, traceContext, currentUserContext.get(tracer)); + currentUserContext.put(tracer, newUserContext); + } + return currentUserContext; + } + + + @Override + public Object onExecutionEventReceived(JdbcExecutionEvent event, Object userContext, Object... params) { + EnumMap currentUserContext = getCurrentUserContext(userContext); + for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext.get(tracer), params); + currentUserContext.put(tracer, newUserContext); + } + return currentUserContext; + } + + @Override + public boolean isDesiredEvent(JdbcExecutionEvent event) { + // Accept all events + return true; + } + + @SuppressWarnings("unchecked") + private EnumMap getCurrentUserContext(Object userContext) { + EnumMap currentUserContext; + if (userContext != null && (userContext instanceof EnumMap)) { + currentUserContext = (EnumMap) userContext; + } else { + currentUserContext = new EnumMap(Tracers.class); + } + return currentUserContext; + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java new file mode 100644 index 00000000..93987b8e --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -0,0 +1,71 @@ +package oracle.jdbc.provider.observability; + +import java.lang.management.ManagementFactory; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import oracle.jdbc.TraceEventListener; +import oracle.jdbc.spi.TraceEventListenerProvider; + +public class ObservabilityTraceEventListenerProvider implements TraceEventListenerProvider { + + private static final String PROVIDER_NAME = "observability-trace-event-listener-provider"; + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.opentelemetry:type=ObservabilityTraceEventListener"; + + private static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; + private static ObjectName objectName; + + Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); + + static { + try { + objectName = new ObjectName(MBEAN_OBJECT_NAME); + } catch (MalformedObjectNameException e) { + objectName = null; + } + } + + @Override + public TraceEventListener getTraceEventListener(Map map) { + ObservabilityTraceEventListener observabilityBean; + try { + if (objectName != null && server.isRegistered(objectName)) { + observabilityBean = (ObservabilityTraceEventListener) server + .instantiate(ObservabilityTraceEventListener.class.getName()); + return observabilityBean; + } + } catch (ReflectionException | MBeanException e) { + logger.log(Level.WARNING, "Could not retrieve MBean from server", e); + } + observabilityBean = new ObservabilityTraceEventListener(); + try { + server.registerMBean(observabilityBean, objectName); + } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { + logger.log(Level.WARNING, "Could not register MBean", e); + } + return observabilityBean; + } + + @Override + public String getName() { + return PROVIDER_NAME; + } + + @Override + public Collection getParameters() { + return Collections.emptyList(); + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java new file mode 100644 index 00000000..8d5be1f4 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -0,0 +1,67 @@ +package oracle.jdbc.provider.observability.configuration; + +import java.util.EnumSet; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; + +public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { + + private final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); + + private static final ObservabilityConfiguration INSTANCE = new ObservabilityConfiguration(); + + private ObservabilityConfiguration() { } + + private boolean sensitiveDataEnabled; + private String tracers; + + private EnumSet enabledTracers; + + @Override + public String getEnabledTracers() { + try { + observabilityConfiguraitonLock.lock(); + return tracers; + } finally { + observabilityConfiguraitonLock.unlock(); + } + } + + @Override + public void setEnabledTracers(String tracers) { + try { + enabledTracers.clear(); + String[] items = tracers.split(","); + for (String item : items) { + if (item != null) { + enabledTracers.add(ObservabilityTraceEventListener.Tracers.valueOf(item.toUpperCase())); + } + } + this.tracers = enabledTracers.stream().map((item) -> item.toString()).collect(Collectors.joining(",")); + } finally { + observabilityConfiguraitonLock.unlock(); + } + + } + + @Override + public boolean getSensitiveDataEnabled() { + return sensitiveDataEnabled; + } + + @Override + public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { + this.sensitiveDataEnabled = sensitiveDataEnabled; + } + + public static ObservabilityConfiguration getInstance() { + return INSTANCE; + } + + public EnumSet getEnabledTracersSet() { + return enabledTracers.clone(); + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java new file mode 100644 index 00000000..3aedf3fc --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java @@ -0,0 +1,12 @@ +package oracle.jdbc.provider.observability.configuration; + +public interface ObservabilityConfigurationMBean { + + public String getEnabledTracers(); + + public void setEnabledTracers(String tracers); + + public boolean getSensitiveDataEnabled(); + + public void setSensitiveDataEnabled(boolean sensitiveDataEnabled); +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java new file mode 100644 index 00000000..4e9736a0 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java @@ -0,0 +1,89 @@ +package oracle.jdbc.provider.observability.tracers; + +import java.util.ArrayList; +import java.util.List; + +import oracle.jdbc.DatabaseFunction; +import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; +import oracle.jdbc.TraceEventListener.Sequence; +import oracle.jdbc.TraceEventListener.TraceContext; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import jdk.jfr.AnnotationElement; +import jdk.jfr.Event; +import jdk.jfr.EventFactory; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.Category; +import jdk.jfr.ValueDescriptor; + +public class JFRTracer implements ObservabilityTracer{ + + public JFRTracer() {} + + @Override + public Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext) { + if (sequence.equals(Sequence.BEFORE)) { + Event event = createEvent( + traceContext.databaseFunction()); + event.begin(); + return event; + } else { + if (userContext != null) { + Event event = (Event) userContext; + event.set(0, traceContext.getConnectionId()); + event.set(1, traceContext.databaseOperation()); + event.set(2, traceContext.tenant()); + event.set(3, traceContext.getSqlId()); + if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + event.set(4, traceContext.originalSqlText()); + event.set(5, traceContext.actualSqlText()); + event.set(6, traceContext.user()); + } + event.end(); + event.commit(); + } + } + return null; + } + + @Override + public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { + return null; + } + + /** + * Creates an event for a given database operation. + * @param databaseFunction The database function originating the round trip. + * @return returns a Java Flight Recorder Event containing the following + * fields: + *
    + *
  • ConnectionID
  • + *
  • DatabaseOperation
  • + *
  • OriginalSqlText
  • + *
  • ActualSqlText
  • + *
  • User
  • + *
+ */ + private static Event createEvent(DatabaseFunction databaseFunction) { + String eventName = "oracle.jdbc.provider.jfr.roundtrip." + databaseFunction.toString(); + List eventAnnotations = new ArrayList(); + eventAnnotations + .add(new AnnotationElement(Name.class, eventName)); + eventAnnotations.add(new AnnotationElement(Label.class, databaseFunction.getDescription())); + eventAnnotations.add(new AnnotationElement(Category.class, new String[] { "Oracle JDBC", "Round trips" })); + + List fields = new ArrayList(); + fields.add(new ValueDescriptor(String.class, "Connection_ID")); + fields.add(new ValueDescriptor(String.class, "Database_operation")); + fields.add(new ValueDescriptor(String.class, "Database_tenant")); + fields.add(new ValueDescriptor(String.class, "SQL_ID")); + fields.add(new ValueDescriptor(String.class, "Original_SQL_text")); + fields.add(new ValueDescriptor(String.class, "Actual_SQL_text")); + fields.add(new ValueDescriptor(String.class, "Database_user")); + + EventFactory f = EventFactory.create(eventAnnotations, fields); + return f.newEvent(); + } + + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java new file mode 100644 index 00000000..5aba96c8 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java @@ -0,0 +1,167 @@ +package oracle.jdbc.provider.observability.tracers; + +import java.sql.SQLException; +import java.time.Instant; +import java.util.EnumMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.security.auth.login.Configuration; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import oracle.jdbc.TraceEventListener; +import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; +import oracle.jdbc.TraceEventListener.Sequence; +import oracle.jdbc.TraceEventListener.TraceContext; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; + +public class OTelTracer implements ObservabilityTracer { + + private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; + + private Tracer tracer; + + // Number of parameters expected for each execution event + private static final Map EXECUTION_EVENTS_PARAMETERS = new EnumMap( + JdbcExecutionEvent.class) { + { + put(JdbcExecutionEvent.AC_REPLAY_STARTED, 3); + put(JdbcExecutionEvent.AC_REPLAY_SUCCESSFUL, 3); + put(JdbcExecutionEvent.VIP_RETRY, 8); + } + }; + + private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); + + @Override + public Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext) { +if (sequence == Sequence.BEFORE) { + // Create the Span before the round-trip. + final Span span = initAndGetSpan(traceContext, traceContext.databaseOperation()); + try (Scope ignored = span.makeCurrent()) { + traceContext.setClientInfo(TRACE_KEY, getTraceValue(span)); + } catch (Exception ex) { + logger.log(Level.WARNING, ex.getMessage(), ex); + } + // Return the Span instance to the driver. The driver holds this instance and + // supplies it + // as user context parameter on the next round-trip call. + return span; + } else { + // End the Span after the round-trip. + if (userContext instanceof Span) { + final Span span = (Span) userContext; + span.setStatus(traceContext.isCompletedExceptionally() ? StatusCode.ERROR : StatusCode.OK); + endSpan(span); + } + return null; + } + } + + @Override + public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { +if (EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + if (event == TraceEventListener.JdbcExecutionEvent.VIP_RETRY) { + SpanBuilder spanBuilder = tracer + .spanBuilder(event.getDescription()) + .setAttribute("Error message", params[0].toString()) + .setAttribute("VIP Address", params[7].toString()); + // Add sensitive information (URL and SQL) if it is enabled + if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + logger.log(Level.FINEST, "Sensitive information on"); + spanBuilder.setAttribute("Protocol", params[1].toString()) + .setAttribute("Host", params[2].toString()) + .setAttribute("Port", params[3].toString()) + .setAttribute("Service name", params[4].toString()) + .setAttribute("SID", params[5].toString()) + .setAttribute("Connection data", params[6].toString()); + } + return spanBuilder.startSpan(); + } else if (event == TraceEventListener.JdbcExecutionEvent.AC_REPLAY_STARTED + || event == TraceEventListener.JdbcExecutionEvent.AC_REPLAY_SUCCESSFUL) { + SpanBuilder spanBuilder = tracer + .spanBuilder(event.getDescription()) + .setAttribute("Error Message", params[0].toString()) + .setAttribute("Error code", ((SQLException) params[1]).getErrorCode()) + .setAttribute("SQL state", ((SQLException) params[1]).getSQLState()) + .setAttribute("Current replay retry count", params[2].toString()); + return spanBuilder.startSpan(); + } else { + logger.log(Level.WARNING, "Unknown event received : " + event.toString()); + } + } else { + // log wrong number of parameters returned for execution event + logger.log(Level.WARNING, "Wrong number of parameters received for event " + event.toString()); + } + return null; + } + + private Span initAndGetSpan(TraceContext traceContext, String spanName) { + /* + * If this is in the context of current span, the following becomes a nested or + * child span to the current span. I.e. the current span in context becomes + * parent to this child span. + */ + SpanBuilder spanBuilder = tracer + .spanBuilder(spanName) + .setAttribute("thread.id", Thread.currentThread().getId()) + .setAttribute("thread.name", Thread.currentThread().getName()) + .setAttribute("Connection ID", traceContext.getConnectionId()) + .setAttribute("Database Operation", traceContext.databaseOperation()) + .setAttribute("Database User", traceContext.user()) + .setAttribute("Database Tenant", traceContext.tenant()) + .setAttribute("SQL ID", traceContext.getSqlId()); + + // Add sensitive information (URL and SQL) if it is enabled + if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + logger.log(Level.FINEST, "Sensitive information on"); + spanBuilder.setAttribute("Original SQL Text", traceContext.originalSqlText()) + .setAttribute("Actual SQL Text", traceContext.actualSqlText()); + } + + // Indicates that the span covers server-side handling of an RPC or other remote + // request. + return spanBuilder.setSpanKind(SpanKind.SERVER).startSpan(); + + } + + private void endSpan(Span span) { + span.end(Instant.now()); + } + + private String getTraceValue(Span span) { + final String traceParent = initAndGetTraceParent(span); + final String traceState = initAndGetTraceState(span); + return traceParent + traceState; + } + + private String initAndGetTraceParent(Span span) { + final SpanContext spanContext = span.getSpanContext(); + // The current specification assumes the version is set to 00. + final String version = "00"; + final String traceId = spanContext.getTraceId(); + // parent-id is known as the span-id + final String parentId = spanContext.getSpanId(); + final String traceFlags = spanContext.getTraceFlags().toString(); + + return String.format("traceparent: %s-%s-%s-%s\r\n", + version, traceId, parentId, traceFlags); + } + + private String initAndGetTraceState(Span span) { + final TraceState traceState = span.getSpanContext().getTraceState(); + final StringBuilder stringBuilder = new StringBuilder(); + + traceState.forEach((k, v) -> stringBuilder.append(k).append("=").append(v)); + return String.format("tracestate: %s\r\n", stringBuilder); + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java new file mode 100644 index 00000000..54e07c72 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java @@ -0,0 +1,13 @@ +package oracle.jdbc.provider.observability.tracers; + +import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; +import oracle.jdbc.TraceEventListener.Sequence; +import oracle.jdbc.TraceEventListener.TraceContext; + +public interface ObservabilityTracer { + + Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext); + + Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params); + +} diff --git a/pom.xml b/pom.xml index 7a26317b..f51eda68 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,15 @@ 8 + + javac-release-jfr + + [9,) + + + 11 + + @@ -62,6 +71,7 @@ ojdbc-provider-samples ojdbc-provider-opentelemetry ojdbc-provider-jackson-oson + ojdbc-provider-observability @@ -76,6 +86,11 @@ ojdbc8 ${jdbc.version} + + com.oracle.database.jdbc + ojdbc11 + ${jdbc.version} + com.oracle.database.security oraclepki From cf6b82af399f660de8d756117fefe85a43caad22 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 3 Feb 2025 13:47:01 +0100 Subject: [PATCH 02/25] Added static Events and tests --- .github/workflows/run-tests.yaml | 7 + .../example-test.properties | 86 ++ ojdbc-provider-observability/pom.xml | 12 + .../ObservabilityTraceEventListener.java | 2 +- ...servabilityTraceEventListenerProvider.java | 19 +- ...enTelemetryTraceEventListenerProvider.java | 20 + .../ObservabilityConfiguration.java | 19 +- .../tracers/JFREventFactory.java | 866 ++++++++++++++++++ .../observability/tracers/JFRTracer.java | 34 +- .../observability/tracers/OTelTracer.java | 10 +- .../tracers/ObservabilityTracer.java | 2 +- ...oracle.jdbc.spi.TraceEventListenerProvider | 2 + .../ObservabilityTestProperties.java | 7 + .../ObservabilityTraceEventListenerTest.java | 189 ++++ 14 files changed, 1228 insertions(+), 47 deletions(-) create mode 100644 ojdbc-provider-observability/example-test.properties create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java create mode 100644 ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider create mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java create mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 2150346b..ffaaedf7 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -119,6 +119,12 @@ jobs: JACKSON_OSON_PASSWORD=${{ secrets.TEST_JACKSON_OSON_PASSWORD }}\n " >> ojdbc-provider-jackson-oson/test.properties + # Generate ojdbc-provider-observability/test.properties + echo -e "OBSERVABILITY_URL=${{ secrets.TEST_JACKSON_OSON_URL }}\n + OBSERVABILITY_USERNAME=${{ secrets.TEST_JACKSON_OSON_USERNAME }}\n + OBSERVABILITY_PASSWORD=${{ secrets.TEST_JACKSON_OSON_PASSWORD }}\n + " >> ojdbc-provider-observability/test.properties + - name: Run tests with Maven run: mvn -B test --file pom.xml @@ -133,3 +139,4 @@ jobs: rm ojdbc-provider-azure/test.properties rm ojdbc-provider-jackson-oson/test.properties + rm ojdbc-provider-observability/test.properties diff --git a/ojdbc-provider-observability/example-test.properties b/ojdbc-provider-observability/example-test.properties new file mode 100644 index 00000000..feafff3b --- /dev/null +++ b/ojdbc-provider-observability/example-test.properties @@ -0,0 +1,86 @@ +################################################################################ +# Copyright (c) 2024 Oracle and/or its affiliates. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or data +# (collectively the "Software"), free of charge and under any and all copyright +# rights in the Software, and any and all patent rights owned or freely +# licensable by each licensor hereunder covering either (i) the unmodified +# Software as contributed to or provided by such licensor, or (ii) the Larger +# Works (as defined below), to deal in both +# +# (a) the Software, and +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software (each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# The above copyright notice and either this complete permission notice or at +# a minimum a reference to the UPL must be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +################################################################################ + +# This file provides examples of properties that configure tests in this +# module. +# +# QUICK GUIDE TO RUNNING TESTS: +# 1. Create a copy of this file named "test.properties": +# cp example-test.properties test.properties +# 2. In test.properties, replace example values with real values (the file is +# .gitignore'd, so sensitive info won't be checked in to the repo) +# 3. Comment out any lines for which a value can not be provided (tests are +# skipped if no value is configured). +# 4. mvn clean verify +# +# CONFIGURING TEST PROPERTIES +# Test properties are read from a properties file by the TestProperties class. +# The TestProperties class can be found in: +# ojdbc-provider-common/src/testFixtures/java/oracle/jdbc/provider/TestProperties.java +# The default behavior of TestProperties is to read a file named +# "test.properties" in the current directory. A non-default location may be +# specified as a JVM system property: +# mvn clean verify -Doracle.jdbc.provider.TestProperties=/path/to/my-test.properties +# +# MAINTAINING THIS FILE +# Project maintainers should add an example to this file anytime they write a +# test which requires a new property. Not doing so will inflict pain and +# suffering upon our fellow programmers, and will also lead to increased +# maintenance costs. +# +# IGNORING UNCONFIGURED PROPERTIES +# No test should cause a build failure due to an unconfigured property. +# Using JUnit terminology: A test should "abort" rather than "fail" when a +# property is not configured. This means that the test does not pass, but it +# does not cause the build to fail either. +# Methods of the TestProperties class will automatically abort a test if a +# property is not configured. The org.junit.jupiter.api.Assumptions class may +# also be used directly to abort a test. +# There is NO environment in which ALL tests can be run. Some tests may +# require authentication as a managed identity in an Azure VM, while other +# tests require authentication as an instance principal in an OCI compute +# instance; These environments are mutually exclusive. This is one reason why +# tests can not fail the build if a required property is not set. +# A more practical reason is that developers may not need to run all tests if +# their changes are isolated to single module. For instance, a developer +# working on an OCI provider should not need to set up an Azure tenancy to test +# their changes. + +OBSERVABILITY_URL= +OBSERVABILITY_USERNAME= +OBSERVABILITY_PASSWORD= diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index 2bec1e23..4b90faad 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -39,6 +39,18 @@ junit-jupiter-engine test + + org.junit.jupiter + junit-jupiter-params + test + + + ojdbc-provider-common + com.oracle.database.jdbc + 1.0.2 + tests + test-jar + \ No newline at end of file diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index d68c7a8a..b371c4b0 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -30,7 +30,7 @@ public ObservabilityTracer getTracer() { public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { EnumMap currentUserContext = getCurrentUserContext(userContext); for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { - Object newUserContext = tracer.getTracer().traceRoudtrip(sequence, traceContext, currentUserContext.get(tracer)); + Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext.get(tracer)); currentUserContext.put(tracer, newUserContext); } return currentUserContext; diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 93987b8e..8ea1163f 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -17,12 +17,13 @@ import javax.management.ReflectionException; import oracle.jdbc.TraceEventListener; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; import oracle.jdbc.spi.TraceEventListenerProvider; public class ObservabilityTraceEventListenerProvider implements TraceEventListenerProvider { private static final String PROVIDER_NAME = "observability-trace-event-listener-provider"; - private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.opentelemetry:type=ObservabilityTraceEventListener"; + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.observability:type=ObservabilityConfiguration"; private static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; private static ObjectName objectName; @@ -39,23 +40,13 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen @Override public TraceEventListener getTraceEventListener(Map map) { - ObservabilityTraceEventListener observabilityBean; try { - if (objectName != null && server.isRegistered(objectName)) { - observabilityBean = (ObservabilityTraceEventListener) server - .instantiate(ObservabilityTraceEventListener.class.getName()); - return observabilityBean; - } - } catch (ReflectionException | MBeanException e) { - logger.log(Level.WARNING, "Could not retrieve MBean from server", e); - } - observabilityBean = new ObservabilityTraceEventListener(); - try { - server.registerMBean(observabilityBean, objectName); + if (!server.isRegistered(objectName)) + server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { logger.log(Level.WARNING, "Could not register MBean", e); } - return observabilityBean; + return new ObservabilityTraceEventListener(); } @Override diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java new file mode 100644 index 00000000..649ef25d --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java @@ -0,0 +1,20 @@ +package oracle.jdbc.provider.observability; + +import java.util.Collection; +import java.util.Collections; + +public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceEventListenerProvider { + + private static final String PROVIDER_NAME = "open-telemetry-trace-event-listener-provider"; + + @Override + public String getName() { + return PROVIDER_NAME; + } + + @Override + public Collection getParameters() { + return Collections.emptyList(); + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index 8d5be1f4..e0404fe2 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -8,16 +8,22 @@ public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { - private final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); + private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); - private static final ObservabilityConfiguration INSTANCE = new ObservabilityConfiguration(); + private static final ObservabilityConfiguration INSTANCE; + + static { + INSTANCE = new ObservabilityConfiguration(); + //INSTANCE.setSensitiveDataEnabled(true); + INSTANCE.setEnabledTracers(System.getProperty("oracle.jdbc.provider.observability.tracer", "OTEL,JFR")); + } private ObservabilityConfiguration() { } private boolean sensitiveDataEnabled; private String tracers; - private EnumSet enabledTracers; + private EnumSet enabledTracers = EnumSet.noneOf(ObservabilityTraceEventListener.Tracers.class); @Override public String getEnabledTracers() { @@ -32,6 +38,7 @@ public String getEnabledTracers() { @Override public void setEnabledTracers(String tracers) { try { + observabilityConfiguraitonLock.lock(); enabledTracers.clear(); String[] items = tracers.split(","); for (String item : items) { @@ -61,7 +68,11 @@ public static ObservabilityConfiguration getInstance() { } public EnumSet getEnabledTracersSet() { - return enabledTracers.clone(); + if (enabledTracers != null) { + return enabledTracers.clone(); + } else { + return null; + } } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java new file mode 100644 index 00000000..3c2f0551 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java @@ -0,0 +1,866 @@ +package oracle.jdbc.provider.observability.tracers; + +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.Category; +import oracle.jdbc.TraceEventListener.TraceContext; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; + +public class JFREventFactory { + + public static RoundTripEvent createJFREvent(TraceContext traceContext) { + switch (traceContext.databaseFunction()) { + case ADVANCED_QUEUING_12C_EMON_DEQUEUE: + return new AdvancedQueuing12cEminDequeueEvent(traceContext); + case ADVANCED_QUEUING_ARRAY_ENQUEUE_DEQUEUE: + return new AdvancedQueuingArrayEnqueueDequeue(traceContext); + case ADVANCED_QUEUING_DEQUEUE_V8: + return new AdvancedQueuingDequeueV8(traceContext); + case ADVANCED_QUEUING_ENQUEUE: + return new AdvancedQueuingEnqueue(traceContext); + case ADVANCED_QUEUING_GET_PROPAGATION_STATUS: + return new AdvancedQueuingGetPropagationStatus(traceContext); + case ADVANCED_QUEUING_LISTEN: + return new AdvancedQueuingListen(traceContext); + case ADVANCED_QUEUING_SESSION_GET_RPC_1: + return new AdvancedQueuingSessionGetRPC1(traceContext); + case ADVANCED_QUEUING_SESSION_GET_RPC_2: + return new AdvancedQueuingSessionGetRPC2(traceContext); + case ADVANCED_QUEUING_SHARED_DEQUEUE: + return new AdvancedQueuingSharedDequeue(traceContext); + case ADVANCED_QUEUING_SHARED_ENQUEUE: + return new AdvancedQueuingSharedEnqueue(traceContext); + case APP_REPLAY: + return new AppReplay(traceContext); + case AUTH_CALL: + return new AuthCall(traceContext); + case AUTO_COMMIT_OFF: + return new AutoCommitOff(traceContext); + case AUTO_COMMIT_ON: + return new AutoCommitOn(traceContext); + case CANCEL_ALL: + return new CancelAll(traceContext); + case CANCEL_OPERATION: + return new CancelOperation(traceContext); + case CHUNCK_INFO: + return new ChunkInfo(traceContext); + case CLIENT_FEATURES: + return new ClientFeatures(traceContext); + case CLIENT_QUERY_CACHE_IDS: + return new ClientQueryCacheIds(traceContext); + case CLIENT_QUERY_CACHE_STATS_UPDATE: + return new ClientQueryCacheStatsUpdate(traceContext); + case CLOSE_ALL_CURSOR: + return new CloseAllCursor(traceContext); + case CLOSE_CURSOR: + return new CloseCursor(traceContext); + case COMMIT: + return new Commit(traceContext); + case DB12C_NOTIFICATION_RCV: + return new DB12cNotificationRCV(traceContext); + case DBNS_SAGAS: + return new DBNSSagas(traceContext); + case DESCRIBE_ANY_V8: + return new DescribeAnyV8(traceContext); + case DESCRIBE_ARRAY: + return new DescribeArray(traceContext); + case DESCRIBE_QUERY_CALL: + return new DescribeQueryCall(traceContext); + case DIRECT_PATH_LOAD_STREAM: + return new DirectPathLoadStream(traceContext); + case DIRECT_PATH_MISC_OP: + return new DirectPathMISCOp(traceContext); + case DIRECT_PATH_PREPARE: + return new DirectPathPrepare(traceContext); + case DISTRIBUTED_TRANS_MGR_RPC: + return new DistributedTransMGRRPC(traceContext); + case EXECUTE_QUERY: + return new ExecuteQuery(traceContext); + case EXTENSIBLE_SECURITY_SESSION_CREATE: + return new ExtensibleSecuritySessionCreate(traceContext); + case EXTENSIBLE_SECURITY_SESSION_PIGGYBACK: + return new ExtensibleSecuritySessionPiggyback(traceContext); + case EXTENSIBLE_SECURITY_SESSION_ROUNDTRIP: + return new ExtensibleSecuritySessionRoundtrip(traceContext); + case FAST_UPI_CALLS: + return new FastUPICalls(traceContext); + case FETCH_ROW: + return new FetchRow(traceContext); + case GET_VERSION: + return new GetVersion(traceContext); + case KERNEL_PROGRAMMATIC_NOTIFICATION: + return new KernelProgrammaticNotification(traceContext); + case KEY_VALUE: + return new KeyValue(traceContext); + case LOB_FILE_CALL: + return new LOBFileCall(traceContext); + case LOGOFF: + return new LogOff(traceContext); + case LOGON_CHALLENGE_RESPONSE_1: + return new LogonChallengeResponse1(traceContext); + case LOGON_CHALLENGE_RESPONSE_2: + return new LogonChallengeResponse2(traceContext); + case OEXFEN: + return new OEXFEN(traceContext); + case OPEN_CURSOR: + return new OpenCursor(traceContext); + case OSQL7: + return new OSQL7(traceContext); + case OSTART: + return new OStart(traceContext); + case OSTOP: + return new OStop(traceContext); + case PARAMETER_PUT_SPFILE: + return new ParameterPutSPFile(traceContext); + case PING: + return new Ping(traceContext); + case PIPELINE_END: + return new PipelineEnd(traceContext); + case PIPELINE_PIGGYBACK_BEGIN: + return new PipelinePiggybackBegin(traceContext); + case PIPELINE_PIGGYBACK_OP: + return new PipelinePiggybackOp(traceContext); + case ROLLBACK: + return new Rollback(traceContext); + case SESSION_KEY: + return new SessionKey(traceContext); + case SESSION_STATE_OPS: + return new SessionStateOps(traceContext); + case SESSION_STATE_TEMPLATE: + return new SessionStateTemplate(traceContext); + case SESSION_SWITCH_V8: + return new SessionSwitchV8(traceContext); + case TRACING_MESSAGE: + return new TracingMessage(traceContext); + case TRANSACTION_COMMIT: + return new TransactionCommit(traceContext); + case TRANSACTION_START: + return new TransactionStart(traceContext); + case TTC_DTY_ROUNDTRIP: + return new TTCDTYRoundtrip(traceContext); + case TTC_PRO_ROUNDTRIP: + return new TTCPRORoundtrip(traceContext); + case XS_ATTACH_SESSION: + return new XSAttachSession(traceContext); + case XS_CREATE_SESSION: + return new XSCreateSession(traceContext); + case XS_DESTROY_SESSION: + return new XSDestroySession(traceContext); + case XS_DETACH_SESSION: + return new XSDetachSession(traceContext); + case XS_NAMESPACE_OP: + return new XSNamespaceOp(traceContext); + case XS_NAMESPACE_OPS: + return new XSNamespaceOps(traceContext); + case XS_SET_SESSION_PARAMETER: + return new XSSetSessionParameter(traceContext); + case XS_STATE_SYNC_OP: + return new XSStateSyncOp(traceContext); + default: + return new RoundTripEvent(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_12C_EMON_DEQUEUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuing12cEminDequeueEvent extends RoundTripEvent{ + public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_ARRAY_ENQUEUE_DEQUEUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingArrayEnqueueDequeue extends RoundTripEvent{ + public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_DEQUEUE_V8") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingDequeueV8 extends RoundTripEvent{ + public AdvancedQueuingDequeueV8(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_ENQUEUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingEnqueue extends RoundTripEvent{ + public AdvancedQueuingEnqueue(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_GET_PROPAGATION_STATUS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingGetPropagationStatus extends RoundTripEvent{ + public AdvancedQueuingGetPropagationStatus(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_LISTEN") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingListen extends RoundTripEvent{ + public AdvancedQueuingListen(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SESSION_GET_RPC_1") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingSessionGetRPC1 extends RoundTripEvent{ + public AdvancedQueuingSessionGetRPC1(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SESSION_GET_RPC_2") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingSessionGetRPC2 extends RoundTripEvent{ + public AdvancedQueuingSessionGetRPC2(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SHARED_DEQUEUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingSharedDequeue extends RoundTripEvent{ + public AdvancedQueuingSharedDequeue(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SHARED_ENQUEUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AdvancedQueuingSharedEnqueue extends RoundTripEvent{ + public AdvancedQueuingSharedEnqueue(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.APP_REPLAY") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AppReplay extends RoundTripEvent{ + public AppReplay(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.AUTH_CALL") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AuthCall extends RoundTripEvent{ + public AuthCall(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.AUTO_COMMIT_OFF") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AutoCommitOff extends RoundTripEvent{ + public AutoCommitOff(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.AUTO_COMMIT_ON") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class AutoCommitOn extends RoundTripEvent{ + public AutoCommitOn(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CANCEL_ALL") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class CancelAll extends RoundTripEvent{ + public CancelAll(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CANCEL_OPERATION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class CancelOperation extends RoundTripEvent{ + public CancelOperation(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CHUNCK_INFO") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ChunkInfo extends RoundTripEvent{ + public ChunkInfo(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_FEATURES") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ClientFeatures extends RoundTripEvent{ + public ClientFeatures(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_QUERY_CACHE_IDS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ClientQueryCacheIds extends RoundTripEvent{ + public ClientQueryCacheIds(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_QUERY_CACHE_STATS_UPDATE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ClientQueryCacheStatsUpdate extends RoundTripEvent{ + public ClientQueryCacheStatsUpdate(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CLOSE_ALL_CURSOR") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class CloseAllCursor extends RoundTripEvent{ + public CloseAllCursor(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.CLOSE_CURSOR") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class CloseCursor extends RoundTripEvent{ + public CloseCursor(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.COMMIT") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class Commit extends RoundTripEvent{ + public Commit(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DB12C_NOTIFICATION_RCV") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DB12cNotificationRCV extends RoundTripEvent{ + public DB12cNotificationRCV(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DBNS_SAGAS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DBNSSagas extends RoundTripEvent{ + public DBNSSagas(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_ANY_V8") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DescribeAnyV8 extends RoundTripEvent{ + public DescribeAnyV8(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_ARRAY") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DescribeArray extends RoundTripEvent{ + public DescribeArray(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_QUERY_CALL") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DescribeQueryCall extends RoundTripEvent{ + public DescribeQueryCall(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_LOAD_STREAM") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DirectPathLoadStream extends RoundTripEvent{ + public DirectPathLoadStream(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_MISC_OP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DirectPathMISCOp extends RoundTripEvent{ + public DirectPathMISCOp(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_PREPARE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DirectPathPrepare extends RoundTripEvent{ + public DirectPathPrepare(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.DISTRIBUTED_TRANS_MGR_RPC") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class DistributedTransMGRRPC extends RoundTripEvent{ + public DistributedTransMGRRPC(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.EXECUTE_QUERY") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ExecuteQuery extends RoundTripEvent{ + public ExecuteQuery(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_CREATE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ExtensibleSecuritySessionCreate extends RoundTripEvent{ + public ExtensibleSecuritySessionCreate(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_PIGGYBACK") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ExtensibleSecuritySessionPiggyback extends RoundTripEvent{ + public ExtensibleSecuritySessionPiggyback(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_ROUNDTRIP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ExtensibleSecuritySessionRoundtrip extends RoundTripEvent{ + public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.FAST_UPI_CALLS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class FastUPICalls extends RoundTripEvent{ + public FastUPICalls(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.FETCH_ROW") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class FetchRow extends RoundTripEvent{ + public FetchRow(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.GET_VERSION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class GetVersion extends RoundTripEvent{ + public GetVersion(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.KERNEL_PROGRAMMATIC_NOTIFICATION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class KernelProgrammaticNotification extends RoundTripEvent{ + public KernelProgrammaticNotification(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.KEY_VALUE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class KeyValue extends RoundTripEvent{ + public KeyValue(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.LOB_FILE_CALL") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class LOBFileCall extends RoundTripEvent{ + public LOBFileCall(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.LOGOFF") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class LogOff extends RoundTripEvent{ + public LogOff(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.LOGON_CHALLENGE_RESPONSE_1") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class LogonChallengeResponse1 extends RoundTripEvent{ + public LogonChallengeResponse1(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.LOGON_CHALLENGE_RESPONSE_2") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class LogonChallengeResponse2 extends RoundTripEvent{ + public LogonChallengeResponse2(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.OEXFEN") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class OEXFEN extends RoundTripEvent{ + public OEXFEN(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.OPEN_CURSOR") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class OpenCursor extends RoundTripEvent{ + public OpenCursor(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.OSQL7") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class OSQL7 extends RoundTripEvent{ + public OSQL7(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.OSTART") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class OStart extends RoundTripEvent{ + public OStart(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.OSTOP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class OStop extends RoundTripEvent{ + public OStop(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.PARAMETER_PUT_SPFILE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class ParameterPutSPFile extends RoundTripEvent{ + public ParameterPutSPFile(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.PING") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class Ping extends RoundTripEvent{ + public Ping(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_END") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class PipelineEnd extends RoundTripEvent{ + public PipelineEnd(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_PIGGYBACK_BEGIN") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class PipelinePiggybackBegin extends RoundTripEvent{ + public PipelinePiggybackBegin(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_PIGGYBACK_OP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class PipelinePiggybackOp extends RoundTripEvent{ + public PipelinePiggybackOp(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.ROLLBACK") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class Rollback extends RoundTripEvent{ + public Rollback(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_KEY") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class SessionKey extends RoundTripEvent{ + public SessionKey(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_STATE_OPS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class SessionStateOps extends RoundTripEvent{ + public SessionStateOps(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_STATE_TEMPLATE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class SessionStateTemplate extends RoundTripEvent{ + public SessionStateTemplate(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_SWITCH_V8") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class SessionSwitchV8 extends RoundTripEvent{ + public SessionSwitchV8(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.TRACING_MESSAGE") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class TracingMessage extends RoundTripEvent{ + public TracingMessage(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.TRANSACTION_COMMIT") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class TransactionCommit extends RoundTripEvent{ + public TransactionCommit(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.TRANSACTION_START") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class TransactionStart extends RoundTripEvent{ + public TransactionStart(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.TTC_DTY_ROUNDTRIP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class TTCDTYRoundtrip extends RoundTripEvent{ + public TTCDTYRoundtrip(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.TTC_PRO_ROUNDTRIP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class TTCPRORoundtrip extends RoundTripEvent{ + public TTCPRORoundtrip(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_ATTACH_SESSION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSAttachSession extends RoundTripEvent{ + public XSAttachSession(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_CREATE_SESSION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSCreateSession extends RoundTripEvent{ + public XSCreateSession(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_DESTROY_SESSION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSDestroySession extends RoundTripEvent{ + public XSDestroySession(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_DETACH_SESSION") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSDetachSession extends RoundTripEvent{ + public XSDetachSession(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_NAMESPACE_OP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSNamespaceOp extends RoundTripEvent{ + public XSNamespaceOp(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_NAMESPACE_OPS") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSNamespaceOps extends RoundTripEvent{ + public XSNamespaceOps(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_SET_SESSION_PARAMETER") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSSetSessionParameter extends RoundTripEvent{ + public XSSetSessionParameter(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip.XS_STATE_SYNC_OP") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class XSStateSyncOp extends RoundTripEvent{ + public XSStateSyncOp(TraceContext traceContext) { + super(traceContext); + } + } + + @Name("oracle.jdbc.provider.observability.RoundTrip") + @Label("Round trip") + @Category({"Oracle JDBC", "Round trips"}) + static class RoundTripEvent extends Event { + + public RoundTripEvent(TraceContext traceContext) { + setValues(traceContext); + } + + public void setValues(TraceContext traceContext) { + this.connectionID = traceContext.getConnectionId(); + this.databaseOperation = traceContext.databaseOperation(); + this.tenant = traceContext.tenant(); + this.sqlID = traceContext.getSqlId(); + if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + this.originalSQLText = traceContext.originalSqlText(); + this.actualSQLText = traceContext.actualSqlText(); + this.databaseUser = traceContext.user(); + } + } + + @Label("Connection ID") + String connectionID; + + @Label("Database operation") + String databaseOperation; + + @Label("Database tenant") + String tenant; + + @Label("SQL ID") + String sqlID; + + @Label("Original SQL text") + String originalSQLText; + + @Label("Actual SQL text") + String actualSQLText; + + @Label("Database user") + String databaseUser; + + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java index 4e9736a0..68347ac8 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java @@ -1,44 +1,24 @@ package oracle.jdbc.provider.observability.tracers; -import java.util.ArrayList; -import java.util.List; - -import oracle.jdbc.DatabaseFunction; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import jdk.jfr.AnnotationElement; -import jdk.jfr.Event; -import jdk.jfr.EventFactory; -import jdk.jfr.Label; -import jdk.jfr.Name; -import jdk.jfr.Category; -import jdk.jfr.ValueDescriptor; +import oracle.jdbc.provider.observability.tracers.JFREventFactory.RoundTripEvent; public class JFRTracer implements ObservabilityTracer{ public JFRTracer() {} @Override - public Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext) { + public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { if (sequence.equals(Sequence.BEFORE)) { - Event event = createEvent( - traceContext.databaseFunction()); + RoundTripEvent event = JFREventFactory.createJFREvent(traceContext); event.begin(); return event; } else { if (userContext != null) { - Event event = (Event) userContext; - event.set(0, traceContext.getConnectionId()); - event.set(1, traceContext.databaseOperation()); - event.set(2, traceContext.tenant()); - event.set(3, traceContext.getSqlId()); - if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { - event.set(4, traceContext.originalSqlText()); - event.set(5, traceContext.actualSqlText()); - event.set(6, traceContext.user()); - } + RoundTripEvent event = (RoundTripEvent) userContext; + event.setValues(traceContext); event.end(); event.commit(); } @@ -51,7 +31,7 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, return null; } - /** + /** * Creates an event for a given database operation. * @param databaseFunction The database function originating the round trip. * @return returns a Java Flight Recorder Event containing the following @@ -64,6 +44,7 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, *
  • User
  • * */ + /* private static Event createEvent(DatabaseFunction databaseFunction) { String eventName = "oracle.jdbc.provider.jfr.roundtrip." + databaseFunction.toString(); List eventAnnotations = new ArrayList(); @@ -84,6 +65,7 @@ private static Event createEvent(DatabaseFunction databaseFunction) { EventFactory f = EventFactory.create(eventAnnotations, fields); return f.newEvent(); } +*/ } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java index 5aba96c8..9bbdafa8 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java @@ -9,6 +9,7 @@ import javax.security.auth.login.Configuration; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; @@ -29,6 +30,13 @@ public class OTelTracer implements ObservabilityTracer { private Tracer tracer; + public OTelTracer() { + this(GlobalOpenTelemetry.get().getTracer(OTelTracer.class.getName())); + } + + public OTelTracer(Tracer tracer) { + this.tracer = tracer; + } // Number of parameters expected for each execution event private static final Map EXECUTION_EVENTS_PARAMETERS = new EnumMap( JdbcExecutionEvent.class) { @@ -42,7 +50,7 @@ public class OTelTracer implements ObservabilityTracer { private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); @Override - public Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext) { + public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { if (sequence == Sequence.BEFORE) { // Create the Span before the round-trip. final Span span = initAndGetSpan(traceContext, traceContext.databaseOperation()); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java index 54e07c72..98f9218a 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java @@ -6,7 +6,7 @@ public interface ObservabilityTracer { - Object traceRoudtrip(Sequence sequence, TraceContext traceContext, Object userContext); + Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext); Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params); diff --git a/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider new file mode 100644 index 00000000..b1c86eef --- /dev/null +++ b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider @@ -0,0 +1,2 @@ +oracle.jdbc.provider.observability.ObservabilityTraceEventListenerProvider +oracle.jdbc.provider.observability.OpenTelemetryTraceEventListenerProvider \ No newline at end of file diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java new file mode 100644 index 00000000..d2e58eda --- /dev/null +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java @@ -0,0 +1,7 @@ +package oracle.jdbc.provider.observability; + +public enum ObservabilityTestProperties { + OBSERVABILITY_URL, + OBSERVABILITY_USERNAME, + OBSERVABILITY_PASSWORD +} diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java new file mode 100644 index 00000000..b598908f --- /dev/null +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -0,0 +1,189 @@ +package oracle.jdbc.provider.observability; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.atLeastOnce; + +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mockito; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.metrics.MeterBuilder; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; +import jdk.jfr.Configuration; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import oracle.jdbc.DatabaseFunction; +import oracle.jdbc.provider.TestProperties; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; + +public class ObservabilityTraceEventListenerTest { + String url = TestProperties.getOrAbort(ObservabilityTestProperties.OBSERVABILITY_URL); + String userName = TestProperties.getOrAbort(ObservabilityTestProperties.OBSERVABILITY_USERNAME); + String password = TestProperties.getOrAbort(ObservabilityTestProperties.OBSERVABILITY_PASSWORD); + + // JFR + private static final String SESSION_KEY = "oracle.jdbc.provider.observability.RoundTrip.SESSION_KEY"; + private static final String AUTH_CALL = "oracle.jdbc.provider.observability.RoundTrip.AUTH_CALL"; + private static final String EXECUTE_QUERY = "oracle.jdbc.provider.observability.RoundTrip.EXECUTE_QUERY"; + private static final String LOGOFF = "oracle.jdbc.provider.observability.RoundTrip.LOGOFF"; + + // OTEL + private static final OpenTelemetry openTelemetry = Mockito.mock(OpenTelemetry.class); + private static final Span span = Mockito.mock(Span.class); + private static final SpanContext spanContext = Mockito.mock(SpanContext.class); + private static final TraceFlags traceFlags = Mockito.mock(TraceFlags.class); + private static final TraceState traceState = Mockito.mock(TraceState.class); + private static final SpanBuilder spanBuilder = Mockito.mock(SpanBuilder.class); + private static final TracerProvider tracerProvider = Mockito.mock(TracerProvider.class); + private static final Tracer tracer = Mockito.mock(Tracer.class); + private static final MeterBuilder meterBuilder = Mockito.mock(MeterBuilder.class); + + static { + GlobalOpenTelemetry.set(openTelemetry); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { + + ObservabilityConfiguration.getInstance().setEnabledTracers("JFR"); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); + Configuration configuration = Configuration.getConfiguration("default"); + try (Recording recording = new Recording(configuration)) { + recording.start(); + try (Connection connection = DriverManager.getConnection(url, userName, password); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { + while (resultSet.next()) { + System.out.println(resultSet.getString(1)); + } + } + recording.stop(); + recording.dump(Path.of("dump" + sensitiveDataEnabled + ".jfr")); + + try (RecordingFile recordingFile = new RecordingFile(Path.of("dump" + sensitiveDataEnabled + ".jfr"))) { + while (recordingFile.hasMoreEvents()) { + RecordedEvent event = recordingFile.readEvent(); + if (event.getEventType().getCategoryNames().contains("Round trips")) { + switch (event.getEventType().getName()) { + case SESSION_KEY: + assertNotNull(event.getString("connectionID")); + assertNotNull(event.getString("databaseOperation")); +// assertNull(event.getString("tenant")); + assertNull(event.getString("sqlID")); + assertNull(event.getString("originalSQLText")); + assertNull(event.getString("actualSQLText")); + assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); + break; + case AUTH_CALL: + assertNotNull(event.getString("connectionID")); + assertNotNull(event.getString("databaseOperation")); +// assertNull(event.getString("tenant")); + assertNull(event.getString("sqlID")); + assertNull(event.getString("originalSQLText")); + assertNull(event.getString("actualSQLText")); + assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); + + break; + case EXECUTE_QUERY: + assertNotNull(event.getString("connectionID")); + assertNotNull(event.getString("databaseOperation")); +// assertNotNull(event.getString("tenant")); + assertNotNull(event.getString("sqlID")); + assertEquals(sensitiveDataEnabled, event.getString("originalSQLText") != null); + assertEquals(sensitiveDataEnabled, event.getString("actualSQLText") != null); + assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); + break; + case LOGOFF: + assertNotNull(event.getString("connectionID")); + assertNotNull(event.getString("databaseOperation")); +// assertNotNull(event.getString("tenant")); + assertNull(event.getString("sqlID")); + assertNull(event.getString("originalSQLText")); + assertNull(event.getString("actualSQLText")); + assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); + break; + default: + fail("Unexpected event"); + } + } + } + } + } + + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { + configureOTEL(); + ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); + try (Connection connection = DriverManager.getConnection(url, userName, password); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { + + while (resultSet.next()) { + System.out.println(resultSet.getString(1)); + } + } + + Mockito.verify(tracer, atLeastOnce()).spanBuilder(DatabaseFunction.SESSION_KEY.getDescription()); + Mockito.verify(tracer, atLeastOnce()).spanBuilder(DatabaseFunction.AUTH_CALL.getDescription()); + Mockito.verify(tracer, atLeastOnce()).spanBuilder(DatabaseFunction.EXECUTE_QUERY.getDescription()); + Mockito.verify(tracer, atLeastOnce()).spanBuilder(DatabaseFunction.LOGOFF.getDescription()); + Mockito.verify(spanBuilder, atLeastOnce()).startSpan(); + Mockito.verify(spanBuilder, Mockito.atLeast(4)).setAttribute("thread.id", Thread.currentThread().getId()); + Mockito.verify(spanBuilder, Mockito.atLeast(4)).setAttribute("thread.name", Thread.currentThread().getName()); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.SESSION_KEY.getDescription()); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.AUTH_CALL.getDescription()); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.EXECUTE_QUERY.getDescription()); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.LOGOFF.getDescription()); + if (sensitiveDataEnabled) { + Mockito.verify(spanBuilder, Mockito.times(4)).setAttribute("Database User", userName); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Original SQL Text", "SELECT 'OK' FROM DUAL"); + Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Actual SQL Text", "SELECT 'OK' FROM DUAL"); + } + + + } + + private static void configureOTEL() { + Mockito.reset(spanBuilder, tracer); + Mockito.when(openTelemetry.getTracerProvider()).thenReturn(tracerProvider); + Mockito.when(tracerProvider.get(Mockito.anyString())).thenReturn(tracer); + Mockito.when(openTelemetry.meterBuilder(Mockito.anyString())).thenReturn(meterBuilder); + Mockito.when(spanContext.getTraceFlags()).thenReturn(traceFlags); + Mockito.when(spanContext.getTraceState()).thenReturn(traceState); + Mockito.when(span.getSpanContext()).thenReturn(spanContext); + Mockito.when(spanBuilder.setAttribute(Mockito.anyString(), Mockito.anyString())).thenReturn(spanBuilder); + Mockito.when(spanBuilder.setAttribute(Mockito.anyString(), Mockito.anyLong())).thenReturn(spanBuilder); + Mockito.when(spanBuilder.setAttribute(Mockito.anyString(), Mockito.anyBoolean())).thenReturn(spanBuilder); + Mockito.when(spanBuilder.setAttribute(Mockito.anyString(), Mockito.any())).thenReturn(spanBuilder); + Mockito.when(spanBuilder.setSpanKind(Mockito.any(SpanKind.class))).thenReturn(spanBuilder); + Mockito.when(spanBuilder.startSpan()).thenReturn(span); + Mockito.when(tracer.spanBuilder(Mockito.anyString())).thenReturn(spanBuilder); + } + +} From 5f5fdb8101dce9b973031d7be1d34f9b6ded9948 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 3 Feb 2025 14:08:35 +0100 Subject: [PATCH 03/25] Replaced set by list --- .../ObservabilityTraceEventListener.java | 24 +++++++++---------- .../ObservabilityConfiguration.java | 13 ++++------ .../ObservabilityTraceEventListenerTest.java | 8 +++---- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index b371c4b0..c3b0c555 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -1,7 +1,5 @@ package oracle.jdbc.provider.observability; -import java.util.EnumMap; - import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; import oracle.jdbc.provider.observability.tracers.JFRTracer; @@ -28,10 +26,10 @@ public ObservabilityTracer getTracer() { @Override public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { - EnumMap currentUserContext = getCurrentUserContext(userContext); + Object[] currentUserContext = getCurrentUserContext(userContext); for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { - Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext.get(tracer)); - currentUserContext.put(tracer, newUserContext); + Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext[tracer.ordinal()]); + currentUserContext[tracer.ordinal()] = newUserContext; } return currentUserContext; } @@ -39,10 +37,10 @@ public Object roundTrip(Sequence sequence, TraceContext traceContext, Object use @Override public Object onExecutionEventReceived(JdbcExecutionEvent event, Object userContext, Object... params) { - EnumMap currentUserContext = getCurrentUserContext(userContext); + Object[] currentUserContext = getCurrentUserContext(userContext); for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { - Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext.get(tracer), params); - currentUserContext.put(tracer, newUserContext); + Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext[tracer.ordinal()], params); + currentUserContext[tracer.ordinal()] = newUserContext; } return currentUserContext; } @@ -54,12 +52,12 @@ public boolean isDesiredEvent(JdbcExecutionEvent event) { } @SuppressWarnings("unchecked") - private EnumMap getCurrentUserContext(Object userContext) { - EnumMap currentUserContext; - if (userContext != null && (userContext instanceof EnumMap)) { - currentUserContext = (EnumMap) userContext; + private Object[] getCurrentUserContext(Object userContext) { + Object[] currentUserContext; + if (userContext != null && (userContext instanceof Object[])) { + currentUserContext = (Object[]) userContext; } else { - currentUserContext = new EnumMap(Tracers.class); + currentUserContext = new Object[Tracers.values().length]; } return currentUserContext; } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index e0404fe2..c6555983 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -1,6 +1,7 @@ package oracle.jdbc.provider.observability.configuration; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -23,7 +24,7 @@ private ObservabilityConfiguration() { } private boolean sensitiveDataEnabled; private String tracers; - private EnumSet enabledTracers = EnumSet.noneOf(ObservabilityTraceEventListener.Tracers.class); + private List enabledTracers = new ArrayList<>(); @Override public String getEnabledTracers() { @@ -67,12 +68,8 @@ public static ObservabilityConfiguration getInstance() { return INSTANCE; } - public EnumSet getEnabledTracersSet() { - if (enabledTracers != null) { - return enabledTracers.clone(); - } else { - return null; - } + public List getEnabledTracersSet() { + return enabledTracers; } } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index b598908f..d1db3a6c 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import java.nio.file.Path; @@ -12,8 +13,6 @@ import java.sql.ResultSet; import java.sql.Statement; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; @@ -61,6 +60,7 @@ public class ObservabilityTraceEventListenerTest { static { GlobalOpenTelemetry.set(openTelemetry); + configureOTEL(); } @ParameterizedTest @@ -137,7 +137,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { @ParameterizedTest @ValueSource(booleans = {true, false}) public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { - configureOTEL(); + Mockito.clearInvocations(tracer, spanBuilder); ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); try (Connection connection = DriverManager.getConnection(url, userName, password); @@ -165,12 +165,12 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Original SQL Text", "SELECT 'OK' FROM DUAL"); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Actual SQL Text", "SELECT 'OK' FROM DUAL"); } + Mockito.verify(span, atLeast(4)).end(Mockito.any()); } private static void configureOTEL() { - Mockito.reset(spanBuilder, tracer); Mockito.when(openTelemetry.getTracerProvider()).thenReturn(tracerProvider); Mockito.when(tracerProvider.get(Mockito.anyString())).thenReturn(tracer); Mockito.when(openTelemetry.meterBuilder(Mockito.anyString())).thenReturn(meterBuilder); From 2546b01818b8a61384c7945a646d97e3bb1ff343 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 3 Feb 2025 14:25:05 +0100 Subject: [PATCH 04/25] Changes to tests --- .../observability/ObservabilityTraceEventListenerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index d1db3a6c..a5336863 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -76,7 +76,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { while (resultSet.next()) { - System.out.println(resultSet.getString(1)); + assertEquals("OK", resultSet.getString(1)); } } recording.stop(); @@ -140,12 +140,13 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.clearInvocations(tracer, spanBuilder); ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); - try (Connection connection = DriverManager.getConnection(url, userName, password); + String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider"; + try (Connection connection = DriverManager.getConnection(otelUrl, userName, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { while (resultSet.next()) { - System.out.println(resultSet.getString(1)); + assertEquals("OK", resultSet.getString(1)); } } From 50211a2f58bc44db5429b5c1c4d3ad535ba874f0 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 3 Feb 2025 15:14:38 +0100 Subject: [PATCH 05/25] Added test name --- .../observability/ObservabilityTraceEventListenerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index a5336863..74931f55 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -63,7 +63,7 @@ public class ObservabilityTraceEventListenerTest { configureOTEL(); } - @ParameterizedTest + @ParameterizedTest(name = "JFRTraceTest - {arguments}") @ValueSource(booleans = {true, false}) public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { @@ -134,7 +134,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { } - @ParameterizedTest + @ParameterizedTest(name = "OTELTraceTest - {arguments}") @ValueSource(booleans = {true, false}) public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.clearInvocations(tracer, spanBuilder); From 535737c6884efa08c2865f0e627018f21a7acfd2 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 3 Feb 2025 15:58:56 +0100 Subject: [PATCH 06/25] Check connectionID --- .../ObservabilityTraceEventListenerTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index 74931f55..5ac37e6c 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -33,6 +33,7 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; import oracle.jdbc.DatabaseFunction; +import oracle.jdbc.driver.OracleConnection; import oracle.jdbc.provider.TestProperties; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; @@ -70,11 +71,13 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { ObservabilityConfiguration.getInstance().setEnabledTracers("JFR"); ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); Configuration configuration = Configuration.getConfiguration("default"); + String connectionId = null; try (Recording recording = new Recording(configuration)) { recording.start(); try (Connection connection = DriverManager.getConnection(url, userName, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { + connectionId = ((OracleConnection)connection).getNetConnectionId(); while (resultSet.next()) { assertEquals("OK", resultSet.getString(1)); } @@ -88,7 +91,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { if (event.getEventType().getCategoryNames().contains("Round trips")) { switch (event.getEventType().getName()) { case SESSION_KEY: - assertNotNull(event.getString("connectionID")); + assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); // assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); @@ -97,7 +100,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); break; case AUTH_CALL: - assertNotNull(event.getString("connectionID")); + assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); // assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); @@ -107,7 +110,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { break; case EXECUTE_QUERY: - assertNotNull(event.getString("connectionID")); + assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); // assertNotNull(event.getString("tenant")); assertNotNull(event.getString("sqlID")); @@ -116,7 +119,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { assertEquals(sensitiveDataEnabled, event.getString("databaseUser") != null); break; case LOGOFF: - assertNotNull(event.getString("connectionID")); + assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); // assertNotNull(event.getString("tenant")); assertNull(event.getString("sqlID")); @@ -141,10 +144,11 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider"; + String connectionId = null; try (Connection connection = DriverManager.getConnection(otelUrl, userName, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { - + connectionId = ((OracleConnection)connection).getNetConnectionId(); while (resultSet.next()) { assertEquals("OK", resultSet.getString(1)); } @@ -157,6 +161,7 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.verify(spanBuilder, atLeastOnce()).startSpan(); Mockito.verify(spanBuilder, Mockito.atLeast(4)).setAttribute("thread.id", Thread.currentThread().getId()); Mockito.verify(spanBuilder, Mockito.atLeast(4)).setAttribute("thread.name", Thread.currentThread().getName()); + Mockito.verify(spanBuilder, Mockito.atLeast(1)).setAttribute("Connection ID", connectionId); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.SESSION_KEY.getDescription()); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.AUTH_CALL.getDescription()); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Database Operation", DatabaseFunction.EXECUTE_QUERY.getDescription()); From 65753e81b230966b3c898f346f6629401bf09766 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 10 Feb 2025 10:07:54 +0100 Subject: [PATCH 07/25] Static JFR events --- .../ObservabilityTraceEventListener.java | 15 ---------- .../ObservabilityConfiguration.java | 10 +++++-- .../tracers/JFREventFactory.java | 15 ++++++++++ .../observability/tracers/JFRTracer.java | 6 ++++ .../tracers/ObservabilityTracer.java | 28 +++++++++++++++++++ .../observability/tracers/Tracers.java | 27 ++++++++++++++++++ .../ObservabilityTraceEventListenerTest.java | 8 +++--- 7 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index c3b0c555..e149e59c 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -9,21 +9,6 @@ public class ObservabilityTraceEventListener implements TraceEventListener { - public enum Tracers { - OTEL(new OTelTracer()), - JFR(new JFRTracer()); - - private ObservabilityTracer tracer; - - Tracers(ObservabilityTracer tracer) { - this.tracer = tracer; - } - - public ObservabilityTracer getTracer() { - return tracer; - } - } - @Override public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { Object[] currentUserContext = getCurrentUserContext(userContext); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index c6555983..527f09c6 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -6,7 +6,11 @@ import java.util.stream.Collectors; import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; +import oracle.jdbc.provider.observability.tracers.Tracers; +/** + * + */ public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); @@ -24,7 +28,7 @@ private ObservabilityConfiguration() { } private boolean sensitiveDataEnabled; private String tracers; - private List enabledTracers = new ArrayList<>(); + private List enabledTracers = new ArrayList<>(); @Override public String getEnabledTracers() { @@ -44,7 +48,7 @@ public void setEnabledTracers(String tracers) { String[] items = tracers.split(","); for (String item : items) { if (item != null) { - enabledTracers.add(ObservabilityTraceEventListener.Tracers.valueOf(item.toUpperCase())); + enabledTracers.add(Tracers.valueOf(item.toUpperCase())); } } this.tracers = enabledTracers.stream().map((item) -> item.toString()).collect(Collectors.joining(",")); @@ -68,7 +72,7 @@ public static ObservabilityConfiguration getInstance() { return INSTANCE; } - public List getEnabledTracersSet() { + public List getEnabledTracersSet() { return enabledTracers; } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java index 3c2f0551..88ddec83 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java @@ -7,8 +7,23 @@ import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +/** + * Factory class for creating JFR events depending on the database function. + */ public class JFREventFactory { + /** + * This class only has a static method, no public constructor needed. + */ + private JFREventFactory() { } + + /** + * An instance of {@link RoundTripEvent} for the given trace context. The type + * of round trip event depends on the database function. + * + * @param traceContext the trace context received by a TraceEventListener. + * @return the {@link RoundTripEvent} for the database function. + */ public static RoundTripEvent createJFREvent(TraceContext traceContext) { switch (traceContext.databaseFunction()) { case ADVANCED_QUEUING_12C_EMON_DEQUEUE: diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java index 68347ac8..31391fd7 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java @@ -5,8 +5,14 @@ import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.tracers.JFREventFactory.RoundTripEvent; +/** + * {@link ObservabilityTracer} for tracing Java Flight Recorder events. + */ public class JFRTracer implements ObservabilityTracer{ + /** + * Creates a new instance. + */ public JFRTracer() {} @Override diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java index 98f9218a..18daf733 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java @@ -3,11 +3,39 @@ import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; +import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; +/** + * This interface must be implemented by all Observability tracers. + */ public interface ObservabilityTracer { + /** + * Called by {@link ObservabilityTraceEventListener} when a round trip event + * is received. + * + * @param sequence BEFORE if before the round trip, AFTER if after the round + * trip + * @param traceContext Information about the round trip. Valid only during the + * call + * @param userContext Result of previous call on this Connection or null if no + * previous call or if observability was disabled since the previous call. + * @return a user context object that is passed to the next call on this + * Connection. May be null. + */ Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext); + /** + * Called by {@link ObservabilityTraceEventListener} when an execution event + * is received. + * + * @param event the event. + * @param userContext the result of the previous call or null if no previous + * call has been made. + * @param params event specific parameters. + * @return a user context object that is passed to the next call for the same + * type of event. May be null. + */ Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params); } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java new file mode 100644 index 00000000..8ac2ec10 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java @@ -0,0 +1,27 @@ +package oracle.jdbc.provider.observability.tracers; + +/** + * This interface defines the constants that are used to identify the + * {@link ObservabilityTracer}. + */ +public enum Tracers { + /** + * Open Telemetry tracer. + */ + OTEL(new OTelTracer()), + + /** + * Java Flight Recorder tracer. + */ + JFR(new JFRTracer()); + + private ObservabilityTracer tracer; + + Tracers(ObservabilityTracer tracer) { + this.tracer = tracer; + } + + public ObservabilityTracer getTracer() { + return tracer; + } +} \ No newline at end of file diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index 5ac37e6c..513de9ef 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -93,7 +93,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case SESSION_KEY: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); -// assertNull(event.getString("tenant")); + assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); @@ -102,7 +102,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case AUTH_CALL: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); -// assertNull(event.getString("tenant")); + assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); @@ -112,7 +112,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case EXECUTE_QUERY: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); -// assertNotNull(event.getString("tenant")); + assertNotNull(event.getString("tenant")); assertNotNull(event.getString("sqlID")); assertEquals(sensitiveDataEnabled, event.getString("originalSQLText") != null); assertEquals(sensitiveDataEnabled, event.getString("actualSQLText") != null); @@ -121,7 +121,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case LOGOFF: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); -// assertNotNull(event.getString("tenant")); + assertNotNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); From ce3601d0af0b49e22608f50330b09dd7a4bcad5b Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 10 Feb 2025 10:12:35 +0100 Subject: [PATCH 08/25] Merged from main --- .../observability/ObservabilityTraceEventListener.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index e149e59c..95352da4 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -2,9 +2,7 @@ import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.JFRTracer; -import oracle.jdbc.provider.observability.tracers.OTelTracer; -import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; +import oracle.jdbc.provider.observability.tracers.Tracers; public class ObservabilityTraceEventListener implements TraceEventListener { From bc11b39d4c87956d422aff330ada926a4e5d4f1f Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 14 Feb 2025 12:23:39 +0100 Subject: [PATCH 09/25] Documentation and tests --- ojdbc-provider-observability/README.md | 122 ++++++++++++++++++ ojdbc-provider-observability/pom.xml | 6 +- .../ObservabilityTraceEventListener.java | 50 ++++++- ...servabilityTraceEventListenerProvider.java | 35 +++-- ...enTelemetryTraceEventListenerProvider.java | 20 --- .../ObservabilityConfiguration.java | 58 ++++++++- .../ObservabilityConfigurationMBean.java | 41 +++++- .../observability/tracers/OTelTracer.java | 16 ++- .../tracers/{Tracers.java => Tracer.java} | 8 +- ...enTelemetryTraceEventListenerProvider.java | 96 ++++++++++++++ .../ObservabilityConfigurationTest.java | 73 +++++++++++ .../BackwardCompatibilityTest.java | 75 +++++++++++ ojdbc-provider-samples/pom.xml | 8 +- 13 files changed, 560 insertions(+), 48 deletions(-) create mode 100644 ojdbc-provider-observability/README.md delete mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java rename ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/{Tracers.java => Tracer.java} (70%) create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java create mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java create mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java diff --git a/ojdbc-provider-observability/README.md b/ojdbc-provider-observability/README.md new file mode 100644 index 00000000..fa942914 --- /dev/null +++ b/ojdbc-provider-observability/README.md @@ -0,0 +1,122 @@ +# Oracle JDBC Observability Provider + +This module contains a provider that adds tracing capabilities to the Oracle +JDBC driver. Two tracers are available: + * OTEL: adds Open Telemetry tracing capabilities. + * JFR: exports events to Java Flight Recorder. + +This provider implements the TraceEventListener interface provided by the JDBC +driver which will be notified whenever events are generated in the driver and +will publish these events into Open Telemetry. These events include: + * roundtrips to the database server + * AC begin and sucess + * 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)* + * Actual SQL Text *(only present if sensitive data is enabled)* + * **AC begin and success** + * Error Message + * Error code + * SQL state + * Current replay retry count + * **VIP down event** + * 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)* + +## Installation + +This provider is distributed as single jar on the Maven Central Repository. The +jar is compiled for JDK 8, and is forward compatible with later JDK versions. +The coordinates for the latest release are: + +```xml + + com.oracle.database.jdbc + ojdbc-provider-observability + 1.0.3 + +``` + +## Usage + +To use the Oracle JDBC observability provider just add the artifact to the +application's classpath and set the following connection property: + +```java +oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider +``` + +## Configuration + +The provider can be configured by: +* using the singleton configuration class, +```java +ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL,JFR"); +ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); +``` +* using system properties, +```java +System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "OTEL,JFR"); +System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "true"); +``` +* or using the MBean. +```java +ObjectName objectName = new ObjectName( + "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"); +MBeanServer server = ManagementFactory.getPlatformMBeanServer(); +server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); +server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", "true")); +``` + +## Backward compatibility + +### Usage + +The provider can also be used by setting the following connection property: + +```java +oracle.jdbc.provider.traceEventListener=open-telemetry-trace-event-listener-provider +``` + +When this property is used only the OTEL tracer can be used. + +### Configuration + +To ensure backward compatibility Oracle JDBC provider for Open Telemetry configuration +properties and MBean have been kept. When these properties and MBean are used only +the Open Telemetry tracer will be enabled. + +The Oracle JDBC provider for Open Telemetry can be configured using system properties +or a MBean. Two parameters can be configured: + * **Enabled**: when enabled (*true*) traces will be exported to Open + Telemetry. This property is **enabled by default**. + * **Sensitive data enabled**: when enabled (*true*) attributes containing + sensitive information like SQL statements and connection URL will be included + in the traces. This property is **disabled by default**. + +The system properties are "oracle.jdbc.provider.opentelemetry.enabled" and +"oracle.jdbc.provider.opentelemetry.sensitive-enabled" respectively and the MBean +with object name "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener" +exposes two attributes "Enabled" and "SensitiveDataEnabled". + + The sample code below shows how to retrieve the value of an attribute: +```java +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(); +``` \ No newline at end of file diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index 4b90faad..fe07046e 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -3,15 +3,17 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + com.oracle.database.jdbc ojdbc-extensions - 1.0.2 + 1.0.3 + Oracle JDBC Observability Provider com.oracle.database.jdbc ojdbc-provider-observability - 1.0.2 + 1.0.3 1.44.1 diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index 95352da4..a9559c8e 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -2,15 +2,56 @@ import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.Tracers; +import oracle.jdbc.provider.observability.tracers.Tracer; +/** + *

    + * TraceEventListener implementaiton that receives notifications whenever events + * are generated in the driver and publishes these events different tracers + * depending on the configuraiton. + *

    + *

    + * These events include: + *

    + *
      + *
    • roundtrips to the database server
    • + *
    • AC begin and success
    • + *
    • VIP down event
    • + *
    + *

    + * The available tracers are defined in the enumeration {@link Tracer}, and + * can be enabled using the method + * {@link ObservabilityConfiguration#setEnabledTracers(String)}. The method + * {@link ObservabilityConfiguration#setSensitiveDataEnabled(boolean)} allows + * to enabled/disable exporting sensitive data to the tracers. + *

    + */ public class ObservabilityTraceEventListener implements TraceEventListener { + /** + * Private constructor. + */ + private ObservabilityTraceEventListener() { } + + /** + * Singleton instance. + */ + private static final ObservabilityTraceEventListener INSTANCE = + new ObservabilityTraceEventListener(); + + /** + * Returns the singleton instance of {@link ObservabilityTraceEventListener}. + * @return the singleton instance of {@link ObservabilityTraceEventListener}. + */ + public static final ObservabilityTraceEventListener getInstance() { + return INSTANCE; + } @Override public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { + if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} Object[] currentUserContext = getCurrentUserContext(userContext); - for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + for (Tracer tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext[tracer.ordinal()]); currentUserContext[tracer.ordinal()] = newUserContext; } @@ -20,8 +61,9 @@ public Object roundTrip(Sequence sequence, TraceContext traceContext, Object use @Override public Object onExecutionEventReceived(JdbcExecutionEvent event, Object userContext, Object... params) { + if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} Object[] currentUserContext = getCurrentUserContext(userContext); - for (Tracers tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + for (Tracer tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext[tracer.ordinal()], params); currentUserContext[tracer.ordinal()] = newUserContext; } @@ -40,7 +82,7 @@ private Object[] getCurrentUserContext(Object userContext) { if (userContext != null && (userContext instanceof Object[])) { currentUserContext = (Object[]) userContext; } else { - currentUserContext = new Object[Tracers.values().length]; + currentUserContext = new Object[Tracer.values().length]; } return currentUserContext; } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 8ea1163f..5c604d71 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -7,28 +7,34 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.management.Attribute; import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; -import javax.management.ReflectionException; import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; import oracle.jdbc.spi.TraceEventListenerProvider; +/** + * Implementation of Oracle JDBC {@link TraceEventListenerProvider} for + * {@link ObservabilityTraceEventListener}. + */ public class ObservabilityTraceEventListenerProvider implements TraceEventListenerProvider { private static final String PROVIDER_NAME = "observability-trace-event-listener-provider"; - private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.observability:type=ObservabilityConfiguration"; + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"; - private static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; + protected static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; + protected static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; + + protected static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; private static ObjectName objectName; - Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); + protected Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); static { try { @@ -38,15 +44,28 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen } } + /** + * Constructs a new instance of ObservabilityTraceEventListenerProvider. This + * constructor will be called by the driver's service provider to create a new + * instance. + */ + public ObservabilityTraceEventListenerProvider() { } + @Override public TraceEventListener getTraceEventListener(Map map) { try { - if (!server.isRegistered(objectName)) - server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); + if (!server.isRegistered(objectName)) { + String enabledTracers = System.getProperty(ENABLED_TRACERS, "OTEL,JFR"); + String sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, "false"); + ObservabilityConfiguration.getInstance().setEnabledTracers(enabledTracers); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(Boolean.parseBoolean(sensitiveDataEnabled)); + + server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); + } } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { logger.log(Level.WARNING, "Could not register MBean", e); } - return new ObservabilityTraceEventListener(); + return ObservabilityTraceEventListener.getInstance(); } @Override diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java deleted file mode 100644 index 649ef25d..00000000 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java +++ /dev/null @@ -1,20 +0,0 @@ -package oracle.jdbc.provider.observability; - -import java.util.Collection; -import java.util.Collections; - -public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceEventListenerProvider { - - private static final String PROVIDER_NAME = "open-telemetry-trace-event-listener-provider"; - - @Override - public String getName() { - return PROVIDER_NAME; - } - - @Override - public Collection getParameters() { - return Collections.emptyList(); - } - -} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index 527f09c6..e0dd7202 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -5,11 +5,11 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; -import oracle.jdbc.provider.observability.tracers.Tracers; +import oracle.jdbc.provider.observability.tracers.Tracer; /** - * + * Implementation of {@link ObservabilityConfigurationMBean} that allows to + * configure the Oracle JDBC Observability Provider. */ public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { @@ -25,11 +25,35 @@ public class ObservabilityConfiguration implements ObservabilityConfigurationMBe private ObservabilityConfiguration() { } + private boolean enabled = true; private boolean sensitiveDataEnabled; private String tracers; - private List enabledTracers = new ArrayList<>(); + private List enabledTracers = new ArrayList<>(); + /** + * Returns true if the provider is enabled, otherwise false. + * + * @return true if the provider is enabled, otherwise false. + */ + @Override + public boolean getEnabled() { + return enabled; + } + + /** + * Enables/disables the provider. + * + * @param enabled true to enable the provider, otherwise false. + */ + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * Returns a comma separated list of enabled tracers. + */ @Override public String getEnabledTracers() { try { @@ -40,6 +64,11 @@ public String getEnabledTracers() { } } + /** + * Enables the tracers. Available tracers are defined in enum {@link Tracer}. + * + * @param tracers comma separated list of enabled tracers. + */ @Override public void setEnabledTracers(String tracers) { try { @@ -48,7 +77,7 @@ public void setEnabledTracers(String tracers) { String[] items = tracers.split(","); for (String item : items) { if (item != null) { - enabledTracers.add(Tracers.valueOf(item.toUpperCase())); + enabledTracers.add(Tracer.valueOf(item.toUpperCase())); } } this.tracers = enabledTracers.stream().map((item) -> item.toString()).collect(Collectors.joining(",")); @@ -58,22 +87,39 @@ public void setEnabledTracers(String tracers) { } + /** + * Returns true if sensitive data is enabled, otherwise false. + */ @Override public boolean getSensitiveDataEnabled() { return sensitiveDataEnabled; } + /** + * Enables/disables sensitive data. + * + * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. + */ @Override public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { this.sensitiveDataEnabled = sensitiveDataEnabled; } + /** + * Returns the singleton instance of {@link ObservabilityConfiguration}. + * @return the singleton instance of {@link ObservabilityConfiguration}. + */ public static ObservabilityConfiguration getInstance() { return INSTANCE; } - public List getEnabledTracersSet() { + /** + * Returns a list of enabled {@link Tracer}. + * @return then list of nabled {@link Tracer}. + */ + public List getEnabledTracersSet() { return enabledTracers; } + } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java index 3aedf3fc..e67d7fb4 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java @@ -1,12 +1,51 @@ package oracle.jdbc.provider.observability.configuration; +import oracle.jdbc.provider.observability.tracers.Tracer; + +/** + * MBean that allows to configure the Oracle JDBC Observability Provider. + */ public interface ObservabilityConfigurationMBean { - + + /** + * Returns true if the provider is enabled, otherwise false. + * + * @return true if the provider is enabled, otherwise false. + */ + public boolean getEnabled(); + + /** + * Enables/disables the provider. + * + * @param enabled true to enable the provider, otherwise false. + */ + public void setEnabled(boolean enabled); + + /** + * Returns a comma separated list of enabled tracers. + * + * @return a comma separated list of enabled tracers. + */ public String getEnabledTracers(); + /** + * Enables the tracers. Available tracers are defined in enum {@link Tracer}. + * + * @param tracers comma separated list of enabled tracers. + */ public void setEnabledTracers(String tracers); + /** + * Returns true if sensitive data is enabled, otherwise false. + * + * @return true if sensitive data is enabled, otherwise false. + */ public boolean getSensitiveDataEnabled(); + /** + * Enables/disables sensitive data. + * + * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. + */ public void setSensitiveDataEnabled(boolean sensitiveDataEnabled); } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java index 9bbdafa8..1d84535f 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java @@ -24,20 +24,34 @@ import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +/** + * Open Telemetry tracer. Exports round trip event and execution events to + * Open Telemetry. + */ public class OTelTracer implements ObservabilityTracer { private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; private Tracer tracer; + /** + * Constructor. Uses {@link GlobalOpenTelemetry} to get the tracer. + */ public OTelTracer() { this(GlobalOpenTelemetry.get().getTracer(OTelTracer.class.getName())); } + /** + * Constructor. + * @param tracer Open Telemetry tracer. + */ public OTelTracer(Tracer tracer) { this.tracer = tracer; } - // Number of parameters expected for each execution event + + /** + * Map containing the number of parameters expected for each execution event + */ private static final Map EXECUTION_EVENTS_PARAMETERS = new EnumMap( JdbcExecutionEvent.class) { { diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java similarity index 70% rename from ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java rename to ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java index 8ac2ec10..3b74d2f2 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracers.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java @@ -4,7 +4,7 @@ * This interface defines the constants that are used to identify the * {@link ObservabilityTracer}. */ -public enum Tracers { +public enum Tracer { /** * Open Telemetry tracer. */ @@ -17,10 +17,14 @@ public enum Tracers { private ObservabilityTracer tracer; - Tracers(ObservabilityTracer tracer) { + Tracer(ObservabilityTracer tracer) { this.tracer = tracer; } + /** + * Returns the {@link ObservabilityTracer} for this {@link Tracer}. + * @return the {@link ObservabilityTracer}. + */ public ObservabilityTracer getTracer() { return tracer; } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java new file mode 100644 index 00000000..c02baab0 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java @@ -0,0 +1,96 @@ +package oracle.jdbc.provider.opentelemetry; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.logging.Level; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + +import oracle.jdbc.TraceEventListener; +import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; +import oracle.jdbc.provider.observability.ObservabilityTraceEventListenerProvider; +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; + +/** + *

    + * This class implements the TraceEventListenerProvider interface exposed by the + * Oracle JDBC driver. It provides TraceEventListeners of type {@link + * oracle.jdbc.provider.observability.ObservabilityTraceEventListener}. + *

    + *

    + * The provider registers a MBean (with objectName {@value #MBEAN_OBJECT_NAME}) + * that allows to configure the TraceEventListener by setting attributes. The + * following attributes are available: + *

      + *
    • Enabled: enables/disables exporting traces to Open Telemetry + * (true by default)
    • + *
    • SensitiveDataEnabled: enables/disables exporting sensiteve data + * to Open Telemetry(false by default)
    • + *
    + */ +public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceEventListenerProvider { + + private static final String PROVIDER_NAME = "open-telemetry-trace-event-listener-provider"; + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener"; + + /** + * Name of the property used to enable or disable this listener. + */ + public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED = "oracle.jdbc.provider.opentelemetry.enabled"; + /** + * Name of the property used to enable or disable sensitive data for this + * listener. + */ + public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; + + private static ObjectName objectName; + + static { + try { + objectName = new ObjectName(MBEAN_OBJECT_NAME); + } catch (MalformedObjectNameException e) { + objectName = null; + } + } + + /** + * Constructs a new instance of OpenTelemetryTraceEventListenerProvider. This + * constructor will be called by the driver's service provider to create a new + * instance. + */ + public OpenTelemetryTraceEventListenerProvider() { } + + @Override + public String getName() { + return PROVIDER_NAME; + } + + @Override + public Collection getParameters() { + return Collections.emptyList(); + } + + @Override + public TraceEventListener getTraceEventListener(Map map) { + try { + if (!server.isRegistered(objectName)) { + boolean enabled = Boolean.valueOf(System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED, "true")); + String sensitiveDataEnabled = System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "false"); + ObservabilityConfiguration.getInstance().setEnabled(enabled); + ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(Boolean.parseBoolean(sensitiveDataEnabled)); + + server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); + } + } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { + logger.log(Level.WARNING, "Could not register MBean", e); + } + return ObservabilityTraceEventListener.getInstance(); + } + +} diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java new file mode 100644 index 00000000..75ba85d9 --- /dev/null +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -0,0 +1,73 @@ +package oracle.jdbc.provider.observability; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.management.ManagementFactory; + +import javax.management.Attribute; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.jupiter.api.Test; + +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.spi.TraceEventListenerProvider; + +public class ObservabilityConfigurationTest { + + @Test + public void testConfiguration() throws Exception { + + // System properties + System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "JFR"); + System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "true"); + + TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); + provider.getTraceEventListener(null); + + assertEquals("JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); + assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + + // MBean + ObjectName objectName = new ObjectName( + "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"); + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals(enabledTracers, "JFR"); + assertEquals(sensitiveDataEnabled, "true"); + + server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); + server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); + + assertEquals("OTEL,JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); + assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals("OTEL,JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); + assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals(2, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(Tracer.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(1)); + + // Singleton + ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); + + enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals("OTEL", enabledTracers); + assertEquals("true", sensitiveDataEnabled); + + assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + + } + +} diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java new file mode 100644 index 00000000..edc9ae2c --- /dev/null +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java @@ -0,0 +1,75 @@ +package oracle.jdbc.provider.opentelemetry; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.management.ManagementFactory; + +import javax.management.Attribute; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.jupiter.api.Test; + +import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.spi.TraceEventListenerProvider; + +public class BackwardCompatibilityTest { + @Test + public void testConfiguration() throws Exception { + + // System properties + System.setProperty("oracle.jdbc.provider.opentelemetry.enabled", "true"); + System.setProperty("oracle.jdbc.provider.opentelemetry.sensitive-enabled", "true"); + + TraceEventListenerProvider provider = new OpenTelemetryTraceEventListenerProvider(); + provider.getTraceEventListener(null); + + assertEquals(true, ObservabilityConfiguration.getInstance().getEnabled()); + assertEquals("OTEL", ObservabilityConfiguration.getInstance().getEnabledTracers()); + assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + + // MBean + ObjectName objectName = new ObjectName( + "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener"); + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + String enabled = server.getAttribute(objectName, "Enabled").toString(); + String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals(enabled, "true"); + assertEquals(enabledTracers, "OTEL"); + assertEquals(sensitiveDataEnabled, "true"); + + server.setAttribute(objectName, new Attribute("Enabled", false)); + server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); + + assertEquals(false, ObservabilityConfiguration.getInstance().getEnabled()); + assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals("OTEL", ObservabilityConfiguration.getInstance().getEnabledTracers()); + assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + + assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + + // Singleton + ObservabilityConfiguration.getInstance().setEnabled(true); + ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); + + enabled = server.getAttribute(objectName, "Enabled").toString(); + enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals("true", enabled); + assertEquals("OTEL", enabledTracers); + assertEquals("true", sensitiveDataEnabled); + + assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); + assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + + } +} diff --git a/ojdbc-provider-samples/pom.xml b/ojdbc-provider-samples/pom.xml index f55ec768..08758a27 100644 --- a/ojdbc-provider-samples/pom.xml +++ b/ojdbc-provider-samples/pom.xml @@ -5,7 +5,7 @@ Oracle JDBC Provider Code Samples ojdbc-provider-samples - ${project.parent.version} + 1.0.3 jar @@ -23,17 +23,17 @@ com.oracle.database.jdbc ojdbc-provider-azure - ${project.parent.version} + 1.0.3 com.oracle.database.jdbc ojdbc-provider-oci - ${project.parent.version} + 1.0.3 com.oracle.database.jdbc ojdbc-provider-jackson-oson - ${project.parent.version} + 1.0.3 com.oracle.database.security From b469a80a7ef7f3f91692458f0017dcb167c70753 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 14 Feb 2025 17:25:49 +0100 Subject: [PATCH 10/25] Added execution events to JFR --- ...servabilityTraceEventListenerProvider.java | 24 +++- .../tracers/JFREventFactory.java | 129 +++++++++++++++++- .../observability/tracers/JFRTracer.java | 41 +----- .../observability/tracers/OTelTracer.java | 13 +- .../tracers/ObservabilityTracer.java | 16 +++ ...enTelemetryTraceEventListenerProvider.java | 6 + 6 files changed, 174 insertions(+), 55 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 5c604d71..50f84221 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -27,14 +27,30 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen private static final String PROVIDER_NAME = "observability-trace-event-listener-provider"; private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"; + private static ObjectName objectName; + + /** + * System property used to enabled/disable tracers. The value of this system property should be a comma separated list + * of {@link Tracer} to enable. By default all tracers will be enabled. + */ + private static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; + + /** + * System property used to enable/disable exporting sensitive data. Set the property to true to enable sensitive data. + * By default exporting sensitive data is disabled. + */ + private static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; - protected static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; - protected static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; + /** + * Logger + */ + private Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); + /** + * MBean server + */ protected static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; - private static ObjectName objectName; - protected Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); static { try { diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java index 88ddec83..eb7977c0 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java @@ -3,9 +3,14 @@ import jdk.jfr.Event; import jdk.jfr.Label; import jdk.jfr.Name; + +import java.sql.SQLException; + import jdk.jfr.Category; +import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.tracers.JFREventFactory.ExecutionEvent; /** * Factory class for creating JFR events depending on the database function. @@ -18,8 +23,8 @@ public class JFREventFactory { private JFREventFactory() { } /** - * An instance of {@link RoundTripEvent} for the given trace context. The type - * of round trip event depends on the database function. + * Creates an instance of {@link RoundTripEvent} for the given trace context. + * The type of round trip event depends on the database function. * * @param traceContext the trace context received by a TraceEventListener. * @return the {@link RoundTripEvent} for the database function. @@ -177,6 +182,29 @@ public static RoundTripEvent createJFREvent(TraceContext traceContext) { } } + /** + * Creates an instance {@link ExecutionEvent} for the given {@link + * JdbcExecutionEvent}. + * + * @param event the event. + * @param params the parameters to populate the event properties. + * @return the execution event. + */ + public static Event createExecutionEvent(JdbcExecutionEvent event, Object... params) { + switch (event) { + case AC_REPLAY_STARTED: + return new ACReplayStarted(event, params); + case AC_REPLAY_SUCCESSFUL: + return new ACReplaySuccessful(event, params); + case VIP_RETRY: + return new VIPRetry(event, params); + default: + return new ExecutionEvent(event, params); + } + } + + // Round-trip events + @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_12C_EMON_DEQUEUE") @Label("Round trip") @Category({"Oracle JDBC", "Round trips"}) @@ -878,4 +906,101 @@ public void setValues(TraceContext traceContext) { } + // Execution Events + @Name("oracle.jdbc.provider.observability.ExecutionEvent.AC_REPLAY_STARTED") + @Label("AC replay started") + @Category({"Oracle JDBC", "Execution events"}) + static class ACReplayStarted extends ACReplay { + public ACReplayStarted(JdbcExecutionEvent event, Object... params) { + super(event, params); + } + } + + @Name("oracle.jdbc.provider.observability.ExecutionEvent.AC_REPLAY_SUCCESSFUL") + @Label("AC replay successful") + @Category({"Oracle JDBC", "Execution events"}) + static class ACReplaySuccessful extends ACReplay { + public ACReplaySuccessful(JdbcExecutionEvent event, Object... params) { + super(event, params); + } + } + + + @Name("oracle.jdbc.provider.observability.ExecutionEvent.AC_REPLAY") + @Label("AC replay") + @Category({"Oracle JDBC", "Execution events"}) + static class ACReplay extends ExecutionEvent { + public ACReplay(JdbcExecutionEvent event, Object... params) { + super(event, params); + if (ObservabilityTracer.EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + this.errorCode = ((SQLException) params[1]).getErrorCode(); + this.sqlState = ((SQLException) params[1]).getSQLState(); + this.currentReplayRetryCount = params[2].toString(); + } + } + @Label("Error code") + public int errorCode; + + @Label("SQL state") + public String sqlState; + + @Label("Current replay retry count") + public String currentReplayRetryCount; + } + + @Name("oracle.jdbc.provider.observability.ExecutionEvent.VIP_RETRY") + @Label("VIP retry") + @Category({"Oracle JDBC", "Round trips"}) + static class VIPRetry extends ExecutionEvent { + public VIPRetry(JdbcExecutionEvent event, Object... params) { + super(event, params); + if (ObservabilityTracer.EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + protocol = params[1].toString(); + host = params[2].toString(); + port = params[3].toString(); + serviceName = params[4].toString(); + sid = params[5].toString(); + connectionData = params[6].toString(); + vipAddress = params[7].toString(); + } + } + + @Label("The protocol") + public String protocol; + + @Label("The host") + public String host; + + @Label("The port") + public String port; + + @Label("The service name") + public String serviceName; + + @Label("The SID") + public String sid; + + @Label("The connection data") + public String connectionData; + + @Label("The VIP address") + public String vipAddress; + } + + @Name("oracle.jdbc.provider.observability.ExecutionEvent") + @Label("Execution event") + @Category({"Oracle JDBC", "Execution events"}) + static class ExecutionEvent extends Event { + public ExecutionEvent(JdbcExecutionEvent event, Object... params) { + if (ObservabilityTracer.EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + if (params != null && params.length > 0) { + this.errorMessage = params[0].toString(); + } + } + } + + @Label("Error message") + String errorMessage; + } + } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java index 31391fd7..ba233c56 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java @@ -1,5 +1,6 @@ package oracle.jdbc.provider.observability.tracers; +import jdk.jfr.Event; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; @@ -34,44 +35,10 @@ public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Objec @Override public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { + Event executionEvent = JFREventFactory.createExecutionEvent(event, params); + executionEvent.begin(); + executionEvent.commit(); return null; } - /** - * Creates an event for a given database operation. - * @param databaseFunction The database function originating the round trip. - * @return returns a Java Flight Recorder Event containing the following - * fields: - *
      - *
    • ConnectionID
    • - *
    • DatabaseOperation
    • - *
    • OriginalSqlText
    • - *
    • ActualSqlText
    • - *
    • User
    • - *
    - */ - /* - private static Event createEvent(DatabaseFunction databaseFunction) { - String eventName = "oracle.jdbc.provider.jfr.roundtrip." + databaseFunction.toString(); - List eventAnnotations = new ArrayList(); - eventAnnotations - .add(new AnnotationElement(Name.class, eventName)); - eventAnnotations.add(new AnnotationElement(Label.class, databaseFunction.getDescription())); - eventAnnotations.add(new AnnotationElement(Category.class, new String[] { "Oracle JDBC", "Round trips" })); - - List fields = new ArrayList(); - fields.add(new ValueDescriptor(String.class, "Connection_ID")); - fields.add(new ValueDescriptor(String.class, "Database_operation")); - fields.add(new ValueDescriptor(String.class, "Database_tenant")); - fields.add(new ValueDescriptor(String.class, "SQL_ID")); - fields.add(new ValueDescriptor(String.class, "Original_SQL_text")); - fields.add(new ValueDescriptor(String.class, "Actual_SQL_text")); - fields.add(new ValueDescriptor(String.class, "Database_user")); - - EventFactory f = EventFactory.create(eventAnnotations, fields); - return f.newEvent(); - } -*/ - - } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java index 1d84535f..8ba559c5 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java @@ -49,17 +49,6 @@ public OTelTracer(Tracer tracer) { this.tracer = tracer; } - /** - * Map containing the number of parameters expected for each execution event - */ - private static final Map EXECUTION_EVENTS_PARAMETERS = new EnumMap( - JdbcExecutionEvent.class) { - { - put(JdbcExecutionEvent.AC_REPLAY_STARTED, 3); - put(JdbcExecutionEvent.AC_REPLAY_SUCCESSFUL, 3); - put(JdbcExecutionEvent.VIP_RETRY, 8); - } - }; private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); @@ -90,7 +79,7 @@ public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Objec @Override public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { -if (EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + if (EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { if (event == TraceEventListener.JdbcExecutionEvent.VIP_RETRY) { SpanBuilder spanBuilder = tracer .spanBuilder(event.getDescription()) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java index 18daf733..5e93c3fa 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java @@ -1,5 +1,8 @@ package oracle.jdbc.provider.observability.tracers; +import java.util.EnumMap; +import java.util.Map; + import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; @@ -10,6 +13,19 @@ */ public interface ObservabilityTracer { + /** + * Map containing the number of parameters expected for each execution event + */ + static final Map EXECUTION_EVENTS_PARAMETERS + = new EnumMap(JdbcExecutionEvent.class) { + { + put(JdbcExecutionEvent.AC_REPLAY_STARTED, 3); + put(JdbcExecutionEvent.AC_REPLAY_SUCCESSFUL, 3); + put(JdbcExecutionEvent.VIP_RETRY, 8); + } + }; + + /** * Called by {@link ObservabilityTraceEventListener} when a round trip event * is received. diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java index c02baab0..46d5f676 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.Map; import java.util.logging.Level; +import java.util.logging.Logger; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanRegistrationException; @@ -48,6 +49,11 @@ public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceE */ public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; + /** + * Logger + */ + private Logger logger = Logger.getLogger(OpenTelemetryTraceEventListenerProvider.class.getName()); + private static ObjectName objectName; static { From a6cd8746ba861df67eb03b05833c314e0fa45958 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 21 Feb 2025 11:15:01 +0100 Subject: [PATCH 11/25] Documentation changes --- .../ObservabilityTraceEventListener.java | 10 ++-- ...servabilityTraceEventListenerProvider.java | 2 +- .../ObservabilityConfiguration.java | 56 ++++++++++++++----- .../ObservabilityConfigurationMBean.java | 4 +- .../tracers/{Tracer.java => TracerType.java} | 9 ++- .../tracers/{ => jfr}/JFREventFactory.java | 4 +- .../tracers/{ => jfr}/JFRTracer.java | 5 +- .../tracers/{ => otel}/OTelTracer.java | 35 ++++++++---- .../ObservabilityConfigurationTest.java | 10 ++-- .../BackwardCompatibilityTest.java | 8 +-- 10 files changed, 95 insertions(+), 48 deletions(-) rename ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/{Tracer.java => TracerType.java} (72%) rename ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/{ => jfr}/JFREventFactory.java (99%) rename ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/{ => jfr}/JFRTracer.java (84%) rename ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/{ => otel}/OTelTracer.java (89%) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index a9559c8e..08484e6f 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -2,7 +2,7 @@ import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.provider.observability.tracers.TracerType; /** *

    @@ -19,7 +19,7 @@ *

  • VIP down event
  • * *

    - * The available tracers are defined in the enumeration {@link Tracer}, and + * The available tracers are defined in the enumeration {@link TracerType}, and * can be enabled using the method * {@link ObservabilityConfiguration#setEnabledTracers(String)}. The method * {@link ObservabilityConfiguration#setSensitiveDataEnabled(boolean)} allows @@ -51,7 +51,7 @@ public static final ObservabilityTraceEventListener getInstance() { public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} Object[] currentUserContext = getCurrentUserContext(userContext); - for (Tracer tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + for (TracerType tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext[tracer.ordinal()]); currentUserContext[tracer.ordinal()] = newUserContext; } @@ -63,7 +63,7 @@ public Object roundTrip(Sequence sequence, TraceContext traceContext, Object use public Object onExecutionEventReceived(JdbcExecutionEvent event, Object userContext, Object... params) { if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} Object[] currentUserContext = getCurrentUserContext(userContext); - for (Tracer tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { + for (TracerType tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext[tracer.ordinal()], params); currentUserContext[tracer.ordinal()] = newUserContext; } @@ -82,7 +82,7 @@ private Object[] getCurrentUserContext(Object userContext) { if (userContext != null && (userContext instanceof Object[])) { currentUserContext = (Object[]) userContext; } else { - currentUserContext = new Object[Tracer.values().length]; + currentUserContext = new Object[TracerType.values().length]; } return currentUserContext; } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 50f84221..4967da31 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -31,7 +31,7 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen /** * System property used to enabled/disable tracers. The value of this system property should be a comma separated list - * of {@link Tracer} to enable. By default all tracers will be enabled. + * of {@link TracerType} to enable. By default all tracers will be enabled. */ private static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index e0dd7202..5d0a391c 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -5,7 +5,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.provider.observability.tracers.TracerType; /** * Implementation of {@link ObservabilityConfigurationMBean} that allows to @@ -29,7 +29,7 @@ private ObservabilityConfiguration() { } private boolean sensitiveDataEnabled; private String tracers; - private List enabledTracers = new ArrayList<>(); + private List enabledTracers = new ArrayList<>(); /** * Returns true if the provider is enabled, otherwise false. @@ -38,7 +38,12 @@ private ObservabilityConfiguration() { } */ @Override public boolean getEnabled() { - return enabled; + try { + observabilityConfiguraitonLock.lock(); + return enabled; + } finally { + observabilityConfiguraitonLock.unlock(); + } } /** @@ -48,7 +53,12 @@ public boolean getEnabled() { */ @Override public void setEnabled(boolean enabled) { - this.enabled = enabled; + try { + observabilityConfiguraitonLock.lock(); + this.enabled = enabled; + } finally { + observabilityConfiguraitonLock.unlock(); + } } /** @@ -65,7 +75,7 @@ public String getEnabledTracers() { } /** - * Enables the tracers. Available tracers are defined in enum {@link Tracer}. + * Enables the tracers. Available tracers are defined in enum {@link TracerType}. * * @param tracers comma separated list of enabled tracers. */ @@ -77,7 +87,7 @@ public void setEnabledTracers(String tracers) { String[] items = tracers.split(","); for (String item : items) { if (item != null) { - enabledTracers.add(Tracer.valueOf(item.toUpperCase())); + enabledTracers.add(TracerType.valueOf(item.toUpperCase())); } } this.tracers = enabledTracers.stream().map((item) -> item.toString()).collect(Collectors.joining(",")); @@ -92,7 +102,12 @@ public void setEnabledTracers(String tracers) { */ @Override public boolean getSensitiveDataEnabled() { - return sensitiveDataEnabled; + try { + observabilityConfiguraitonLock.lock(); + return sensitiveDataEnabled; + } finally { + observabilityConfiguraitonLock.unlock(); + } } /** @@ -102,7 +117,12 @@ public boolean getSensitiveDataEnabled() { */ @Override public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { - this.sensitiveDataEnabled = sensitiveDataEnabled; + try { + observabilityConfiguraitonLock.lock(); + this.sensitiveDataEnabled = sensitiveDataEnabled; + } finally { + observabilityConfiguraitonLock.unlock(); + } } /** @@ -110,15 +130,25 @@ public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { * @return the singleton instance of {@link ObservabilityConfiguration}. */ public static ObservabilityConfiguration getInstance() { - return INSTANCE; + try { + observabilityConfiguraitonLock.lock(); + return INSTANCE; + } finally { + observabilityConfiguraitonLock.unlock(); + } } /** - * Returns a list of enabled {@link Tracer}. - * @return then list of nabled {@link Tracer}. + * Returns a list of enabled {@link TracerType}. + * @return then list of nabled {@link TracerType}. */ - public List getEnabledTracersSet() { - return enabledTracers; + public List getEnabledTracersSet() { + try { + observabilityConfiguraitonLock.lock(); + return enabledTracers; + } finally { + observabilityConfiguraitonLock.unlock(); + } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java index e67d7fb4..41457aaf 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java @@ -1,6 +1,6 @@ package oracle.jdbc.provider.observability.configuration; -import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.provider.observability.tracers.TracerType; /** * MBean that allows to configure the Oracle JDBC Observability Provider. @@ -29,7 +29,7 @@ public interface ObservabilityConfigurationMBean { public String getEnabledTracers(); /** - * Enables the tracers. Available tracers are defined in enum {@link Tracer}. + * Enables the tracers. Available tracers are defined in enum {@link TracerType}. * * @param tracers comma separated list of enabled tracers. */ diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java similarity index 72% rename from ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java rename to ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java index 3b74d2f2..fec5fea9 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/Tracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java @@ -1,10 +1,13 @@ package oracle.jdbc.provider.observability.tracers; +import oracle.jdbc.provider.observability.tracers.jfr.JFRTracer; +import oracle.jdbc.provider.observability.tracers.otel.OTelTracer; + /** * This interface defines the constants that are used to identify the * {@link ObservabilityTracer}. */ -public enum Tracer { +public enum TracerType { /** * Open Telemetry tracer. */ @@ -17,12 +20,12 @@ public enum Tracer { private ObservabilityTracer tracer; - Tracer(ObservabilityTracer tracer) { + TracerType(ObservabilityTracer tracer) { this.tracer = tracer; } /** - * Returns the {@link ObservabilityTracer} for this {@link Tracer}. + * Returns the {@link ObservabilityTracer} for this {@link TracerType}. * @return the {@link ObservabilityTracer}. */ public ObservabilityTracer getTracer() { diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java similarity index 99% rename from ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java rename to ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java index eb7977c0..bc73268d 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFREventFactory.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java @@ -1,4 +1,4 @@ -package oracle.jdbc.provider.observability.tracers; +package oracle.jdbc.provider.observability.tracers.jfr; import jdk.jfr.Event; import jdk.jfr.Label; @@ -10,7 +10,7 @@ import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.JFREventFactory.ExecutionEvent; +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; /** * Factory class for creating JFR events depending on the database function. diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java similarity index 84% rename from ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java rename to ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java index ba233c56..f7f7ee64 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java @@ -1,10 +1,11 @@ -package oracle.jdbc.provider.observability.tracers; +package oracle.jdbc.provider.observability.tracers.jfr; import jdk.jfr.Event; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; -import oracle.jdbc.provider.observability.tracers.JFREventFactory.RoundTripEvent; +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; +import oracle.jdbc.provider.observability.tracers.jfr.JFREventFactory.RoundTripEvent; /** * {@link ObservabilityTracer} for tracing Java Flight Recorder events. diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java similarity index 89% rename from ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java rename to ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java index 8ba559c5..f2fe36ac 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java @@ -1,4 +1,4 @@ -package oracle.jdbc.provider.observability.tracers; +package oracle.jdbc.provider.observability.tracers.otel; import java.sql.SQLException; import java.time.Instant; @@ -23,6 +23,7 @@ import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; /** * Open Telemetry tracer. Exports round trip event and execution events to @@ -30,10 +31,22 @@ */ public class OTelTracer implements ObservabilityTracer { + /** + * Key used to send the current Open Telemetry Trace Context to the server + * using {@link TraceContext#setClientInfo(String, String)}. + */ private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; + /** + * Open Telemetry tracer. + */ private Tracer tracer; + /** + * Logger. + */ + private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); + /** * Constructor. Uses {@link GlobalOpenTelemetry} to get the tracer. */ @@ -50,11 +63,10 @@ public OTelTracer(Tracer tracer) { } - private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); @Override public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { -if (sequence == Sequence.BEFORE) { + if (sequence == Sequence.BEFORE) { // Create the Span before the round-trip. final Span span = initAndGetSpan(traceContext, traceContext.databaseOperation()); try (Scope ignored = span.makeCurrent()) { @@ -71,7 +83,7 @@ public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Objec if (userContext instanceof Span) { final Span span = (Span) userContext; span.setStatus(traceContext.isCompletedExceptionally() ? StatusCode.ERROR : StatusCode.OK); - endSpan(span); + span.end(Instant.now()); } return null; } @@ -138,16 +150,17 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { .setAttribute("Actual SQL Text", traceContext.actualSqlText()); } - // Indicates that the span covers server-side handling of an RPC or other remote - // request. - return spanBuilder.setSpanKind(SpanKind.SERVER).startSpan(); - - } + // According to the semantic conventions the Span Kind should be CLIENT, + // used to be SERVER. + return spanBuilder.setSpanKind(SpanKind.CLIENT).startSpan(); - private void endSpan(Span span) { - span.end(Instant.now()); } + /** + * Builds the Open Telemetry trace context to be sent to the database server. + * @param span the currect spans + * @return the current trace context formatted so that the server can read it. + */ private String getTraceValue(Span span) { final String traceParent = initAndGetTraceParent(span); final String traceState = initAndGetTraceState(span); diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index 75ba85d9..a62b152a 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.provider.observability.tracers.TracerType; import oracle.jdbc.spi.TraceEventListenerProvider; public class ObservabilityConfigurationTest { @@ -30,7 +30,7 @@ public void testConfiguration() throws Exception { assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); // MBean ObjectName objectName = new ObjectName( @@ -52,8 +52,8 @@ public void testConfiguration() throws Exception { assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); assertEquals(2, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); - assertEquals(Tracer.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(1)); + assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(1)); // Singleton ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); @@ -66,7 +66,7 @@ public void testConfiguration() throws Exception { assertEquals("true", sensitiveDataEnabled); assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java index edc9ae2c..2719e235 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.Tracer; +import oracle.jdbc.provider.observability.tracers.TracerType; import oracle.jdbc.spi.TraceEventListenerProvider; public class BackwardCompatibilityTest { @@ -30,7 +30,7 @@ public void testConfiguration() throws Exception { assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); // MBean ObjectName objectName = new ObjectName( @@ -54,7 +54,7 @@ public void testConfiguration() throws Exception { assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); // Singleton ObservabilityConfiguration.getInstance().setEnabled(true); @@ -69,7 +69,7 @@ public void testConfiguration() throws Exception { assertEquals("true", sensitiveDataEnabled); assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(Tracer.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); } } From 8142aa0112098dc78b8b68c7ea9bd232953896d3 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 11:03:28 +0100 Subject: [PATCH 12/25] Fixed tests --- ...servabilityTraceEventListenerProvider.java | 17 ---------- .../ObservabilityConfiguration.java | 32 ++++++++++++++----- .../tracers/otel/OTelTracer.java | 27 +++++----------- .../ObservabilityConfigurationTest.java | 10 +++--- 4 files changed, 38 insertions(+), 48 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 4967da31..482cae01 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -29,18 +29,6 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"; private static ObjectName objectName; - /** - * System property used to enabled/disable tracers. The value of this system property should be a comma separated list - * of {@link TracerType} to enable. By default all tracers will be enabled. - */ - private static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; - - /** - * System property used to enable/disable exporting sensitive data. Set the property to true to enable sensitive data. - * By default exporting sensitive data is disabled. - */ - private static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; - /** * Logger */ @@ -71,11 +59,6 @@ public ObservabilityTraceEventListenerProvider() { } public TraceEventListener getTraceEventListener(Map map) { try { if (!server.isRegistered(objectName)) { - String enabledTracers = System.getProperty(ENABLED_TRACERS, "OTEL,JFR"); - String sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, "false"); - ObservabilityConfiguration.getInstance().setEnabledTracers(enabledTracers); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(Boolean.parseBoolean(sensitiveDataEnabled)); - server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); } } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index 5d0a391c..8633dec8 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -13,17 +13,21 @@ */ public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { - private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); + /** + * System property used to enabled/disable tracers. The value of this system property should be a comma separated list + * of {@link TracerType} to enable. By default all tracers will be enabled. + */ + private static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; - private static final ObservabilityConfiguration INSTANCE; + /** + * System property used to enable/disable exporting sensitive data. Set the property to true to enable sensitive data. + * By default exporting sensitive data is disabled. + */ + private static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; - static { - INSTANCE = new ObservabilityConfiguration(); - //INSTANCE.setSensitiveDataEnabled(true); - INSTANCE.setEnabledTracers(System.getProperty("oracle.jdbc.provider.observability.tracer", "OTEL,JFR")); - } + private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); - private ObservabilityConfiguration() { } + private static final ObservabilityConfiguration INSTANCE; private boolean enabled = true; private boolean sensitiveDataEnabled; @@ -31,6 +35,18 @@ private ObservabilityConfiguration() { } private List enabledTracers = new ArrayList<>(); + + static { + INSTANCE = new ObservabilityConfiguration(); + } + + private ObservabilityConfiguration() { + String enabledTracers = System.getProperty(ENABLED_TRACERS, "OTEL,JFR"); + String sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, "false"); + setEnabledTracers(enabledTracers); + setSensitiveDataEnabled(Boolean.valueOf(sensitiveDataEnabled)); + } + /** * Returns true if the provider is enabled, otherwise false. * diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java index f2fe36ac..3143c790 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java @@ -37,10 +37,7 @@ public class OTelTracer implements ObservabilityTracer { */ private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; - /** - * Open Telemetry tracer. - */ - private Tracer tracer; + /** * Logger. @@ -48,21 +45,10 @@ public class OTelTracer implements ObservabilityTracer { private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); /** - * Constructor. Uses {@link GlobalOpenTelemetry} to get the tracer. - */ - public OTelTracer() { - this(GlobalOpenTelemetry.get().getTracer(OTelTracer.class.getName())); - } - - /** - * Constructor. - * @param tracer Open Telemetry tracer. + * Constructor. This tracer always uses {@link GlobalOpenTelemetry} to get + * the Open Telemetry tracer. */ - public OTelTracer(Tracer tracer) { - this.tracer = tracer; - } - - + public OTelTracer() { } @Override public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { @@ -92,6 +78,7 @@ public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Objec @Override public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { if (EXECUTION_EVENTS_PARAMETERS.get(event) == params.length) { + Tracer tracer = GlobalOpenTelemetry.get().getTracer(OTelTracer.class.getName()); if (event == TraceEventListener.JdbcExecutionEvent.VIP_RETRY) { SpanBuilder spanBuilder = tracer .spanBuilder(event.getDescription()) @@ -133,6 +120,7 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { * child span to the current span. I.e. the current span in context becomes * parent to this child span. */ + Tracer tracer = GlobalOpenTelemetry.get().getTracer(OTelTracer.class.getName()); SpanBuilder spanBuilder = tracer .spanBuilder(spanName) .setAttribute("thread.id", Thread.currentThread().getId()) @@ -146,7 +134,8 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { // Add sensitive information (URL and SQL) if it is enabled if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { logger.log(Level.FINEST, "Sensitive information on"); - spanBuilder.setAttribute("Original SQL Text", traceContext.originalSqlText()) + spanBuilder + .setAttribute("Original SQL Text", traceContext.originalSqlText()) .setAttribute("Actual SQL Text", traceContext.actualSqlText()); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index a62b152a..68663c97 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -16,13 +16,15 @@ public class ObservabilityConfigurationTest { - @Test - public void testConfiguration() throws Exception { - - // System properties + // Set system properties before starting + static { System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "JFR"); System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "true"); + } + @Test + public void testConfiguration() throws Exception { + TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); provider.getTraceEventListener(null); From 01cfd1232f85de6928d443a894f8cf4a34edf6fb Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 11:27:03 +0100 Subject: [PATCH 13/25] Observability configuration test --- .../configuration/ObservabilityConfiguration.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index 8633dec8..a2423f13 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -27,7 +27,7 @@ public class ObservabilityConfiguration implements ObservabilityConfigurationMBe private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); - private static final ObservabilityConfiguration INSTANCE; + private static final ObservabilityConfiguration INSTANCE = new ObservabilityConfiguration(); private boolean enabled = true; private boolean sensitiveDataEnabled; @@ -35,11 +35,6 @@ public class ObservabilityConfiguration implements ObservabilityConfigurationMBe private List enabledTracers = new ArrayList<>(); - - static { - INSTANCE = new ObservabilityConfiguration(); - } - private ObservabilityConfiguration() { String enabledTracers = System.getProperty(ENABLED_TRACERS, "OTEL,JFR"); String sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, "false"); From ad7df96a7d12607139f5aee68e78e7b715b1b6a4 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 11:47:25 +0100 Subject: [PATCH 14/25] Added debug info --- .../observability/ObservabilityConfigurationTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index 68663c97..7a23cdb0 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -20,14 +20,17 @@ public class ObservabilityConfigurationTest { static { System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "JFR"); System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "true"); + System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); } @Test public void testConfiguration() throws Exception { - + + System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); provider.getTraceEventListener(null); + System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); assertEquals("JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); From ac08356493ecef89b2c10551b2816c94eb615dc5 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 12:19:56 +0100 Subject: [PATCH 15/25] Run tests one by one --- ojdbc-provider-observability/pom.xml | 112 +++++++++++++++------------ 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index fe07046e..06671f9b 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -1,58 +1,68 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - com.oracle.database.jdbc - ojdbc-extensions - 1.0.3 - - - Oracle JDBC Observability Provider - com.oracle.database.jdbc - ojdbc-provider-observability - 1.0.3 + + com.oracle.database.jdbc + ojdbc-extensions + 1.0.3 + - - 1.44.1 - 11 - 11 - + Oracle JDBC Observability Provider + com.oracle.database.jdbc + ojdbc-provider-observability + 1.0.3 - - - com.oracle.database.jdbc - ojdbc11 - - - io.opentelemetry - opentelemetry-api - ${opentelemetry.version} - - - org.mockito - mockito-core - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.jupiter - junit-jupiter-params - test - - - ojdbc-provider-common - com.oracle.database.jdbc - 1.0.2 - tests - test-jar - - + + 1.44.1 + 11 + 11 + + + + com.oracle.database.jdbc + ojdbc11 + + + io.opentelemetry + opentelemetry-api + ${opentelemetry.version} + + + org.mockito + mockito-core + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + ojdbc-provider-common + com.oracle.database.jdbc + 1.0.2 + tests + test-jar + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + none + + + + \ No newline at end of file From 8478b83607c09e1cde7b28e1ed5ddc464c9d705e Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 12:31:46 +0100 Subject: [PATCH 16/25] Test Order --- ojdbc-provider-observability/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index 06671f9b..0050aff8 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -61,6 +61,7 @@ maven-surefire-plugin none + alphabetical From 6b03e6ff2c204cec69f205b64f10fe7c324ef743 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 12:37:50 +0100 Subject: [PATCH 17/25] Added comment for test run configuration. --- ojdbc-provider-observability/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index 0050aff8..ead8150e 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -60,6 +60,12 @@ org.apache.maven.plugins maven-surefire-plugin + none alphabetical From c8a8cdf2d934a21c70918da0e6856aaf58d1d71f Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 24 Feb 2025 15:20:24 +0100 Subject: [PATCH 18/25] Backward compatibility --- .../services/oracle.jdbc.spi.TraceEventListenerProvider | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider index b1c86eef..9b12f75b 100644 --- a/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider +++ b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider @@ -1,2 +1,2 @@ oracle.jdbc.provider.observability.ObservabilityTraceEventListenerProvider -oracle.jdbc.provider.observability.OpenTelemetryTraceEventListenerProvider \ No newline at end of file +oracle.jdbc.provider.opentelemetry.OpenTelemetryTraceEventListenerProvider \ No newline at end of file From dee07b4ca9426a9582c48bffc017af42a2513838 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Tue, 25 Feb 2025 18:35:52 +0100 Subject: [PATCH 19/25] Locks and event labels --- .../ObservabilityConfiguration.java | 16 +- .../tracers/jfr/JFREventFactory.java | 146 +++++++++--------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java index a2423f13..4e4e7b27 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java @@ -49,8 +49,8 @@ private ObservabilityConfiguration() { */ @Override public boolean getEnabled() { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); return enabled; } finally { observabilityConfiguraitonLock.unlock(); @@ -64,8 +64,8 @@ public boolean getEnabled() { */ @Override public void setEnabled(boolean enabled) { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); this.enabled = enabled; } finally { observabilityConfiguraitonLock.unlock(); @@ -77,8 +77,8 @@ public void setEnabled(boolean enabled) { */ @Override public String getEnabledTracers() { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); return tracers; } finally { observabilityConfiguraitonLock.unlock(); @@ -92,8 +92,8 @@ public String getEnabledTracers() { */ @Override public void setEnabledTracers(String tracers) { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); enabledTracers.clear(); String[] items = tracers.split(","); for (String item : items) { @@ -113,8 +113,8 @@ public void setEnabledTracers(String tracers) { */ @Override public boolean getSensitiveDataEnabled() { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); return sensitiveDataEnabled; } finally { observabilityConfiguraitonLock.unlock(); @@ -128,8 +128,8 @@ public boolean getSensitiveDataEnabled() { */ @Override public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); this.sensitiveDataEnabled = sensitiveDataEnabled; } finally { observabilityConfiguraitonLock.unlock(); @@ -141,8 +141,8 @@ public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { * @return the singleton instance of {@link ObservabilityConfiguration}. */ public static ObservabilityConfiguration getInstance() { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); return INSTANCE; } finally { observabilityConfiguraitonLock.unlock(); @@ -154,8 +154,8 @@ public static ObservabilityConfiguration getInstance() { * @return then list of nabled {@link TracerType}. */ public List getEnabledTracersSet() { + observabilityConfiguraitonLock.lock(); try { - observabilityConfiguraitonLock.lock(); return enabledTracers; } finally { observabilityConfiguraitonLock.unlock(); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java index bc73268d..24158877 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java @@ -206,7 +206,7 @@ public static Event createExecutionEvent(JdbcExecutionEvent event, Object... par // Round-trip events @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_12C_EMON_DEQUEUE") - @Label("Round trip") + @Label("AQ 12c emon dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuing12cEminDequeueEvent extends RoundTripEvent{ public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext) { @@ -215,7 +215,7 @@ public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_ARRAY_ENQUEUE_DEQUEUE") - @Label("Round trip") + @Label("AQ Array Enqueue/Dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingArrayEnqueueDequeue extends RoundTripEvent{ public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext) { @@ -224,7 +224,7 @@ public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_DEQUEUE_V8") - @Label("Round trip") + @Label("AQ Dequeue before 8.1") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingDequeueV8 extends RoundTripEvent{ public AdvancedQueuingDequeueV8(TraceContext traceContext) { @@ -233,7 +233,7 @@ public AdvancedQueuingDequeueV8(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_ENQUEUE") - @Label("Round trip") + @Label("AQ EnQueue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingEnqueue extends RoundTripEvent{ public AdvancedQueuingEnqueue(TraceContext traceContext) { @@ -242,7 +242,7 @@ public AdvancedQueuingEnqueue(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_GET_PROPAGATION_STATUS") - @Label("Round trip") + @Label("AQ get propagation status entries") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingGetPropagationStatus extends RoundTripEvent{ public AdvancedQueuingGetPropagationStatus(TraceContext traceContext) { @@ -251,7 +251,7 @@ public AdvancedQueuingGetPropagationStatus(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_LISTEN") - @Label("Round trip") + @Label("AQ Listen") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingListen extends RoundTripEvent{ public AdvancedQueuingListen(TraceContext traceContext) { @@ -260,7 +260,7 @@ public AdvancedQueuingListen(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SESSION_GET_RPC_1") - @Label("Round trip") + @Label("Session get RPC in server pool scenario") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSessionGetRPC1 extends RoundTripEvent{ public AdvancedQueuingSessionGetRPC1(TraceContext traceContext) { @@ -269,7 +269,7 @@ public AdvancedQueuingSessionGetRPC1(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SESSION_GET_RPC_2") - @Label("Round trip") + @Label("Session get RPC in server pool scenario") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSessionGetRPC2 extends RoundTripEvent{ public AdvancedQueuingSessionGetRPC2(TraceContext traceContext) { @@ -278,7 +278,7 @@ public AdvancedQueuingSessionGetRPC2(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SHARED_DEQUEUE") - @Label("Round trip") + @Label("AQ Sharded dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSharedDequeue extends RoundTripEvent{ public AdvancedQueuingSharedDequeue(TraceContext traceContext) { @@ -287,7 +287,7 @@ public AdvancedQueuingSharedDequeue(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ADVANCED_QUEUING_SHARED_ENQUEUE") - @Label("Round trip") + @Label("AQ Sharded enqueue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSharedEnqueue extends RoundTripEvent{ public AdvancedQueuingSharedEnqueue(TraceContext traceContext) { @@ -296,7 +296,7 @@ public AdvancedQueuingSharedEnqueue(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.APP_REPLAY") - @Label("Round trip") + @Label("Application continuity REPLAY") @Category({"Oracle JDBC", "Round trips"}) static class AppReplay extends RoundTripEvent{ public AppReplay(TraceContext traceContext) { @@ -305,7 +305,7 @@ public AppReplay(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.AUTH_CALL") - @Label("Round trip") + @Label("Generic authentication call") @Category({"Oracle JDBC", "Round trips"}) static class AuthCall extends RoundTripEvent{ public AuthCall(TraceContext traceContext) { @@ -314,7 +314,7 @@ public AuthCall(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.AUTO_COMMIT_OFF") - @Label("Round trip") + @Label("Auto commit off") @Category({"Oracle JDBC", "Round trips"}) static class AutoCommitOff extends RoundTripEvent{ public AutoCommitOff(TraceContext traceContext) { @@ -323,7 +323,7 @@ public AutoCommitOff(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.AUTO_COMMIT_ON") - @Label("Round trip") + @Label("Auto commit on") @Category({"Oracle JDBC", "Round trips"}) static class AutoCommitOn extends RoundTripEvent{ public AutoCommitOn(TraceContext traceContext) { @@ -332,7 +332,7 @@ public AutoCommitOn(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CANCEL_ALL") - @Label("Round trip") + @Label("Cancel All") @Category({"Oracle JDBC", "Round trips"}) static class CancelAll extends RoundTripEvent{ public CancelAll(TraceContext traceContext) { @@ -341,7 +341,7 @@ public CancelAll(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CANCEL_OPERATION") - @Label("Round trip") + @Label("Cancel the current operation") @Category({"Oracle JDBC", "Round trips"}) static class CancelOperation extends RoundTripEvent{ public CancelOperation(TraceContext traceContext) { @@ -350,7 +350,7 @@ public CancelOperation(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CHUNCK_INFO") - @Label("Round trip") + @Label("Chunk info RPC") @Category({"Oracle JDBC", "Round trips"}) static class ChunkInfo extends RoundTripEvent{ public ChunkInfo(TraceContext traceContext) { @@ -359,7 +359,7 @@ public ChunkInfo(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_FEATURES") - @Label("Round trip") + @Label("Client features") @Category({"Oracle JDBC", "Round trips"}) static class ClientFeatures extends RoundTripEvent{ public ClientFeatures(TraceContext traceContext) { @@ -368,7 +368,7 @@ public ClientFeatures(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_QUERY_CACHE_IDS") - @Label("Round trip") + @Label("Client query cache IDs") @Category({"Oracle JDBC", "Round trips"}) static class ClientQueryCacheIds extends RoundTripEvent{ public ClientQueryCacheIds(TraceContext traceContext) { @@ -377,7 +377,7 @@ public ClientQueryCacheIds(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CLIENT_QUERY_CACHE_STATS_UPDATE") - @Label("Round trip") + @Label("Client query cache statistics update") @Category({"Oracle JDBC", "Round trips"}) static class ClientQueryCacheStatsUpdate extends RoundTripEvent{ public ClientQueryCacheStatsUpdate(TraceContext traceContext) { @@ -386,7 +386,7 @@ public ClientQueryCacheStatsUpdate(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CLOSE_ALL_CURSOR") - @Label("Round trip") + @Label("Cursor close all") @Category({"Oracle JDBC", "Round trips"}) static class CloseAllCursor extends RoundTripEvent{ public CloseAllCursor(TraceContext traceContext) { @@ -395,7 +395,7 @@ public CloseAllCursor(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.CLOSE_CURSOR") - @Label("Round trip") + @Label("Close a cursor") @Category({"Oracle JDBC", "Round trips"}) static class CloseCursor extends RoundTripEvent{ public CloseCursor(TraceContext traceContext) { @@ -404,7 +404,7 @@ public CloseCursor(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.COMMIT") - @Label("Round trip") + @Label("Commit") @Category({"Oracle JDBC", "Round trips"}) static class Commit extends RoundTripEvent{ public Commit(TraceContext traceContext) { @@ -413,7 +413,7 @@ public Commit(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DB12C_NOTIFICATION_RCV") - @Label("Round trip") + @Label("12c notification receive") @Category({"Oracle JDBC", "Round trips"}) static class DB12cNotificationRCV extends RoundTripEvent{ public DB12cNotificationRCV(TraceContext traceContext) { @@ -422,7 +422,7 @@ public DB12cNotificationRCV(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DBNS_SAGAS") - @Label("Round trip") + @Label("DBMS Sagas") @Category({"Oracle JDBC", "Round trips"}) static class DBNSSagas extends RoundTripEvent{ public DBNSSagas(TraceContext traceContext) { @@ -431,7 +431,7 @@ public DBNSSagas(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_ANY_V8") - @Label("Round trip") + @Label("V8 Describe Any") @Category({"Oracle JDBC", "Round trips"}) static class DescribeAnyV8 extends RoundTripEvent{ public DescribeAnyV8(TraceContext traceContext) { @@ -440,7 +440,7 @@ public DescribeAnyV8(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_ARRAY") - @Label("Round trip") + @Label("Array describe") @Category({"Oracle JDBC", "Round trips"}) static class DescribeArray extends RoundTripEvent{ public DescribeArray(TraceContext traceContext) { @@ -449,7 +449,7 @@ public DescribeArray(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DESCRIBE_QUERY_CALL") - @Label("Round trip") + @Label("New describe query call") @Category({"Oracle JDBC", "Round trips"}) static class DescribeQueryCall extends RoundTripEvent{ public DescribeQueryCall(TraceContext traceContext) { @@ -458,7 +458,7 @@ public DescribeQueryCall(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_LOAD_STREAM") - @Label("Round trip") + @Label("Direct Path Load Stream") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathLoadStream extends RoundTripEvent{ public DirectPathLoadStream(TraceContext traceContext) { @@ -467,7 +467,7 @@ public DirectPathLoadStream(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_MISC_OP") - @Label("Round trip") + @Label("Direct Path Misc Operations") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathMISCOp extends RoundTripEvent{ public DirectPathMISCOp(TraceContext traceContext) { @@ -476,7 +476,7 @@ public DirectPathMISCOp(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DIRECT_PATH_PREPARE") - @Label("Round trip") + @Label("Direct Path Prepare") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathPrepare extends RoundTripEvent{ public DirectPathPrepare(TraceContext traceContext) { @@ -485,7 +485,7 @@ public DirectPathPrepare(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.DISTRIBUTED_TRANS_MGR_RPC") - @Label("Round trip") + @Label("Distributed transaction manager RPC") @Category({"Oracle JDBC", "Round trips"}) static class DistributedTransMGRRPC extends RoundTripEvent{ public DistributedTransMGRRPC(TraceContext traceContext) { @@ -494,7 +494,7 @@ public DistributedTransMGRRPC(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.EXECUTE_QUERY") - @Label("Round trip") + @Label("Execute query") @Category({"Oracle JDBC", "Round trips"}) static class ExecuteQuery extends RoundTripEvent{ public ExecuteQuery(TraceContext traceContext) { @@ -503,7 +503,7 @@ public ExecuteQuery(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_CREATE") - @Label("Round trip") + @Label("eXtensible Security Sessions Create Session") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionCreate extends RoundTripEvent{ public ExtensibleSecuritySessionCreate(TraceContext traceContext) { @@ -512,7 +512,7 @@ public ExtensibleSecuritySessionCreate(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_PIGGYBACK") - @Label("Round trip") + @Label("eXtensible Security Sessions Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionPiggyback extends RoundTripEvent{ public ExtensibleSecuritySessionPiggyback(TraceContext traceContext) { @@ -521,7 +521,7 @@ public ExtensibleSecuritySessionPiggyback(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.EXTENSIBLE_SECURITY_SESSION_ROUNDTRIP") - @Label("Round trip") + @Label("eXtensible Security Session Roundtrip") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionRoundtrip extends RoundTripEvent{ public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext) { @@ -530,7 +530,7 @@ public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.FAST_UPI_CALLS") - @Label("Round trip") + @Label("Fast UPI calls to opial7") @Category({"Oracle JDBC", "Round trips"}) static class FastUPICalls extends RoundTripEvent{ public FastUPICalls(TraceContext traceContext) { @@ -539,7 +539,7 @@ public FastUPICalls(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.FETCH_ROW") - @Label("Round trip") + @Label("Fetch a row") @Category({"Oracle JDBC", "Round trips"}) static class FetchRow extends RoundTripEvent{ public FetchRow(TraceContext traceContext) { @@ -548,7 +548,7 @@ public FetchRow(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.GET_VERSION") - @Label("Round trip") + @Label("Get Oracle version-date string in new format") @Category({"Oracle JDBC", "Round trips"}) static class GetVersion extends RoundTripEvent{ public GetVersion(TraceContext traceContext) { @@ -557,7 +557,7 @@ public GetVersion(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.KERNEL_PROGRAMMATIC_NOTIFICATION") - @Label("Round trip") + @Label("Kernel Programmatic Notification") @Category({"Oracle JDBC", "Round trips"}) static class KernelProgrammaticNotification extends RoundTripEvent{ public KernelProgrammaticNotification(TraceContext traceContext) { @@ -566,7 +566,7 @@ public KernelProgrammaticNotification(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.KEY_VALUE") - @Label("Round trip") + @Label("Client app context, namespace, attribute, values") @Category({"Oracle JDBC", "Round trips"}) static class KeyValue extends RoundTripEvent{ public KeyValue(TraceContext traceContext) { @@ -575,7 +575,7 @@ public KeyValue(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.LOB_FILE_CALL") - @Label("Round trip") + @Label("LOB and FILE related calls") @Category({"Oracle JDBC", "Round trips"}) static class LOBFileCall extends RoundTripEvent{ public LOBFileCall(TraceContext traceContext) { @@ -584,7 +584,7 @@ public LOBFileCall(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.LOGOFF") - @Label("Round trip") + @Label("Logoff of Oracle") @Category({"Oracle JDBC", "Round trips"}) static class LogOff extends RoundTripEvent{ public LogOff(TraceContext traceContext) { @@ -593,7 +593,7 @@ public LogOff(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.LOGON_CHALLENGE_RESPONSE_1") - @Label("Round trip") + @Label("First half of challenge-response logon") @Category({"Oracle JDBC", "Round trips"}) static class LogonChallengeResponse1 extends RoundTripEvent{ public LogonChallengeResponse1(TraceContext traceContext) { @@ -602,7 +602,7 @@ public LogonChallengeResponse1(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.LOGON_CHALLENGE_RESPONSE_2") - @Label("Round trip") + @Label("Second half of challenge-response logon") @Category({"Oracle JDBC", "Round trips"}) static class LogonChallengeResponse2 extends RoundTripEvent{ public LogonChallengeResponse2(TraceContext traceContext) { @@ -611,7 +611,7 @@ public LogonChallengeResponse2(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.OEXFEN") - @Label("Round trip") + @Label("OEXFEN") @Category({"Oracle JDBC", "Round trips"}) static class OEXFEN extends RoundTripEvent{ public OEXFEN(TraceContext traceContext) { @@ -620,7 +620,7 @@ public OEXFEN(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.OPEN_CURSOR") - @Label("Round trip") + @Label("Open a cursor") @Category({"Oracle JDBC", "Round trips"}) static class OpenCursor extends RoundTripEvent{ public OpenCursor(TraceContext traceContext) { @@ -629,7 +629,7 @@ public OpenCursor(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.OSQL7") - @Label("Round trip") + @Label("OSQL7") @Category({"Oracle JDBC", "Round trips"}) static class OSQL7 extends RoundTripEvent{ public OSQL7(TraceContext traceContext) { @@ -638,7 +638,7 @@ public OSQL7(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.OSTART") - @Label("Round trip") + @Label("Starts Oracle") @Category({"Oracle JDBC", "Round trips"}) static class OStart extends RoundTripEvent{ public OStart(TraceContext traceContext) { @@ -647,7 +647,7 @@ public OStart(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.OSTOP") - @Label("Round trip") + @Label("Stops Oracle") @Category({"Oracle JDBC", "Round trips"}) static class OStop extends RoundTripEvent{ public OStop(TraceContext traceContext) { @@ -656,7 +656,7 @@ public OStop(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.PARAMETER_PUT_SPFILE") - @Label("Round trip") + @Label("Put parameter using spfile (for startup)") @Category({"Oracle JDBC", "Round trips"}) static class ParameterPutSPFile extends RoundTripEvent{ public ParameterPutSPFile(TraceContext traceContext) { @@ -665,7 +665,7 @@ public ParameterPutSPFile(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.PING") - @Label("Round trip") + @Label("Ping") @Category({"Oracle JDBC", "Round trips"}) static class Ping extends RoundTripEvent{ public Ping(TraceContext traceContext) { @@ -674,7 +674,7 @@ public Ping(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_END") - @Label("Round trip") + @Label("Pipeline End") @Category({"Oracle JDBC", "Round trips"}) static class PipelineEnd extends RoundTripEvent{ public PipelineEnd(TraceContext traceContext) { @@ -683,7 +683,7 @@ public PipelineEnd(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_PIGGYBACK_BEGIN") - @Label("Round trip") + @Label("Pipeline Begin Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class PipelinePiggybackBegin extends RoundTripEvent{ public PipelinePiggybackBegin(TraceContext traceContext) { @@ -692,7 +692,7 @@ public PipelinePiggybackBegin(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.PIPELINE_PIGGYBACK_OP") - @Label("Round trip") + @Label("Pipeline Operation Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class PipelinePiggybackOp extends RoundTripEvent{ public PipelinePiggybackOp(TraceContext traceContext) { @@ -701,7 +701,7 @@ public PipelinePiggybackOp(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.ROLLBACK") - @Label("Round trip") + @Label("Rollback") @Category({"Oracle JDBC", "Round trips"}) static class Rollback extends RoundTripEvent{ public Rollback(TraceContext traceContext) { @@ -710,7 +710,7 @@ public Rollback(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_KEY") - @Label("Round trip") + @Label("Get the session key") @Category({"Oracle JDBC", "Round trips"}) static class SessionKey extends RoundTripEvent{ public SessionKey(TraceContext traceContext) { @@ -719,7 +719,7 @@ public SessionKey(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_STATE_OPS") - @Label("Round trip") + @Label("Session state ops") @Category({"Oracle JDBC", "Round trips"}) static class SessionStateOps extends RoundTripEvent{ public SessionStateOps(TraceContext traceContext) { @@ -728,7 +728,7 @@ public SessionStateOps(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_STATE_TEMPLATE") - @Label("Round trip") + @Label("Session state template") @Category({"Oracle JDBC", "Round trips"}) static class SessionStateTemplate extends RoundTripEvent{ public SessionStateTemplate(TraceContext traceContext) { @@ -737,7 +737,7 @@ public SessionStateTemplate(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.SESSION_SWITCH_V8") - @Label("Round trip") + @Label("V8 session switching piggyback") @Category({"Oracle JDBC", "Round trips"}) static class SessionSwitchV8 extends RoundTripEvent{ public SessionSwitchV8(TraceContext traceContext) { @@ -746,7 +746,7 @@ public SessionSwitchV8(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.TRACING_MESSAGE") - @Label("Round trip") + @Label("End to end tracing message") @Category({"Oracle JDBC", "Round trips"}) static class TracingMessage extends RoundTripEvent{ public TracingMessage(TraceContext traceContext) { @@ -755,7 +755,7 @@ public TracingMessage(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.TRANSACTION_COMMIT") - @Label("Round trip") + @Label("Transaction commit, rollback, recover") @Category({"Oracle JDBC", "Round trips"}) static class TransactionCommit extends RoundTripEvent{ public TransactionCommit(TraceContext traceContext) { @@ -764,7 +764,7 @@ public TransactionCommit(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.TRANSACTION_START") - @Label("Round trip") + @Label("Transaction start, attach, detach") @Category({"Oracle JDBC", "Round trips"}) static class TransactionStart extends RoundTripEvent{ public TransactionStart(TraceContext traceContext) { @@ -773,7 +773,7 @@ public TransactionStart(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.TTC_DTY_ROUNDTRIP") - @Label("Round trip") + @Label("Data type message exchange") @Category({"Oracle JDBC", "Round trips"}) static class TTCDTYRoundtrip extends RoundTripEvent{ public TTCDTYRoundtrip(TraceContext traceContext) { @@ -782,7 +782,7 @@ public TTCDTYRoundtrip(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.TTC_PRO_ROUNDTRIP") - @Label("Round trip") + @Label("Protocol negotiation message exchange") @Category({"Oracle JDBC", "Round trips"}) static class TTCPRORoundtrip extends RoundTripEvent{ public TTCPRORoundtrip(TraceContext traceContext) { @@ -791,7 +791,7 @@ public TTCPRORoundtrip(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_ATTACH_SESSION") - @Label("Round trip") + @Label("XS Attach Session") @Category({"Oracle JDBC", "Round trips"}) static class XSAttachSession extends RoundTripEvent{ public XSAttachSession(TraceContext traceContext) { @@ -800,7 +800,7 @@ public XSAttachSession(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_CREATE_SESSION") - @Label("Round trip") + @Label("XS Create Session") @Category({"Oracle JDBC", "Round trips"}) static class XSCreateSession extends RoundTripEvent{ public XSCreateSession(TraceContext traceContext) { @@ -809,7 +809,7 @@ public XSCreateSession(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_DESTROY_SESSION") - @Label("Round trip") + @Label("XS Destroy Session") @Category({"Oracle JDBC", "Round trips"}) static class XSDestroySession extends RoundTripEvent{ public XSDestroySession(TraceContext traceContext) { @@ -818,7 +818,7 @@ public XSDestroySession(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_DETACH_SESSION") - @Label("Round trip") + @Label("XS Detach Session") @Category({"Oracle JDBC", "Round trips"}) static class XSDetachSession extends RoundTripEvent{ public XSDetachSession(TraceContext traceContext) { @@ -827,7 +827,7 @@ public XSDetachSession(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_NAMESPACE_OP") - @Label("Round trip") + @Label("XS Namespace OP") @Category({"Oracle JDBC", "Round trips"}) static class XSNamespaceOp extends RoundTripEvent{ public XSNamespaceOp(TraceContext traceContext) { @@ -836,7 +836,7 @@ public XSNamespaceOp(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_NAMESPACE_OPS") - @Label("Round trip") + @Label("XS namespace OPs") @Category({"Oracle JDBC", "Round trips"}) static class XSNamespaceOps extends RoundTripEvent{ public XSNamespaceOps(TraceContext traceContext) { @@ -845,7 +845,7 @@ public XSNamespaceOps(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_SET_SESSION_PARAMETER") - @Label("Round trip") + @Label("XS Set Session Parameter") @Category({"Oracle JDBC", "Round trips"}) static class XSSetSessionParameter extends RoundTripEvent{ public XSSetSessionParameter(TraceContext traceContext) { @@ -854,7 +854,7 @@ public XSSetSessionParameter(TraceContext traceContext) { } @Name("oracle.jdbc.provider.observability.RoundTrip.XS_STATE_SYNC_OP") - @Label("Round trip") + @Label("XS State Sync OP") @Category({"Oracle JDBC", "Round trips"}) static class XSStateSyncOp extends RoundTripEvent{ public XSStateSyncOp(TraceContext traceContext) { From c649e571ba3f8ba72e52739b869c669b52c62493 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 7 Mar 2025 09:29:57 +0100 Subject: [PATCH 20/25] Refactoring and added possibility to have different configuration and listeners --- ojdbc-provider-observability/README.md | 27 +- .../ObservabilityConfiguration.java | 333 ++++++++++++ .../ObservabilityConfigurationMBean.java | 96 ++++ .../ObservabilityTraceEventListener.java | 254 +++++++-- ...servabilityTraceEventListenerProvider.java | 93 ++-- ...enTelemetryTraceEventListenerProvider.java | 78 +++ .../ObservabilityConfiguration.java | 166 ------ .../ObservabilityConfigurationMBean.java | 51 -- .../tracers/ObservabilityTracer.java | 47 +- .../observability/tracers/TracerType.java | 34 -- .../tracers/jfr/JFREventFactory.java | 502 ++++++++++-------- .../observability/tracers/jfr/JFRTracer.java | 68 ++- .../tracers/otel/OTelTracer.java | 150 ++++-- ...enTelemetryTraceEventListenerProvider.java | 102 ---- ...oracle.jdbc.spi.TraceEventListenerProvider | 2 +- .../BackwardCompatibilityTest.java | 120 +++++ .../ObservabilityConfigurationTest.java | 108 ++-- .../ObservabilityTestProperties.java | 37 ++ .../ObservabilityTraceEventListenerTest.java | 63 ++- .../BackwardCompatibilityTest.java | 75 --- .../OpenTelemetryTraceEventListener.java | 12 +- .../OpenTelemetryTraceEventListenerTest.java | 8 +- 22 files changed, 1598 insertions(+), 828 deletions(-) create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfigurationMBean.java create mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java delete mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java delete mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java delete mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java delete mode 100644 ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java create mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java delete mode 100644 ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java diff --git a/ojdbc-provider-observability/README.md b/ojdbc-provider-observability/README.md index fa942914..cc17d12f 100644 --- a/ojdbc-provider-observability/README.md +++ b/ojdbc-provider-observability/README.md @@ -9,10 +9,10 @@ This provider implements the TraceEventListener interface provided by the JDBC driver which will be notified whenever events are generated in the driver and will publish these events into Open Telemetry. These events include: * roundtrips to the database server - * AC begin and sucess + * AC begin and success * VIP down event -The following attributes are added the the traces for each event: +The following attributes are added the traces for each event: * **Roundtrips** * Connection ID * Database Operation @@ -39,7 +39,7 @@ The following attributes are added the the traces for each event: ## Installation This provider is distributed as single jar on the Maven Central Repository. The -jar is compiled for JDK 8, and is forward compatible with later JDK versions. +jar is compiled for JDK 11, and is forward compatible with later JDK versions. The coordinates for the latest release are: ```xml @@ -62,11 +62,6 @@ oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provi ## Configuration The provider can be configured by: -* using the singleton configuration class, -```java -ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL,JFR"); -ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); -``` * using system properties, ```java System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "OTEL,JFR"); @@ -74,12 +69,19 @@ System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "t ``` * or using the MBean. ```java -ObjectName objectName = new ObjectName( - "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"); +ObservabilityTraceEventListener listener = ObservabilityTraceEventListener.getTraceEventListener(""); +ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", "true")); ``` +* it is also possible to use the ObservabilityConfiguration object directly by +calling the +```java +ObservabilityConfiguration configuration = ObservabilityTraceEventListener.getObservabilityConfiguration(""); +configuration.setEnabledTracers("OTEL,JFR"); +configuration.setSensitiveDataEnabled(true); +``` ## Backward compatibility @@ -109,13 +111,12 @@ or a MBean. Two parameters can be configured: The system properties are "oracle.jdbc.provider.opentelemetry.enabled" and "oracle.jdbc.provider.opentelemetry.sensitive-enabled" respectively and the MBean -with object name "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener" exposes two attributes "Enabled" and "SensitiveDataEnabled". The sample code below shows how to retrieve the value of an attribute: ```java -ObjectName objectName = new ObjectName( - "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener"); +ObservabilityTraceEventListener listener = ObservabilityTraceEventListener.getTraceEventListener(""); +ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); boolean isEnabled = Boolean.valueOf(server.getAttribute(objectName, "Enabled").toString()) .booleanValue(); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java new file mode 100644 index 00000000..4f417b7d --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java @@ -0,0 +1,333 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ +package oracle.jdbc.provider.observability; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; +import oracle.jdbc.provider.observability.tracers.jfr.JFRTracer; +import oracle.jdbc.provider.observability.tracers.otel.OTelTracer; + +/** + *

    + * Implementation of {@link ObservabilityConfigurationMBean} that allows to + * configure the Oracle JDBC Observability Provider. The system properties that + * can be used to configure the Observability Provider depend on the provider + * used: + *

    + * If {@link ObservabilityTraceEventListenerProvider} is being used: + *
      + *
    • {@link ObservabilityConfiguration#ENABLED_TRACERS}: comma separated list + * of enabled tracers, default "JFR,OTEL"
    • + *
    • {@link ObservabilityConfiguration#SENSITIVE_DATA_ENABLED}: true if + * sensitive data is enabled, default false
    • + *
    + * If {@link OpenTelemetryTraceEventListenerProvider} is being used: + *
      + *
    • {@link ObservabilityConfiguration#OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED}: + * true if OTEL tracer is enabled, otherwise false. Default true.
    • + *
    • {@link ObservabilityConfiguration#OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED}: + * true if sensitive data is enabled, default false
    • + *
    + */ +public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { + + /** + *

    + * System property used to enabled/disable tracers. The value of this system property should be a comma separated list + * of tracers to enable. + *

    + *

    + * This extension implements two tracers: + *

    + *
      + *
    • OTEL: which exports traces to Open Telemetry {@link OTelTracer}
    • + *
    • JFR: which exports traces to Java Flight recorder {@link JFRTracer}
    • + *
    + *

    + * By default all tracers will be enabled. + */ + public static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; + + /** + * System property used to enable/disable exporting sensitive data. Set the property to true to enable sensitive data. + * By default exporting sensitive data is disabled. + */ + public static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; + + /** + * This property is kept for backward compatibility. It is used to enable/disable the previous verison of the provider: + * "open-telemetry-trace-event-listener-provider". + */ + public static final String OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED = "oracle.jdbc.provider.opentelemetry.enabled"; + + /** + * This property is kept for backward compatibility. It allows to enable/disable sensitive data when using the previous + * version of the provider: "open-telemetry-trace-event-listener-provider". + */ + public static final String OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; + + /** + * Default values + */ + private static final String DEFAULT_ENABLED_TRACERS = "OTEL,JFR"; + private static final String DEFAULT_SENSITIVE_DATA_ENABLED = "false"; + private static final String DEFAULT_OPEN_TELEMETRY_ENABLED = "true"; + + /** + * Lock used to ensure that only one thread can access the configuration at a time. + */ + private static final ReentrantLock observabilityConfigurationLock = new ReentrantLock(); + + /** + * Indicates whether traces are enabled + */ + private boolean enabled = true; + + /** + * Indicates whether sensitive data is enabled + */ + private boolean sensitiveDataEnabled; + + /** + * List of enabled tracers + */ + private List enabledTracers = new ArrayList<>(); + + /** + * Maps registered tracer's name to its instance. + */ + Map registeredTracers = new HashMap<>(2, 1); + + + /** + * Types of configuration. For backward compatibility allows to use OTEL for + * Oracle JDBC Open Telemetry Provider configuration properties. + */ + public enum ObservabilityConfigurationType { + /** + * Use Oracle JDBC Open Telemetry Provider configuration properties + */ + OTEL, + /** + * USE Oracle JDBC Observability Provider configuration properties + */ + OBSERVABILITY + } + + /** + * Constructor + */ + public ObservabilityConfiguration() { + this(ObservabilityConfigurationType.OBSERVABILITY); + } + + /** + * Constructor used by {@link ObservabilityTraceEventListener} to create a configuration. + * + * @param configurationType indicates which system properties to use. When + * {@link ObservabilityConfigurationType#OTEL}, the previous + * verison of system properties are used. + */ + ObservabilityConfiguration(ObservabilityConfigurationType configurationType) { + String enabledTracers = DEFAULT_ENABLED_TRACERS; + String sensitiveDataEnabled = DEFAULT_SENSITIVE_DATA_ENABLED; + if (ObservabilityConfigurationType.OBSERVABILITY.equals(configurationType)) { + enabledTracers = System.getProperty(ENABLED_TRACERS, DEFAULT_ENABLED_TRACERS); + sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, DEFAULT_SENSITIVE_DATA_ENABLED); + } else { + String otelEnabled = System.getProperty(OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED, DEFAULT_OPEN_TELEMETRY_ENABLED); + if (otelEnabled != null) { + enabledTracers = "OTEL"; + this.enabled = Boolean.parseBoolean(otelEnabled); + } + String otelSensitiveDataEnabled = System.getProperty(OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, DEFAULT_SENSITIVE_DATA_ENABLED); + if(otelSensitiveDataEnabled != null) { + sensitiveDataEnabled = otelSensitiveDataEnabled; + } + } + + setEnabledTracers(enabledTracers); + setSensitiveDataEnabled(Boolean.parseBoolean(sensitiveDataEnabled)); + } + + /** + * Returns true if the provider is enabled, otherwise false. + * + * @return true if the provider is enabled, otherwise false. + */ + @Override + public boolean getEnabled() { + observabilityConfigurationLock.lock(); + try { + return enabled; + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Enables/disables the provider. + * + * @param enabled true to enable the provider, otherwise false. + */ + @Override + public void setEnabled(boolean enabled) { + observabilityConfigurationLock.lock(); + try { + this.enabled = enabled; + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Returns a comma separated list of enabled tracers. Not {@code null}. + */ + @Override + public String getEnabledTracers() { + observabilityConfigurationLock.lock(); + try { + return enabledTracers == null ? + "" : + enabledTracers.stream().collect(Collectors.joining(",")); + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Enables the tracers. + *

    + * This extension implements two tracers: + *

    + *
      + *
    • OTEL: which exports traces to Open Telemetry {@link OTelTracer}
    • + *
    • JFR: which exports traces to Java Flight recorder {@link JFRTracer}
    • + *
    + *

    + * Other tracer can be registered using the {@link ObservabilityConfiguration#registeredTracers} + * method. + *

    + * @param tracers comma separated list of enabled tracers. + */ + @Override + public void setEnabledTracers(String tracers){ + observabilityConfigurationLock.lock(); + try { + String[] items = tracers.replaceAll("\\s", tracers).split(","); + enabledTracers = Arrays.asList(items); + } finally { + observabilityConfigurationLock.unlock(); + } + + } + + /** + * Returns true if sensitive data is enabled, otherwise false. + * @return true if sensitive data is enabled, otherwise false. + */ + @Override + public boolean getSensitiveDataEnabled() { + observabilityConfigurationLock.lock(); + try { + return sensitiveDataEnabled; + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Enables/disables sensitive data. + * + * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. + */ + @Override + public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { + observabilityConfigurationLock.lock(); + try { + this.sensitiveDataEnabled = sensitiveDataEnabled; + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Returns a list of enabled tracers. + * @return then list of enabled tracers. + */ + public List getEnabledTracersAsList() { + observabilityConfigurationLock.lock(); + try { + return enabledTracers; + } finally { + observabilityConfigurationLock.unlock(); + } + } + + /** + * Returns the tracer registered with that name. + * @param tracerName the name of the tracer. + * @return returns the registered tracer that was registered using that name. + */ + public ObservabilityTracer getTracer(String tracerName) { + return registeredTracers.get(tracerName); + } + + /** + * Registeres a tracer. + * + * @param tracer the tracer to register + */ + public void registerTracer(ObservabilityTracer tracer) { + observabilityConfigurationLock.lock(); + try { + registeredTracers.put(tracer.getName(), tracer); + } finally { + observabilityConfigurationLock.unlock(); + } + } + + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfigurationMBean.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfigurationMBean.java new file mode 100644 index 00000000..f516dafa --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfigurationMBean.java @@ -0,0 +1,96 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ +package oracle.jdbc.provider.observability; + +import oracle.jdbc.provider.observability.tracers.jfr.JFRTracer; +import oracle.jdbc.provider.observability.tracers.otel.OTelTracer; + +/** + * MBean that allows to configure the Oracle JDBC Observability Provider. + */ +public interface ObservabilityConfigurationMBean { + + /** + * Returns true if the provider is enabled, otherwise false. + * + * @return true if the provider is enabled, otherwise false. + */ + boolean getEnabled(); + + /** + * Enables/disables the provider. + * + * @param enabled true to enable the provider, otherwise false. + */ + void setEnabled(boolean enabled); + + /** + * Returns a comma separated list of enabled tracers. + * + * @return a comma separated list of enabled tracers. + */ + String getEnabledTracers(); + + /** + * Enables the tracers. + *

    + * This extension implements two tracers: + *

    + *
      + *
    • OTEL: which exports traces to Open Telemetry {@link OTelTracer}
    • + *
    • JFR: which exports traces to Java Flight recorder {@link JFRTracer}
    • + *
    + * + * @param tracers comma separated list of enabled tracers. + */ + void setEnabledTracers(String tracers); + + /** + * Returns true if sensitive data is enabled, otherwise false. + * + * @return true if sensitive data is enabled, otherwise false. + */ + boolean getSensitiveDataEnabled(); + + /** + * Enables/disables sensitive data. + * + * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. + */ + void setSensitiveDataEnabled(boolean sensitiveDataEnabled); +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index 08484e6f..1032ef3c 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -1,14 +1,67 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability; +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + import oracle.jdbc.TraceEventListener; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.TracerType; +import oracle.jdbc.provider.observability.ObservabilityConfiguration.ObservabilityConfigurationType; +import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; +import oracle.jdbc.provider.observability.tracers.jfr.JFRTracer; +import oracle.jdbc.provider.observability.tracers.otel.OTelTracer; /** *

    - * TraceEventListener implementaiton that receives notifications whenever events + * TraceEventListener implementation that receives notifications whenever events * are generated in the driver and publishes these events different tracers - * depending on the configuraiton. + * depending on the configuration. *

    *

    * These events include: @@ -19,54 +72,145 @@ *

  • VIP down event
  • * *

    - * The available tracers are defined in the enumeration {@link TracerType}, and - * can be enabled using the method - * {@link ObservabilityConfiguration#setEnabledTracers(String)}. The method - * {@link ObservabilityConfiguration#setSensitiveDataEnabled(boolean)} allows - * to enabled/disable exporting sensitive data to the tracers. + * This extension implements two tracers: + *

    + *
      + *
    • OTEL: which exports traces to Open Telemetry
    • + *
    • JFR: which exports traces to Java Flight recorder
    • + *
    + *

    + * The {@link ObservabilityConfiguration} class allows to configure which tracers + * are enabled and whether sensitive data should be exported or not. *

    + *

    + * The {@link ObservabilityConfiguration} is a registered MBean the object name + * can be retrieved by calling {@link ObservabilityTraceEventListener#getMBeanObjectName()}. + * This MBean allows to configure the TraceEventListener by setting attributes. + * The following attributes are available: + *

    + *
      + *
    • EnabledTracers: comma separated list of tracers "OTEL,JFR" by + * default.
    • + *
    • SensitiveDataEnabled: enables/disables exporting sensiteve data + * (false by default)
    • + *
    */ public class ObservabilityTraceEventListener implements TraceEventListener { + /** + * MBean object name format + */ + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration,name=%s"; + private static final String MBEAN_OBJECT_NAME_OLD = "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener,name=%s"; + + /** + * MBean server + */ + protected static final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); /** - * Private constructor. + * Logger */ - private ObservabilityTraceEventListener() { } + private static final Logger logger = Logger.getLogger( + ObservabilityTraceEventListener.class.getPackageName()); /** - * Singleton instance. + * Configuration for this instance of Trace Event Listener */ - private static final ObservabilityTraceEventListener INSTANCE = - new ObservabilityTraceEventListener(); + private final ObservabilityConfiguration configuration; + + + private final String mBeanObjectName; /** - * Returns the singleton instance of {@link ObservabilityTraceEventListener}. - * @return the singleton instance of {@link ObservabilityTraceEventListener}. + * Create a trace event listener identified by the given name. + * @param name the name of the trace event listener. + * @param configurationType configuration type for backward compatibility. */ - public static final ObservabilityTraceEventListener getInstance() { - return INSTANCE; + private ObservabilityTraceEventListener(String name, ObservabilityConfigurationType configurationType) { + // Create the configuration for this instance and register MBean + mBeanObjectName = ObservabilityConfigurationType.OTEL.equals(configurationType) ? + String.format(MBEAN_OBJECT_NAME_OLD, name) : + String.format(MBEAN_OBJECT_NAME, name); + this.configuration = new ObservabilityConfiguration(configurationType); + try { + final ObjectName objectName = new ObjectName(mBeanObjectName); + if (!server.isRegistered(objectName)) { + server.registerMBean(configuration, objectName); + logger.log(Level.FINEST, "MBean and tracers registered"); + } + } catch (InstanceAlreadyExistsException | MBeanRegistrationException | + NotCompliantMBeanException | MalformedObjectNameException e) { + logger.log(Level.WARNING, "Could not register MBean", e); + } + // Register known tracers + configuration.registerTracer(new OTelTracer(configuration)); + configuration.registerTracer(new JFRTracer(configuration)); } + /** + * Static map linking the name of the listener to its instance. + */ + private static final Map INSTANCES + = new ConcurrentHashMap<>(); + @Override + @SuppressWarnings("unchecked") public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { - if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} - Object[] currentUserContext = getCurrentUserContext(userContext); - for (TracerType tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { - Object newUserContext = tracer.getTracer().traceRoundtrip(sequence, traceContext, currentUserContext[tracer.ordinal()]); - currentUserContext[tracer.ordinal()] = newUserContext; + if (!configuration.getEnabled()) { return null;} + + // Cast the userContext to the map this listener uses, or create a new one + // if it is being used for the first time. This is the return value of the + // method, and will be send back by the driver on the next event. + Map currentUserContext = userContext == null ? + new HashMap<>() : (Map)userContext; + + // loop through all the enabled tracers + for (String tracerName : configuration.getEnabledTracersAsList()) { + ObservabilityTracer tracer = configuration.getTracer(tracerName); + if (tracer != null) { + // call the tracer's round trip event with the tracer's context and store + // the new user context returned by the tracer in the user context map + Object newUserContext = tracer.traceRoundTrip(sequence, traceContext, currentUserContext.get(tracerName)); + currentUserContext.put(tracerName, newUserContext); + } else { + // the listener does not fail if the tracer is unknow, it is possible to + // enable a tracer and register it later + logger.log(Level.WARNING, "Could not find registered tracer with name: " + tracer); + } } + + // return the new user context return currentUserContext; } @Override + @SuppressWarnings("unchecked") public Object onExecutionEventReceived(JdbcExecutionEvent event, Object userContext, Object... params) { - if (!ObservabilityConfiguration.getInstance().getEnabled()) { return null;} - Object[] currentUserContext = getCurrentUserContext(userContext); - for (TracerType tracer : ObservabilityConfiguration.getInstance().getEnabledTracersSet()) { - Object newUserContext = tracer.getTracer().traceExecutionEvent(event, currentUserContext[tracer.ordinal()], params); - currentUserContext[tracer.ordinal()] = newUserContext; + if (!configuration.getEnabled()) { return null;} + + // Cast the userContext to the map this listener uses, or create a new one + // if it is being used for the first time. This is the return value of the + // method, and will be send back by the driver on the next event. + Map currentUserContext = userContext == null ? + new HashMap<>() : (Map)userContext; + + // loop through all the enabled tracers + for (String tracerName : configuration.getEnabledTracersAsList()) { + ObservabilityTracer tracer = configuration.getTracer(tracerName); + if (tracer != null) { + // call the tracer's execution event with the tracer's context and store + // the new user context returned by the tracer in the user context map + Object newUserContext = tracer.traceExecutionEvent(event, currentUserContext.get(tracerName), params); + currentUserContext.put(tracerName, newUserContext); + } else { + // the listener does not fail if the tracer is unknow, it is possible to + // enable a tracer and register it later + logger.log(Level.WARNING, "Could not find registered tracer with name: " + tracer); + } } + + // return the new user context return currentUserContext; } @@ -76,15 +220,53 @@ public boolean isDesiredEvent(JdbcExecutionEvent event) { return true; } - @SuppressWarnings("unchecked") - private Object[] getCurrentUserContext(Object userContext) { - Object[] currentUserContext; - if (userContext != null && (userContext instanceof Object[])) { - currentUserContext = (Object[]) userContext; - } else { - currentUserContext = new Object[TracerType.values().length]; + /** + * Returns the trace event listener identified by the given name. + * + * @param name the name of the listener. + * @return the trace event listener identified by the given name, or {@code + * null} if no trace event listener with that name was found. + */ + public static ObservabilityTraceEventListener getTraceEventListener(String name) { + return INSTANCES.get(name); + } + + /** + * Returns the configuration for a given listener. + * + * @param name the name of the listener. + * @return then configuration instance associated to that listener, or {@code + * null} if not trace event listener with that name was found. + */ + public static ObservabilityConfiguration getObservabilityConfiguration(String name) { + ObservabilityTraceEventListener listener = INSTANCES.get(name); + if (listener != null) { + return listener.configuration; } - return currentUserContext; + return null; + } + + /** + * Returns the MBean object name assiciated with the configuration of the + * listener. + * + * @return the MBean object name. + */ + public String getMBeanObjectName() { + return mBeanObjectName; + } + + /** + * Gets or creates an instance of {@link ObservabilityTraceEventListener} + * associated to the name. + * @param name the name of the listener instance. + * @param configurationType configuration type for backward compatibility. + * + * @return an instance of {@link ObservabilityTraceEventListener}. + */ + static ObservabilityTraceEventListener getOrCreateInstance(String name, + ObservabilityConfigurationType configurationType) { + return INSTANCES.computeIfAbsent(name, n -> new ObservabilityTraceEventListener(n, configurationType)); } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index 482cae01..af4f6f53 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -1,22 +1,52 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability; import java.lang.management.ManagementFactory; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.management.Attribute; -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; import oracle.jdbc.TraceEventListener; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.ObservabilityConfiguration.ObservabilityConfigurationType; import oracle.jdbc.spi.TraceEventListenerProvider; /** @@ -25,46 +55,49 @@ */ public class ObservabilityTraceEventListenerProvider implements TraceEventListenerProvider { + /** + * Provider name + */ private static final String PROVIDER_NAME = "observability-trace-event-listener-provider"; - private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"; - private static ObjectName objectName; /** - * Logger + * Name Parameter name, identifies the listener */ - private Logger logger = Logger.getLogger(ObservabilityTraceEventListenerProvider.class.getName()); + private static final String NAME_PARAMETER_NAME = "NAME"; + /** - * MBean server + * Name Parameter, identifies the listener */ - protected static final MBeanServer server = ManagementFactory.getPlatformMBeanServer();; + protected static final Parameter nameParameter = new Parameter() { + @Override + public boolean isSensitive() { + return false; + } - static { - try { - objectName = new ObjectName(MBEAN_OBJECT_NAME); - } catch (MalformedObjectNameException e) { - objectName = null; + @Override + public String name() { + return NAME_PARAMETER_NAME; } - } + + }; + /** * Constructs a new instance of ObservabilityTraceEventListenerProvider. This * constructor will be called by the driver's service provider to create a new * instance. */ - public ObservabilityTraceEventListenerProvider() { } + public ObservabilityTraceEventListenerProvider() { + + + } @Override public TraceEventListener getTraceEventListener(Map map) { - try { - if (!server.isRegistered(objectName)) { - server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); - } - } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { - logger.log(Level.WARNING, "Could not register MBean", e); - } - return ObservabilityTraceEventListener.getInstance(); + String name = map.get(nameParameter).toString(); + return ObservabilityTraceEventListener.getOrCreateInstance(name, ObservabilityConfigurationType.OBSERVABILITY); } @Override @@ -74,7 +107,7 @@ public String getName() { @Override public Collection getParameters() { - return Collections.emptyList(); + return Collections.singletonList(nameParameter); } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java new file mode 100644 index 00000000..3e3d3369 --- /dev/null +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java @@ -0,0 +1,78 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ +package oracle.jdbc.provider.observability; + +import java.util.Map; + +import oracle.jdbc.TraceEventListener; +import oracle.jdbc.provider.observability.ObservabilityConfiguration.ObservabilityConfigurationType; + +/** + *

    + * This class implements the TraceEventListenerProvider interface exposed by the + * Oracle JDBC driver. It provides TraceEventListeners of type {@link + * oracle.jdbc.provider.observability.ObservabilityTraceEventListener}. + *

    + */ +public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceEventListenerProvider { + + /** + * Name of the provider + */ + private static final String PROVIDER_NAME = "open-telemetry-trace-event-listener-provider"; + + /** + * Constructs a new instance of OpenTelemetryTraceEventListenerProvider. This + * constructor will be called by the driver's service provider to create a new + * instance. + */ + public OpenTelemetryTraceEventListenerProvider() { } + + @Override + public String getName() { + return PROVIDER_NAME; + } + + @Override + public TraceEventListener getTraceEventListener(Map map) { + String name = map.get(nameParameter).toString(); + return ObservabilityTraceEventListener.getOrCreateInstance(name, + ObservabilityConfigurationType.OTEL); + } + +} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java deleted file mode 100644 index 4e4e7b27..00000000 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfiguration.java +++ /dev/null @@ -1,166 +0,0 @@ -package oracle.jdbc.provider.observability.configuration; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -import oracle.jdbc.provider.observability.tracers.TracerType; - -/** - * Implementation of {@link ObservabilityConfigurationMBean} that allows to - * configure the Oracle JDBC Observability Provider. - */ -public class ObservabilityConfiguration implements ObservabilityConfigurationMBean { - - /** - * System property used to enabled/disable tracers. The value of this system property should be a comma separated list - * of {@link TracerType} to enable. By default all tracers will be enabled. - */ - private static final String ENABLED_TRACERS = "oracle.jdbc.provider.observability.enabledTracers"; - - /** - * System property used to enable/disable exporting sensitive data. Set the property to true to enable sensitive data. - * By default exporting sensitive data is disabled. - */ - private static final String SENSITIVE_DATA_ENABLED = "oracle.jdbc.provider.observability.sensitiveDataEnabled"; - - private static final ReentrantLock observabilityConfiguraitonLock = new ReentrantLock(); - - private static final ObservabilityConfiguration INSTANCE = new ObservabilityConfiguration(); - - private boolean enabled = true; - private boolean sensitiveDataEnabled; - private String tracers; - - private List enabledTracers = new ArrayList<>(); - - private ObservabilityConfiguration() { - String enabledTracers = System.getProperty(ENABLED_TRACERS, "OTEL,JFR"); - String sensitiveDataEnabled = System.getProperty(SENSITIVE_DATA_ENABLED, "false"); - setEnabledTracers(enabledTracers); - setSensitiveDataEnabled(Boolean.valueOf(sensitiveDataEnabled)); - } - - /** - * Returns true if the provider is enabled, otherwise false. - * - * @return true if the provider is enabled, otherwise false. - */ - @Override - public boolean getEnabled() { - observabilityConfiguraitonLock.lock(); - try { - return enabled; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Enables/disables the provider. - * - * @param enabled true to enable the provider, otherwise false. - */ - @Override - public void setEnabled(boolean enabled) { - observabilityConfiguraitonLock.lock(); - try { - this.enabled = enabled; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Returns a comma separated list of enabled tracers. - */ - @Override - public String getEnabledTracers() { - observabilityConfiguraitonLock.lock(); - try { - return tracers; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Enables the tracers. Available tracers are defined in enum {@link TracerType}. - * - * @param tracers comma separated list of enabled tracers. - */ - @Override - public void setEnabledTracers(String tracers) { - observabilityConfiguraitonLock.lock(); - try { - enabledTracers.clear(); - String[] items = tracers.split(","); - for (String item : items) { - if (item != null) { - enabledTracers.add(TracerType.valueOf(item.toUpperCase())); - } - } - this.tracers = enabledTracers.stream().map((item) -> item.toString()).collect(Collectors.joining(",")); - } finally { - observabilityConfiguraitonLock.unlock(); - } - - } - - /** - * Returns true if sensitive data is enabled, otherwise false. - */ - @Override - public boolean getSensitiveDataEnabled() { - observabilityConfiguraitonLock.lock(); - try { - return sensitiveDataEnabled; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Enables/disables sensitive data. - * - * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. - */ - @Override - public void setSensitiveDataEnabled(boolean sensitiveDataEnabled) { - observabilityConfiguraitonLock.lock(); - try { - this.sensitiveDataEnabled = sensitiveDataEnabled; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Returns the singleton instance of {@link ObservabilityConfiguration}. - * @return the singleton instance of {@link ObservabilityConfiguration}. - */ - public static ObservabilityConfiguration getInstance() { - observabilityConfiguraitonLock.lock(); - try { - return INSTANCE; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - /** - * Returns a list of enabled {@link TracerType}. - * @return then list of nabled {@link TracerType}. - */ - public List getEnabledTracersSet() { - observabilityConfiguraitonLock.lock(); - try { - return enabledTracers; - } finally { - observabilityConfiguraitonLock.unlock(); - } - } - - -} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java deleted file mode 100644 index 41457aaf..00000000 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/configuration/ObservabilityConfigurationMBean.java +++ /dev/null @@ -1,51 +0,0 @@ -package oracle.jdbc.provider.observability.configuration; - -import oracle.jdbc.provider.observability.tracers.TracerType; - -/** - * MBean that allows to configure the Oracle JDBC Observability Provider. - */ -public interface ObservabilityConfigurationMBean { - - /** - * Returns true if the provider is enabled, otherwise false. - * - * @return true if the provider is enabled, otherwise false. - */ - public boolean getEnabled(); - - /** - * Enables/disables the provider. - * - * @param enabled true to enable the provider, otherwise false. - */ - public void setEnabled(boolean enabled); - - /** - * Returns a comma separated list of enabled tracers. - * - * @return a comma separated list of enabled tracers. - */ - public String getEnabledTracers(); - - /** - * Enables the tracers. Available tracers are defined in enum {@link TracerType}. - * - * @param tracers comma separated list of enabled tracers. - */ - public void setEnabledTracers(String tracers); - - /** - * Returns true if sensitive data is enabled, otherwise false. - * - * @return true if sensitive data is enabled, otherwise false. - */ - public boolean getSensitiveDataEnabled(); - - /** - * Enables/disables sensitive data. - * - * @param sensitiveDataEnabled true to enable sensitive data, otherwise false. - */ - public void setSensitiveDataEnabled(boolean sensitiveDataEnabled); -} diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java index 5e93c3fa..d0c4c208 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/ObservabilityTracer.java @@ -1,3 +1,40 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability.tracers; import java.util.EnumMap; @@ -16,7 +53,7 @@ public interface ObservabilityTracer { /** * Map containing the number of parameters expected for each execution event */ - static final Map EXECUTION_EVENTS_PARAMETERS + Map EXECUTION_EVENTS_PARAMETERS = new EnumMap(JdbcExecutionEvent.class) { { put(JdbcExecutionEvent.AC_REPLAY_STARTED, 3); @@ -25,6 +62,12 @@ public interface ObservabilityTracer { } }; + /** + * Returns the unique name of the tracer. + * @return the unique name of the tracer. + */ + String getName(); + /** * Called by {@link ObservabilityTraceEventListener} when a round trip event @@ -39,7 +82,7 @@ public interface ObservabilityTracer { * @return a user context object that is passed to the next call on this * Connection. May be null. */ - Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext); + Object traceRoundTrip(Sequence sequence, TraceContext traceContext, Object userContext); /** * Called by {@link ObservabilityTraceEventListener} when an execution event diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java deleted file mode 100644 index fec5fea9..00000000 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/TracerType.java +++ /dev/null @@ -1,34 +0,0 @@ -package oracle.jdbc.provider.observability.tracers; - -import oracle.jdbc.provider.observability.tracers.jfr.JFRTracer; -import oracle.jdbc.provider.observability.tracers.otel.OTelTracer; - -/** - * This interface defines the constants that are used to identify the - * {@link ObservabilityTracer}. - */ -public enum TracerType { - /** - * Open Telemetry tracer. - */ - OTEL(new OTelTracer()), - - /** - * Java Flight Recorder tracer. - */ - JFR(new JFRTracer()); - - private ObservabilityTracer tracer; - - TracerType(ObservabilityTracer tracer) { - this.tracer = tracer; - } - - /** - * Returns the {@link ObservabilityTracer} for this {@link TracerType}. - * @return the {@link ObservabilityTracer}. - */ - public ObservabilityTracer getTracer() { - return tracer; - } -} \ No newline at end of file diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java index 24158877..f42c811a 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFREventFactory.java @@ -1,3 +1,40 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability.tracers.jfr; import jdk.jfr.Event; @@ -5,11 +42,13 @@ import jdk.jfr.Name; import java.sql.SQLException; +import java.util.logging.Logger; import jdk.jfr.Category; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.TraceContext; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; /** @@ -17,6 +56,12 @@ */ public class JFREventFactory { + /** + * Logger + */ + private static final Logger logger = Logger.getLogger( + ObservabilityTraceEventListener.class.getPackageName()); + /** * This class only has a static method, no public constructor needed. */ @@ -27,158 +72,160 @@ private JFREventFactory() { } * The type of round trip event depends on the database function. * * @param traceContext the trace context received by a TraceEventListener. + * @param configuration the configuration * @return the {@link RoundTripEvent} for the database function. */ - public static RoundTripEvent createJFREvent(TraceContext traceContext) { + public static RoundTripEvent createJFRRoundTripEvent(TraceContext traceContext, ObservabilityConfiguration configuration) { switch (traceContext.databaseFunction()) { case ADVANCED_QUEUING_12C_EMON_DEQUEUE: - return new AdvancedQueuing12cEminDequeueEvent(traceContext); + return new AdvancedQueuing12cEminDequeueEvent(traceContext, configuration); case ADVANCED_QUEUING_ARRAY_ENQUEUE_DEQUEUE: - return new AdvancedQueuingArrayEnqueueDequeue(traceContext); + return new AdvancedQueuingArrayEnqueueDequeue(traceContext, configuration); case ADVANCED_QUEUING_DEQUEUE_V8: - return new AdvancedQueuingDequeueV8(traceContext); + return new AdvancedQueuingDequeueV8(traceContext, configuration); case ADVANCED_QUEUING_ENQUEUE: - return new AdvancedQueuingEnqueue(traceContext); + return new AdvancedQueuingEnqueue(traceContext, configuration); case ADVANCED_QUEUING_GET_PROPAGATION_STATUS: - return new AdvancedQueuingGetPropagationStatus(traceContext); + return new AdvancedQueuingGetPropagationStatus(traceContext, configuration); case ADVANCED_QUEUING_LISTEN: - return new AdvancedQueuingListen(traceContext); + return new AdvancedQueuingListen(traceContext, configuration); case ADVANCED_QUEUING_SESSION_GET_RPC_1: - return new AdvancedQueuingSessionGetRPC1(traceContext); + return new AdvancedQueuingSessionGetRPC1(traceContext, configuration); case ADVANCED_QUEUING_SESSION_GET_RPC_2: - return new AdvancedQueuingSessionGetRPC2(traceContext); + return new AdvancedQueuingSessionGetRPC2(traceContext, configuration); case ADVANCED_QUEUING_SHARED_DEQUEUE: - return new AdvancedQueuingSharedDequeue(traceContext); + return new AdvancedQueuingSharedDequeue(traceContext, configuration); case ADVANCED_QUEUING_SHARED_ENQUEUE: - return new AdvancedQueuingSharedEnqueue(traceContext); + return new AdvancedQueuingSharedEnqueue(traceContext, configuration); case APP_REPLAY: - return new AppReplay(traceContext); + return new AppReplay(traceContext, configuration); case AUTH_CALL: - return new AuthCall(traceContext); + return new AuthCall(traceContext, configuration); case AUTO_COMMIT_OFF: - return new AutoCommitOff(traceContext); + return new AutoCommitOff(traceContext, configuration); case AUTO_COMMIT_ON: - return new AutoCommitOn(traceContext); + return new AutoCommitOn(traceContext, configuration); case CANCEL_ALL: - return new CancelAll(traceContext); + return new CancelAll(traceContext, configuration); case CANCEL_OPERATION: - return new CancelOperation(traceContext); + return new CancelOperation(traceContext, configuration); case CHUNCK_INFO: - return new ChunkInfo(traceContext); + return new ChunkInfo(traceContext, configuration); case CLIENT_FEATURES: - return new ClientFeatures(traceContext); + return new ClientFeatures(traceContext, configuration); case CLIENT_QUERY_CACHE_IDS: - return new ClientQueryCacheIds(traceContext); + return new ClientQueryCacheIds(traceContext, configuration); case CLIENT_QUERY_CACHE_STATS_UPDATE: - return new ClientQueryCacheStatsUpdate(traceContext); + return new ClientQueryCacheStatsUpdate(traceContext, configuration); case CLOSE_ALL_CURSOR: - return new CloseAllCursor(traceContext); + return new CloseAllCursor(traceContext, configuration); case CLOSE_CURSOR: - return new CloseCursor(traceContext); + return new CloseCursor(traceContext, configuration); case COMMIT: - return new Commit(traceContext); + return new Commit(traceContext, configuration); case DB12C_NOTIFICATION_RCV: - return new DB12cNotificationRCV(traceContext); + return new DB12cNotificationRCV(traceContext, configuration); case DBNS_SAGAS: - return new DBNSSagas(traceContext); + return new DBNSSagas(traceContext, configuration); case DESCRIBE_ANY_V8: - return new DescribeAnyV8(traceContext); + return new DescribeAnyV8(traceContext, configuration); case DESCRIBE_ARRAY: - return new DescribeArray(traceContext); + return new DescribeArray(traceContext, configuration); case DESCRIBE_QUERY_CALL: - return new DescribeQueryCall(traceContext); + return new DescribeQueryCall(traceContext, configuration); case DIRECT_PATH_LOAD_STREAM: - return new DirectPathLoadStream(traceContext); + return new DirectPathLoadStream(traceContext, configuration); case DIRECT_PATH_MISC_OP: - return new DirectPathMISCOp(traceContext); + return new DirectPathMISCOp(traceContext, configuration); case DIRECT_PATH_PREPARE: - return new DirectPathPrepare(traceContext); + return new DirectPathPrepare(traceContext, configuration); case DISTRIBUTED_TRANS_MGR_RPC: - return new DistributedTransMGRRPC(traceContext); + return new DistributedTransMGRRPC(traceContext, configuration); case EXECUTE_QUERY: - return new ExecuteQuery(traceContext); + return new ExecuteQuery(traceContext, configuration); case EXTENSIBLE_SECURITY_SESSION_CREATE: - return new ExtensibleSecuritySessionCreate(traceContext); + return new ExtensibleSecuritySessionCreate(traceContext, configuration); case EXTENSIBLE_SECURITY_SESSION_PIGGYBACK: - return new ExtensibleSecuritySessionPiggyback(traceContext); + return new ExtensibleSecuritySessionPiggyback(traceContext, configuration); case EXTENSIBLE_SECURITY_SESSION_ROUNDTRIP: - return new ExtensibleSecuritySessionRoundtrip(traceContext); + return new ExtensibleSecuritySessionRoundtrip(traceContext, configuration); case FAST_UPI_CALLS: - return new FastUPICalls(traceContext); + return new FastUPICalls(traceContext, configuration); case FETCH_ROW: - return new FetchRow(traceContext); + return new FetchRow(traceContext, configuration); case GET_VERSION: - return new GetVersion(traceContext); + return new GetVersion(traceContext, configuration); case KERNEL_PROGRAMMATIC_NOTIFICATION: - return new KernelProgrammaticNotification(traceContext); + return new KernelProgrammaticNotification(traceContext, configuration); case KEY_VALUE: - return new KeyValue(traceContext); + return new KeyValue(traceContext, configuration); case LOB_FILE_CALL: - return new LOBFileCall(traceContext); + return new LOBFileCall(traceContext, configuration); case LOGOFF: - return new LogOff(traceContext); + return new LogOff(traceContext, configuration); case LOGON_CHALLENGE_RESPONSE_1: - return new LogonChallengeResponse1(traceContext); + return new LogonChallengeResponse1(traceContext, configuration); case LOGON_CHALLENGE_RESPONSE_2: - return new LogonChallengeResponse2(traceContext); + return new LogonChallengeResponse2(traceContext, configuration); case OEXFEN: - return new OEXFEN(traceContext); + return new OEXFEN(traceContext, configuration); case OPEN_CURSOR: - return new OpenCursor(traceContext); + return new OpenCursor(traceContext, configuration); case OSQL7: - return new OSQL7(traceContext); + return new OSQL7(traceContext, configuration); case OSTART: - return new OStart(traceContext); + return new OStart(traceContext, configuration); case OSTOP: - return new OStop(traceContext); + return new OStop(traceContext, configuration); case PARAMETER_PUT_SPFILE: - return new ParameterPutSPFile(traceContext); + return new ParameterPutSPFile(traceContext, configuration); case PING: - return new Ping(traceContext); + return new Ping(traceContext, configuration); case PIPELINE_END: - return new PipelineEnd(traceContext); + return new PipelineEnd(traceContext, configuration); case PIPELINE_PIGGYBACK_BEGIN: - return new PipelinePiggybackBegin(traceContext); + return new PipelinePiggybackBegin(traceContext, configuration); case PIPELINE_PIGGYBACK_OP: - return new PipelinePiggybackOp(traceContext); + return new PipelinePiggybackOp(traceContext, configuration); case ROLLBACK: - return new Rollback(traceContext); + return new Rollback(traceContext, configuration); case SESSION_KEY: - return new SessionKey(traceContext); + return new SessionKey(traceContext, configuration); case SESSION_STATE_OPS: - return new SessionStateOps(traceContext); + return new SessionStateOps(traceContext, configuration); case SESSION_STATE_TEMPLATE: - return new SessionStateTemplate(traceContext); + return new SessionStateTemplate(traceContext, configuration); case SESSION_SWITCH_V8: - return new SessionSwitchV8(traceContext); + return new SessionSwitchV8(traceContext, configuration); case TRACING_MESSAGE: - return new TracingMessage(traceContext); + return new TracingMessage(traceContext, configuration); case TRANSACTION_COMMIT: - return new TransactionCommit(traceContext); + return new TransactionCommit(traceContext, configuration); case TRANSACTION_START: - return new TransactionStart(traceContext); + return new TransactionStart(traceContext, configuration); case TTC_DTY_ROUNDTRIP: - return new TTCDTYRoundtrip(traceContext); + return new TTCDTYRoundtrip(traceContext, configuration); case TTC_PRO_ROUNDTRIP: - return new TTCPRORoundtrip(traceContext); + return new TTCPRORoundtrip(traceContext, configuration); case XS_ATTACH_SESSION: - return new XSAttachSession(traceContext); + return new XSAttachSession(traceContext, configuration); case XS_CREATE_SESSION: - return new XSCreateSession(traceContext); + return new XSCreateSession(traceContext, configuration); case XS_DESTROY_SESSION: - return new XSDestroySession(traceContext); + return new XSDestroySession(traceContext, configuration); case XS_DETACH_SESSION: - return new XSDetachSession(traceContext); + return new XSDetachSession(traceContext, configuration); case XS_NAMESPACE_OP: - return new XSNamespaceOp(traceContext); + return new XSNamespaceOp(traceContext, configuration); case XS_NAMESPACE_OPS: - return new XSNamespaceOps(traceContext); + return new XSNamespaceOps(traceContext, configuration); case XS_SET_SESSION_PARAMETER: - return new XSSetSessionParameter(traceContext); + return new XSSetSessionParameter(traceContext, configuration); case XS_STATE_SYNC_OP: - return new XSStateSyncOp(traceContext); + return new XSStateSyncOp(traceContext, configuration); default: - return new RoundTripEvent(traceContext); + logger.warning("Unknown round trip received: " + traceContext.databaseFunction()); + return new RoundTripEvent(traceContext, configuration); } } @@ -199,6 +246,7 @@ public static Event createExecutionEvent(JdbcExecutionEvent event, Object... par case VIP_RETRY: return new VIPRetry(event, params); default: + logger.warning("Unknow event received: " + event); return new ExecutionEvent(event, params); } } @@ -209,8 +257,8 @@ public static Event createExecutionEvent(JdbcExecutionEvent event, Object... par @Label("AQ 12c emon dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuing12cEminDequeueEvent extends RoundTripEvent{ - public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -218,8 +266,8 @@ public AdvancedQueuing12cEminDequeueEvent(TraceContext traceContext) { @Label("AQ Array Enqueue/Dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingArrayEnqueueDequeue extends RoundTripEvent{ - public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -227,8 +275,8 @@ public AdvancedQueuingArrayEnqueueDequeue(TraceContext traceContext) { @Label("AQ Dequeue before 8.1") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingDequeueV8 extends RoundTripEvent{ - public AdvancedQueuingDequeueV8(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingDequeueV8(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -236,8 +284,8 @@ public AdvancedQueuingDequeueV8(TraceContext traceContext) { @Label("AQ EnQueue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingEnqueue extends RoundTripEvent{ - public AdvancedQueuingEnqueue(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingEnqueue(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -245,8 +293,8 @@ public AdvancedQueuingEnqueue(TraceContext traceContext) { @Label("AQ get propagation status entries") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingGetPropagationStatus extends RoundTripEvent{ - public AdvancedQueuingGetPropagationStatus(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingGetPropagationStatus(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -254,8 +302,8 @@ public AdvancedQueuingGetPropagationStatus(TraceContext traceContext) { @Label("AQ Listen") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingListen extends RoundTripEvent{ - public AdvancedQueuingListen(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingListen(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -263,8 +311,8 @@ public AdvancedQueuingListen(TraceContext traceContext) { @Label("Session get RPC in server pool scenario") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSessionGetRPC1 extends RoundTripEvent{ - public AdvancedQueuingSessionGetRPC1(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingSessionGetRPC1(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -272,8 +320,8 @@ public AdvancedQueuingSessionGetRPC1(TraceContext traceContext) { @Label("Session get RPC in server pool scenario") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSessionGetRPC2 extends RoundTripEvent{ - public AdvancedQueuingSessionGetRPC2(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingSessionGetRPC2(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -281,8 +329,8 @@ public AdvancedQueuingSessionGetRPC2(TraceContext traceContext) { @Label("AQ Sharded dequeue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSharedDequeue extends RoundTripEvent{ - public AdvancedQueuingSharedDequeue(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingSharedDequeue(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -290,8 +338,8 @@ public AdvancedQueuingSharedDequeue(TraceContext traceContext) { @Label("AQ Sharded enqueue") @Category({"Oracle JDBC", "Round trips"}) static class AdvancedQueuingSharedEnqueue extends RoundTripEvent{ - public AdvancedQueuingSharedEnqueue(TraceContext traceContext) { - super(traceContext); + public AdvancedQueuingSharedEnqueue(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -299,8 +347,8 @@ public AdvancedQueuingSharedEnqueue(TraceContext traceContext) { @Label("Application continuity REPLAY") @Category({"Oracle JDBC", "Round trips"}) static class AppReplay extends RoundTripEvent{ - public AppReplay(TraceContext traceContext) { - super(traceContext); + public AppReplay(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -308,8 +356,8 @@ public AppReplay(TraceContext traceContext) { @Label("Generic authentication call") @Category({"Oracle JDBC", "Round trips"}) static class AuthCall extends RoundTripEvent{ - public AuthCall(TraceContext traceContext) { - super(traceContext); + public AuthCall(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -317,8 +365,8 @@ public AuthCall(TraceContext traceContext) { @Label("Auto commit off") @Category({"Oracle JDBC", "Round trips"}) static class AutoCommitOff extends RoundTripEvent{ - public AutoCommitOff(TraceContext traceContext) { - super(traceContext); + public AutoCommitOff(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -326,8 +374,8 @@ public AutoCommitOff(TraceContext traceContext) { @Label("Auto commit on") @Category({"Oracle JDBC", "Round trips"}) static class AutoCommitOn extends RoundTripEvent{ - public AutoCommitOn(TraceContext traceContext) { - super(traceContext); + public AutoCommitOn(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -335,8 +383,8 @@ public AutoCommitOn(TraceContext traceContext) { @Label("Cancel All") @Category({"Oracle JDBC", "Round trips"}) static class CancelAll extends RoundTripEvent{ - public CancelAll(TraceContext traceContext) { - super(traceContext); + public CancelAll(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -344,8 +392,8 @@ public CancelAll(TraceContext traceContext) { @Label("Cancel the current operation") @Category({"Oracle JDBC", "Round trips"}) static class CancelOperation extends RoundTripEvent{ - public CancelOperation(TraceContext traceContext) { - super(traceContext); + public CancelOperation(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -353,8 +401,8 @@ public CancelOperation(TraceContext traceContext) { @Label("Chunk info RPC") @Category({"Oracle JDBC", "Round trips"}) static class ChunkInfo extends RoundTripEvent{ - public ChunkInfo(TraceContext traceContext) { - super(traceContext); + public ChunkInfo(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -362,8 +410,8 @@ public ChunkInfo(TraceContext traceContext) { @Label("Client features") @Category({"Oracle JDBC", "Round trips"}) static class ClientFeatures extends RoundTripEvent{ - public ClientFeatures(TraceContext traceContext) { - super(traceContext); + public ClientFeatures(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -371,8 +419,8 @@ public ClientFeatures(TraceContext traceContext) { @Label("Client query cache IDs") @Category({"Oracle JDBC", "Round trips"}) static class ClientQueryCacheIds extends RoundTripEvent{ - public ClientQueryCacheIds(TraceContext traceContext) { - super(traceContext); + public ClientQueryCacheIds(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -380,8 +428,8 @@ public ClientQueryCacheIds(TraceContext traceContext) { @Label("Client query cache statistics update") @Category({"Oracle JDBC", "Round trips"}) static class ClientQueryCacheStatsUpdate extends RoundTripEvent{ - public ClientQueryCacheStatsUpdate(TraceContext traceContext) { - super(traceContext); + public ClientQueryCacheStatsUpdate(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -389,8 +437,8 @@ public ClientQueryCacheStatsUpdate(TraceContext traceContext) { @Label("Cursor close all") @Category({"Oracle JDBC", "Round trips"}) static class CloseAllCursor extends RoundTripEvent{ - public CloseAllCursor(TraceContext traceContext) { - super(traceContext); + public CloseAllCursor(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -398,8 +446,8 @@ public CloseAllCursor(TraceContext traceContext) { @Label("Close a cursor") @Category({"Oracle JDBC", "Round trips"}) static class CloseCursor extends RoundTripEvent{ - public CloseCursor(TraceContext traceContext) { - super(traceContext); + public CloseCursor(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -407,8 +455,8 @@ public CloseCursor(TraceContext traceContext) { @Label("Commit") @Category({"Oracle JDBC", "Round trips"}) static class Commit extends RoundTripEvent{ - public Commit(TraceContext traceContext) { - super(traceContext); + public Commit(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -416,8 +464,8 @@ public Commit(TraceContext traceContext) { @Label("12c notification receive") @Category({"Oracle JDBC", "Round trips"}) static class DB12cNotificationRCV extends RoundTripEvent{ - public DB12cNotificationRCV(TraceContext traceContext) { - super(traceContext); + public DB12cNotificationRCV(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -425,8 +473,8 @@ public DB12cNotificationRCV(TraceContext traceContext) { @Label("DBMS Sagas") @Category({"Oracle JDBC", "Round trips"}) static class DBNSSagas extends RoundTripEvent{ - public DBNSSagas(TraceContext traceContext) { - super(traceContext); + public DBNSSagas(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -434,8 +482,8 @@ public DBNSSagas(TraceContext traceContext) { @Label("V8 Describe Any") @Category({"Oracle JDBC", "Round trips"}) static class DescribeAnyV8 extends RoundTripEvent{ - public DescribeAnyV8(TraceContext traceContext) { - super(traceContext); + public DescribeAnyV8(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -443,8 +491,8 @@ public DescribeAnyV8(TraceContext traceContext) { @Label("Array describe") @Category({"Oracle JDBC", "Round trips"}) static class DescribeArray extends RoundTripEvent{ - public DescribeArray(TraceContext traceContext) { - super(traceContext); + public DescribeArray(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -452,8 +500,8 @@ public DescribeArray(TraceContext traceContext) { @Label("New describe query call") @Category({"Oracle JDBC", "Round trips"}) static class DescribeQueryCall extends RoundTripEvent{ - public DescribeQueryCall(TraceContext traceContext) { - super(traceContext); + public DescribeQueryCall(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -461,8 +509,8 @@ public DescribeQueryCall(TraceContext traceContext) { @Label("Direct Path Load Stream") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathLoadStream extends RoundTripEvent{ - public DirectPathLoadStream(TraceContext traceContext) { - super(traceContext); + public DirectPathLoadStream(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -470,8 +518,8 @@ public DirectPathLoadStream(TraceContext traceContext) { @Label("Direct Path Misc Operations") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathMISCOp extends RoundTripEvent{ - public DirectPathMISCOp(TraceContext traceContext) { - super(traceContext); + public DirectPathMISCOp(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -479,8 +527,8 @@ public DirectPathMISCOp(TraceContext traceContext) { @Label("Direct Path Prepare") @Category({"Oracle JDBC", "Round trips"}) static class DirectPathPrepare extends RoundTripEvent{ - public DirectPathPrepare(TraceContext traceContext) { - super(traceContext); + public DirectPathPrepare(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -488,8 +536,8 @@ public DirectPathPrepare(TraceContext traceContext) { @Label("Distributed transaction manager RPC") @Category({"Oracle JDBC", "Round trips"}) static class DistributedTransMGRRPC extends RoundTripEvent{ - public DistributedTransMGRRPC(TraceContext traceContext) { - super(traceContext); + public DistributedTransMGRRPC(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -497,8 +545,8 @@ public DistributedTransMGRRPC(TraceContext traceContext) { @Label("Execute query") @Category({"Oracle JDBC", "Round trips"}) static class ExecuteQuery extends RoundTripEvent{ - public ExecuteQuery(TraceContext traceContext) { - super(traceContext); + public ExecuteQuery(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -506,8 +554,8 @@ public ExecuteQuery(TraceContext traceContext) { @Label("eXtensible Security Sessions Create Session") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionCreate extends RoundTripEvent{ - public ExtensibleSecuritySessionCreate(TraceContext traceContext) { - super(traceContext); + public ExtensibleSecuritySessionCreate(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -515,8 +563,8 @@ public ExtensibleSecuritySessionCreate(TraceContext traceContext) { @Label("eXtensible Security Sessions Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionPiggyback extends RoundTripEvent{ - public ExtensibleSecuritySessionPiggyback(TraceContext traceContext) { - super(traceContext); + public ExtensibleSecuritySessionPiggyback(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -524,8 +572,8 @@ public ExtensibleSecuritySessionPiggyback(TraceContext traceContext) { @Label("eXtensible Security Session Roundtrip") @Category({"Oracle JDBC", "Round trips"}) static class ExtensibleSecuritySessionRoundtrip extends RoundTripEvent{ - public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext) { - super(traceContext); + public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -533,8 +581,8 @@ public ExtensibleSecuritySessionRoundtrip(TraceContext traceContext) { @Label("Fast UPI calls to opial7") @Category({"Oracle JDBC", "Round trips"}) static class FastUPICalls extends RoundTripEvent{ - public FastUPICalls(TraceContext traceContext) { - super(traceContext); + public FastUPICalls(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -542,8 +590,8 @@ public FastUPICalls(TraceContext traceContext) { @Label("Fetch a row") @Category({"Oracle JDBC", "Round trips"}) static class FetchRow extends RoundTripEvent{ - public FetchRow(TraceContext traceContext) { - super(traceContext); + public FetchRow(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -551,8 +599,8 @@ public FetchRow(TraceContext traceContext) { @Label("Get Oracle version-date string in new format") @Category({"Oracle JDBC", "Round trips"}) static class GetVersion extends RoundTripEvent{ - public GetVersion(TraceContext traceContext) { - super(traceContext); + public GetVersion(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -560,17 +608,17 @@ public GetVersion(TraceContext traceContext) { @Label("Kernel Programmatic Notification") @Category({"Oracle JDBC", "Round trips"}) static class KernelProgrammaticNotification extends RoundTripEvent{ - public KernelProgrammaticNotification(TraceContext traceContext) { - super(traceContext); + public KernelProgrammaticNotification(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @Name("oracle.jdbc.provider.observability.RoundTrip.KEY_VALUE") - @Label("Client app context, namespace, attribute, values") + @Label("Client app context, configurationspace, attribute, values") @Category({"Oracle JDBC", "Round trips"}) static class KeyValue extends RoundTripEvent{ - public KeyValue(TraceContext traceContext) { - super(traceContext); + public KeyValue(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -578,8 +626,8 @@ public KeyValue(TraceContext traceContext) { @Label("LOB and FILE related calls") @Category({"Oracle JDBC", "Round trips"}) static class LOBFileCall extends RoundTripEvent{ - public LOBFileCall(TraceContext traceContext) { - super(traceContext); + public LOBFileCall(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -587,8 +635,8 @@ public LOBFileCall(TraceContext traceContext) { @Label("Logoff of Oracle") @Category({"Oracle JDBC", "Round trips"}) static class LogOff extends RoundTripEvent{ - public LogOff(TraceContext traceContext) { - super(traceContext); + public LogOff(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -596,8 +644,8 @@ public LogOff(TraceContext traceContext) { @Label("First half of challenge-response logon") @Category({"Oracle JDBC", "Round trips"}) static class LogonChallengeResponse1 extends RoundTripEvent{ - public LogonChallengeResponse1(TraceContext traceContext) { - super(traceContext); + public LogonChallengeResponse1(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -605,8 +653,8 @@ public LogonChallengeResponse1(TraceContext traceContext) { @Label("Second half of challenge-response logon") @Category({"Oracle JDBC", "Round trips"}) static class LogonChallengeResponse2 extends RoundTripEvent{ - public LogonChallengeResponse2(TraceContext traceContext) { - super(traceContext); + public LogonChallengeResponse2(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -614,8 +662,8 @@ public LogonChallengeResponse2(TraceContext traceContext) { @Label("OEXFEN") @Category({"Oracle JDBC", "Round trips"}) static class OEXFEN extends RoundTripEvent{ - public OEXFEN(TraceContext traceContext) { - super(traceContext); + public OEXFEN(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -623,8 +671,8 @@ public OEXFEN(TraceContext traceContext) { @Label("Open a cursor") @Category({"Oracle JDBC", "Round trips"}) static class OpenCursor extends RoundTripEvent{ - public OpenCursor(TraceContext traceContext) { - super(traceContext); + public OpenCursor(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -632,8 +680,8 @@ public OpenCursor(TraceContext traceContext) { @Label("OSQL7") @Category({"Oracle JDBC", "Round trips"}) static class OSQL7 extends RoundTripEvent{ - public OSQL7(TraceContext traceContext) { - super(traceContext); + public OSQL7(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -641,8 +689,8 @@ public OSQL7(TraceContext traceContext) { @Label("Starts Oracle") @Category({"Oracle JDBC", "Round trips"}) static class OStart extends RoundTripEvent{ - public OStart(TraceContext traceContext) { - super(traceContext); + public OStart(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -650,8 +698,8 @@ public OStart(TraceContext traceContext) { @Label("Stops Oracle") @Category({"Oracle JDBC", "Round trips"}) static class OStop extends RoundTripEvent{ - public OStop(TraceContext traceContext) { - super(traceContext); + public OStop(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -659,8 +707,8 @@ public OStop(TraceContext traceContext) { @Label("Put parameter using spfile (for startup)") @Category({"Oracle JDBC", "Round trips"}) static class ParameterPutSPFile extends RoundTripEvent{ - public ParameterPutSPFile(TraceContext traceContext) { - super(traceContext); + public ParameterPutSPFile(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -668,8 +716,8 @@ public ParameterPutSPFile(TraceContext traceContext) { @Label("Ping") @Category({"Oracle JDBC", "Round trips"}) static class Ping extends RoundTripEvent{ - public Ping(TraceContext traceContext) { - super(traceContext); + public Ping(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -677,8 +725,8 @@ public Ping(TraceContext traceContext) { @Label("Pipeline End") @Category({"Oracle JDBC", "Round trips"}) static class PipelineEnd extends RoundTripEvent{ - public PipelineEnd(TraceContext traceContext) { - super(traceContext); + public PipelineEnd(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -686,8 +734,8 @@ public PipelineEnd(TraceContext traceContext) { @Label("Pipeline Begin Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class PipelinePiggybackBegin extends RoundTripEvent{ - public PipelinePiggybackBegin(TraceContext traceContext) { - super(traceContext); + public PipelinePiggybackBegin(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -695,8 +743,8 @@ public PipelinePiggybackBegin(TraceContext traceContext) { @Label("Pipeline Operation Piggyback") @Category({"Oracle JDBC", "Round trips"}) static class PipelinePiggybackOp extends RoundTripEvent{ - public PipelinePiggybackOp(TraceContext traceContext) { - super(traceContext); + public PipelinePiggybackOp(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -704,8 +752,8 @@ public PipelinePiggybackOp(TraceContext traceContext) { @Label("Rollback") @Category({"Oracle JDBC", "Round trips"}) static class Rollback extends RoundTripEvent{ - public Rollback(TraceContext traceContext) { - super(traceContext); + public Rollback(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -713,8 +761,8 @@ public Rollback(TraceContext traceContext) { @Label("Get the session key") @Category({"Oracle JDBC", "Round trips"}) static class SessionKey extends RoundTripEvent{ - public SessionKey(TraceContext traceContext) { - super(traceContext); + public SessionKey(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -722,8 +770,8 @@ public SessionKey(TraceContext traceContext) { @Label("Session state ops") @Category({"Oracle JDBC", "Round trips"}) static class SessionStateOps extends RoundTripEvent{ - public SessionStateOps(TraceContext traceContext) { - super(traceContext); + public SessionStateOps(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -731,8 +779,8 @@ public SessionStateOps(TraceContext traceContext) { @Label("Session state template") @Category({"Oracle JDBC", "Round trips"}) static class SessionStateTemplate extends RoundTripEvent{ - public SessionStateTemplate(TraceContext traceContext) { - super(traceContext); + public SessionStateTemplate(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -740,8 +788,8 @@ public SessionStateTemplate(TraceContext traceContext) { @Label("V8 session switching piggyback") @Category({"Oracle JDBC", "Round trips"}) static class SessionSwitchV8 extends RoundTripEvent{ - public SessionSwitchV8(TraceContext traceContext) { - super(traceContext); + public SessionSwitchV8(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -749,8 +797,8 @@ public SessionSwitchV8(TraceContext traceContext) { @Label("End to end tracing message") @Category({"Oracle JDBC", "Round trips"}) static class TracingMessage extends RoundTripEvent{ - public TracingMessage(TraceContext traceContext) { - super(traceContext); + public TracingMessage(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -758,8 +806,8 @@ public TracingMessage(TraceContext traceContext) { @Label("Transaction commit, rollback, recover") @Category({"Oracle JDBC", "Round trips"}) static class TransactionCommit extends RoundTripEvent{ - public TransactionCommit(TraceContext traceContext) { - super(traceContext); + public TransactionCommit(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -767,8 +815,8 @@ public TransactionCommit(TraceContext traceContext) { @Label("Transaction start, attach, detach") @Category({"Oracle JDBC", "Round trips"}) static class TransactionStart extends RoundTripEvent{ - public TransactionStart(TraceContext traceContext) { - super(traceContext); + public TransactionStart(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -776,8 +824,8 @@ public TransactionStart(TraceContext traceContext) { @Label("Data type message exchange") @Category({"Oracle JDBC", "Round trips"}) static class TTCDTYRoundtrip extends RoundTripEvent{ - public TTCDTYRoundtrip(TraceContext traceContext) { - super(traceContext); + public TTCDTYRoundtrip(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -785,8 +833,8 @@ public TTCDTYRoundtrip(TraceContext traceContext) { @Label("Protocol negotiation message exchange") @Category({"Oracle JDBC", "Round trips"}) static class TTCPRORoundtrip extends RoundTripEvent{ - public TTCPRORoundtrip(TraceContext traceContext) { - super(traceContext); + public TTCPRORoundtrip(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -794,8 +842,8 @@ public TTCPRORoundtrip(TraceContext traceContext) { @Label("XS Attach Session") @Category({"Oracle JDBC", "Round trips"}) static class XSAttachSession extends RoundTripEvent{ - public XSAttachSession(TraceContext traceContext) { - super(traceContext); + public XSAttachSession(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -803,8 +851,8 @@ public XSAttachSession(TraceContext traceContext) { @Label("XS Create Session") @Category({"Oracle JDBC", "Round trips"}) static class XSCreateSession extends RoundTripEvent{ - public XSCreateSession(TraceContext traceContext) { - super(traceContext); + public XSCreateSession(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -812,8 +860,8 @@ public XSCreateSession(TraceContext traceContext) { @Label("XS Destroy Session") @Category({"Oracle JDBC", "Round trips"}) static class XSDestroySession extends RoundTripEvent{ - public XSDestroySession(TraceContext traceContext) { - super(traceContext); + public XSDestroySession(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -821,8 +869,8 @@ public XSDestroySession(TraceContext traceContext) { @Label("XS Detach Session") @Category({"Oracle JDBC", "Round trips"}) static class XSDetachSession extends RoundTripEvent{ - public XSDetachSession(TraceContext traceContext) { - super(traceContext); + public XSDetachSession(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -830,8 +878,8 @@ public XSDetachSession(TraceContext traceContext) { @Label("XS Namespace OP") @Category({"Oracle JDBC", "Round trips"}) static class XSNamespaceOp extends RoundTripEvent{ - public XSNamespaceOp(TraceContext traceContext) { - super(traceContext); + public XSNamespaceOp(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -839,8 +887,8 @@ public XSNamespaceOp(TraceContext traceContext) { @Label("XS namespace OPs") @Category({"Oracle JDBC", "Round trips"}) static class XSNamespaceOps extends RoundTripEvent{ - public XSNamespaceOps(TraceContext traceContext) { - super(traceContext); + public XSNamespaceOps(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -848,8 +896,8 @@ public XSNamespaceOps(TraceContext traceContext) { @Label("XS Set Session Parameter") @Category({"Oracle JDBC", "Round trips"}) static class XSSetSessionParameter extends RoundTripEvent{ - public XSSetSessionParameter(TraceContext traceContext) { - super(traceContext); + public XSSetSessionParameter(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -857,8 +905,8 @@ public XSSetSessionParameter(TraceContext traceContext) { @Label("XS State Sync OP") @Category({"Oracle JDBC", "Round trips"}) static class XSStateSyncOp extends RoundTripEvent{ - public XSStateSyncOp(TraceContext traceContext) { - super(traceContext); + public XSStateSyncOp(TraceContext traceContext, ObservabilityConfiguration configuration) { + super(traceContext, configuration); } } @@ -867,16 +915,16 @@ public XSStateSyncOp(TraceContext traceContext) { @Category({"Oracle JDBC", "Round trips"}) static class RoundTripEvent extends Event { - public RoundTripEvent(TraceContext traceContext) { - setValues(traceContext); + public RoundTripEvent(TraceContext traceContext, ObservabilityConfiguration configuration) { + setValues(traceContext, configuration); } - public void setValues(TraceContext traceContext) { + public void setValues(TraceContext traceContext, ObservabilityConfiguration configuration) { this.connectionID = traceContext.getConnectionId(); this.databaseOperation = traceContext.databaseOperation(); this.tenant = traceContext.tenant(); this.sqlID = traceContext.getSqlId(); - if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + if (configuration.getSensitiveDataEnabled()) { this.originalSQLText = traceContext.originalSqlText(); this.actualSQLText = traceContext.actualSqlText(); this.databaseUser = traceContext.user(); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java index f7f7ee64..814c4e99 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java @@ -1,9 +1,47 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability.tracers.jfr; import jdk.jfr.Event; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; +import oracle.jdbc.provider.observability.ObservabilityConfiguration; import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; import oracle.jdbc.provider.observability.tracers.jfr.JFREventFactory.RoundTripEvent; @@ -12,22 +50,38 @@ */ public class JFRTracer implements ObservabilityTracer{ + /** + * Configuraiton + */ + private final ObservabilityConfiguration configuration; + /** * Creates a new instance. + * + * @param configuration the configuraiton. */ - public JFRTracer() {} + public JFRTracer(ObservabilityConfiguration configuration) { + this.configuration = configuration; + } @Override - public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { + public String getName() { + return "JFR"; + } + + @Override + public Object traceRoundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { if (sequence.equals(Sequence.BEFORE)) { - RoundTripEvent event = JFREventFactory.createJFREvent(traceContext); + // Create the event and start measuring event duration + RoundTripEvent event = JFREventFactory.createJFRRoundTripEvent(traceContext, configuration); event.begin(); return event; } else { if (userContext != null) { RoundTripEvent event = (RoundTripEvent) userContext; - event.setValues(traceContext); - event.end(); + // set event attributes + event.setValues(traceContext, configuration); + // stop the measuring event durating and commit event.commit(); } } @@ -36,10 +90,12 @@ public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Objec @Override public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, Object... params) { + // Create event and commit Event executionEvent = JFREventFactory.createExecutionEvent(event, params); executionEvent.begin(); executionEvent.commit(); - return null; + //Return previous user context + return userContext; } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java index 3143c790..f4dd8eb8 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java @@ -1,14 +1,46 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability.tracers.otel; import java.sql.SQLException; -import java.time.Instant; -import java.util.EnumMap; -import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import javax.security.auth.login.Configuration; - import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; @@ -22,7 +54,7 @@ import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; import oracle.jdbc.TraceEventListener.TraceContext; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; +import oracle.jdbc.provider.observability.ObservabilityConfiguration; import oracle.jdbc.provider.observability.tracers.ObservabilityTracer; /** @@ -37,40 +69,66 @@ public class OTelTracer implements ObservabilityTracer { */ private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; + /** + * The trace context is sent to the server in two lines, this is the first + * line it contains the version and the span context. + */ + private static final String TRACE_FORMAT = "traceparent: %s-%s-%s-%s\r\n"; + /** + * Trace context version. + */ + private static final String TRACE_VERSION = "00"; + + /** + * Format of the second line sent to the server containing the trace context. + * It contains the trace state. + */ + private static final String TRACE_STATE_FORMAT = "tracestate: %s\r\n"; /** * Logger. */ private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); + /** + * Configuraiton + */ + private final ObservabilityConfiguration configuration; + + /** * Constructor. This tracer always uses {@link GlobalOpenTelemetry} to get * the Open Telemetry tracer. + * + * @param configuration the configuration. */ - public OTelTracer() { } + public OTelTracer(ObservabilityConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public String getName() { + return "OTEL"; + } @Override - public Object traceRoundtrip(Sequence sequence, TraceContext traceContext, Object userContext) { + public Object traceRoundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { if (sequence == Sequence.BEFORE) { // Create the Span before the round-trip. final Span span = initAndGetSpan(traceContext, traceContext.databaseOperation()); - try (Scope ignored = span.makeCurrent()) { - traceContext.setClientInfo(TRACE_KEY, getTraceValue(span)); - } catch (Exception ex) { - logger.log(Level.WARNING, ex.getMessage(), ex); - } + makeSpanCurrentAndSendContextToServer(traceContext, span); // Return the Span instance to the driver. The driver holds this instance and - // supplies it - // as user context parameter on the next round-trip call. + // supplies it as user context parameter on the next round-trip call. return span; } else { // End the Span after the round-trip. if (userContext instanceof Span) { final Span span = (Span) userContext; span.setStatus(traceContext.isCompletedExceptionally() ? StatusCode.ERROR : StatusCode.OK); - span.end(Instant.now()); + span.end(); } + logger.log(Level.WARNING, "Unknown or null user context received from the driver."); return null; } } @@ -85,7 +143,7 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, .setAttribute("Error message", params[0].toString()) .setAttribute("VIP Address", params[7].toString()); // Add sensitive information (URL and SQL) if it is enabled - if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + if (configuration.getSensitiveDataEnabled()) { logger.log(Level.FINEST, "Sensitive information on"); spanBuilder.setAttribute("Protocol", params[1].toString()) .setAttribute("Host", params[2].toString()) @@ -94,7 +152,8 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, .setAttribute("SID", params[5].toString()) .setAttribute("Connection data", params[6].toString()); } - return spanBuilder.startSpan(); + // start and end span. + spanBuilder.startSpan().end(); } else if (event == TraceEventListener.JdbcExecutionEvent.AC_REPLAY_STARTED || event == TraceEventListener.JdbcExecutionEvent.AC_REPLAY_SUCCESSFUL) { SpanBuilder spanBuilder = tracer @@ -103,7 +162,7 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, .setAttribute("Error code", ((SQLException) params[1]).getErrorCode()) .setAttribute("SQL state", ((SQLException) params[1]).getSQLState()) .setAttribute("Current replay retry count", params[2].toString()); - return spanBuilder.startSpan(); + spanBuilder.startSpan().end(); } else { logger.log(Level.WARNING, "Unknown event received : " + event.toString()); } @@ -111,9 +170,18 @@ public Object traceExecutionEvent(JdbcExecutionEvent event, Object userContext, // log wrong number of parameters returned for execution event logger.log(Level.WARNING, "Wrong number of parameters received for event " + event.toString()); } - return null; + // return the previous userContext + return userContext; } + /** + * Creates a Open Telemetry Span and sets it's attributes according to the + * trace context and the configuration. + * + * @param traceContext the trace context. + * @param spanName then span name. + * @return returns the Span. + */ private Span initAndGetSpan(TraceContext traceContext, String spanName) { /* * If this is in the context of current span, the following becomes a nested or @@ -132,7 +200,7 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { .setAttribute("SQL ID", traceContext.getSqlId()); // Add sensitive information (URL and SQL) if it is enabled - if (ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()) { + if (configuration.getSensitiveDataEnabled()) { logger.log(Level.FINEST, "Sensitive information on"); spanBuilder .setAttribute("Original SQL Text", traceContext.originalSqlText()) @@ -146,35 +214,57 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { } /** - * Builds the Open Telemetry trace context to be sent to the database server. + * Sets the span as the current Open Telemetry Span and sends context information + * to the database server. + * + * @param traceContext the trace context * @param span the currect spans - * @return the current trace context formatted so that the server can read it. */ - private String getTraceValue(Span span) { + private void makeSpanCurrentAndSendContextToServer(TraceContext traceContext, Span span) { final String traceParent = initAndGetTraceParent(span); final String traceState = initAndGetTraceState(span); - return traceParent + traceState; + + try (Scope ignored = span.makeCurrent()) { + // Send the current context to the server + traceContext.setClientInfo(TRACE_KEY, traceParent + traceState); + } catch (Exception ex) { + logger.log(Level.WARNING, "An error occured while sending the current Open Telemetry context to the server. " + + ex.getMessage(), ex); + } } + /** + * Formats the current Open Telemetry context in a format that the server can + * understand. + * + * @param span the current Span + * @return the current Open Telemetry context formatted so that the server + * can understand. + */ private String initAndGetTraceParent(Span span) { final SpanContext spanContext = span.getSpanContext(); - // The current specification assumes the version is set to 00. - final String version = "00"; final String traceId = spanContext.getTraceId(); // parent-id is known as the span-id final String parentId = spanContext.getSpanId(); final String traceFlags = spanContext.getTraceFlags().toString(); - return String.format("traceparent: %s-%s-%s-%s\r\n", - version, traceId, parentId, traceFlags); + return String.format(TRACE_FORMAT, TRACE_VERSION, traceId, parentId, traceFlags); } + /** + * Formats the current Open Telemetry Span state in a format that the server + * can understand. + * + * @param span the current Span + * @return the current Open Telemetry Span state formatted so that the server + * can understand. + */ private String initAndGetTraceState(Span span) { final TraceState traceState = span.getSpanContext().getTraceState(); final StringBuilder stringBuilder = new StringBuilder(); traceState.forEach((k, v) -> stringBuilder.append(k).append("=").append(v)); - return String.format("tracestate: %s\r\n", stringBuilder); + return String.format(TRACE_STATE_FORMAT, stringBuilder); } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java deleted file mode 100644 index 46d5f676..00000000 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerProvider.java +++ /dev/null @@ -1,102 +0,0 @@ -package oracle.jdbc.provider.opentelemetry; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; - -import oracle.jdbc.TraceEventListener; -import oracle.jdbc.provider.observability.ObservabilityTraceEventListener; -import oracle.jdbc.provider.observability.ObservabilityTraceEventListenerProvider; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; - -/** - *

    - * This class implements the TraceEventListenerProvider interface exposed by the - * Oracle JDBC driver. It provides TraceEventListeners of type {@link - * oracle.jdbc.provider.observability.ObservabilityTraceEventListener}. - *

    - *

    - * The provider registers a MBean (with objectName {@value #MBEAN_OBJECT_NAME}) - * that allows to configure the TraceEventListener by setting attributes. The - * following attributes are available: - *

      - *
    • Enabled: enables/disables exporting traces to Open Telemetry - * (true by default)
    • - *
    • SensitiveDataEnabled: enables/disables exporting sensiteve data - * to Open Telemetry(false by default)
    • - *
    - */ -public class OpenTelemetryTraceEventListenerProvider extends ObservabilityTraceEventListenerProvider { - - private static final String PROVIDER_NAME = "open-telemetry-trace-event-listener-provider"; - private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener"; - - /** - * Name of the property used to enable or disable this listener. - */ - public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED = "oracle.jdbc.provider.opentelemetry.enabled"; - /** - * Name of the property used to enable or disable sensitive data for this - * listener. - */ - public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; - - /** - * Logger - */ - private Logger logger = Logger.getLogger(OpenTelemetryTraceEventListenerProvider.class.getName()); - - private static ObjectName objectName; - - static { - try { - objectName = new ObjectName(MBEAN_OBJECT_NAME); - } catch (MalformedObjectNameException e) { - objectName = null; - } - } - - /** - * Constructs a new instance of OpenTelemetryTraceEventListenerProvider. This - * constructor will be called by the driver's service provider to create a new - * instance. - */ - public OpenTelemetryTraceEventListenerProvider() { } - - @Override - public String getName() { - return PROVIDER_NAME; - } - - @Override - public Collection getParameters() { - return Collections.emptyList(); - } - - @Override - public TraceEventListener getTraceEventListener(Map map) { - try { - if (!server.isRegistered(objectName)) { - boolean enabled = Boolean.valueOf(System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED, "true")); - String sensitiveDataEnabled = System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "false"); - ObservabilityConfiguration.getInstance().setEnabled(enabled); - ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(Boolean.parseBoolean(sensitiveDataEnabled)); - - server.registerMBean(ObservabilityConfiguration.getInstance(), objectName); - } - } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { - logger.log(Level.WARNING, "Could not register MBean", e); - } - return ObservabilityTraceEventListener.getInstance(); - } - -} diff --git a/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider index 9b12f75b..b1c86eef 100644 --- a/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider +++ b/ojdbc-provider-observability/src/main/resources/META-INF/services/oracle.jdbc.spi.TraceEventListenerProvider @@ -1,2 +1,2 @@ oracle.jdbc.provider.observability.ObservabilityTraceEventListenerProvider -oracle.jdbc.provider.opentelemetry.OpenTelemetryTraceEventListenerProvider \ No newline at end of file +oracle.jdbc.provider.observability.OpenTelemetryTraceEventListenerProvider \ No newline at end of file diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java new file mode 100644 index 00000000..ca3f32cc --- /dev/null +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java @@ -0,0 +1,120 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ +package oracle.jdbc.provider.observability; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; + +import javax.management.Attribute; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.jupiter.api.Test; + +import oracle.jdbc.spi.OracleResourceProvider.Parameter; +import oracle.jdbc.spi.TraceEventListenerProvider; + +public class BackwardCompatibilityTest { + private static final String INSTANCE_NAME = "test-instance"; + + @Test + public void testConfiguration() throws Exception { + + // System properties + System.setProperty("oracle.jdbc.provider.opentelemetry.enabled", "true"); + System.setProperty("oracle.jdbc.provider.opentelemetry.sensitive-enabled", "true"); + + TraceEventListenerProvider provider = new OpenTelemetryTraceEventListenerProvider(); + Map parameters = new HashMap<>(); + provider.getParameters().forEach(parameter -> { + parameters.put(parameter, (CharSequence)INSTANCE_NAME); + }); + ObservabilityTraceEventListener listener = (ObservabilityTraceEventListener)provider.getTraceEventListener(parameters); + + ObservabilityConfiguration configuration = ObservabilityTraceEventListener.getObservabilityConfiguration(INSTANCE_NAME); + + assertEquals(true, configuration.getEnabled()); + assertEquals("OTEL", configuration.getEnabledTracers()); + assertEquals(true, configuration.getSensitiveDataEnabled()); + + assertEquals(1, configuration.getEnabledTracersAsList().size()); + assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); + + // MBean + ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + String enabled = server.getAttribute(objectName, "Enabled").toString(); + String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals(enabled, "true"); + assertEquals(enabledTracers, "OTEL"); + assertEquals(sensitiveDataEnabled, "true"); + + server.setAttribute(objectName, new Attribute("Enabled", false)); + server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); + + assertEquals(false, configuration.getEnabled()); + assertEquals(false, configuration.getSensitiveDataEnabled()); + + assertEquals("OTEL", configuration.getEnabledTracers()); + assertEquals(false, configuration.getSensitiveDataEnabled()); + + assertEquals(1, configuration.getEnabledTracersAsList().size()); + assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); + + // Singleton + configuration.setEnabled(true); + configuration.setSensitiveDataEnabled(true); + + enabled = server.getAttribute(objectName, "Enabled").toString(); + enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); + sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); + + assertEquals("true", enabled); + assertEquals("OTEL", enabledTracers); + assertEquals("true", sensitiveDataEnabled); + + assertEquals(1, configuration.getEnabledTracersAsList().size()); + assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); + + } +} diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index 7a23cdb0..b9f91bd9 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -1,8 +1,47 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability; import static org.junit.jupiter.api.Assertions.assertEquals; import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; import javax.management.Attribute; import javax.management.MBeanServer; @@ -10,68 +49,73 @@ import org.junit.jupiter.api.Test; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.TracerType; +import oracle.jdbc.TraceEventListener; import oracle.jdbc.spi.TraceEventListenerProvider; +import oracle.jdbc.spi.OracleResourceProvider.Parameter; public class ObservabilityConfigurationTest { + private static final String INSTANCE_NAME = "test-instance"; + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + // Set system properties before starting static { System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "JFR"); System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "true"); - System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); } @Test public void testConfiguration() throws Exception { - - System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); + + // Create a TraceEventListner named test-instance TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); - provider.getTraceEventListener(null); + Map parameters = new HashMap<>(); + provider.getParameters().forEach(parameter -> { + parameters.put(parameter, (CharSequence)INSTANCE_NAME); + }); + ObservabilityTraceEventListener listener = (ObservabilityTraceEventListener)provider.getTraceEventListener(parameters); - System.out.println(ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals("JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + // Get the configuration object + ObservabilityConfiguration configuration = ObservabilityTraceEventListener.getObservabilityConfiguration(INSTANCE_NAME); - assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + // Verify that the configuration matches the configuration set using system properties + assertEquals("JFR", configuration.getEnabledTracers()); + assertEquals(true, configuration.getSensitiveDataEnabled()); + assertEquals(1, configuration.getEnabledTracersAsList().size()); + assertEquals("JFR", configuration.getEnabledTracersAsList().get(0)); - // MBean - ObjectName objectName = new ObjectName( - "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration"); - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + // Get the MBean for the configuration + ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); + + // Get configuration using MBean and check that it matches the configuration set using system properties String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - assertEquals(enabledTracers, "JFR"); assertEquals(sensitiveDataEnabled, "true"); + // Update configuration using MBean server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); - assertEquals("OTEL,JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); + // check that the values have been updated using the instance of the configuration + assertEquals("OTEL,JFR", configuration.getEnabledTracers()); + assertEquals(false, configuration.getSensitiveDataEnabled()); + assertEquals(2, configuration.getEnabledTracersAsList().size()); + assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); + assertEquals("JFR", configuration.getEnabledTracersAsList().get(1)); - assertEquals("OTEL,JFR", ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); - - assertEquals(2, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); - assertEquals(TracerType.JFR, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(1)); - - // Singleton - ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); + // Update the configuration using the instance of the configuration + configuration.setEnabledTracers("OTEL"); + configuration.setSensitiveDataEnabled(true); + // Check that the values returned by the MBean correspond to the values set using the instance enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - assertEquals("OTEL", enabledTracers); assertEquals("true", sensitiveDataEnabled); - - assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); + assertEquals(1, configuration.getEnabledTracersAsList().size()); + assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java index d2e58eda..7a765d5a 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTestProperties.java @@ -1,3 +1,40 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability; public enum ObservabilityTestProperties { diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index 513de9ef..74b4a592 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -1,8 +1,46 @@ +/* + ** Copyright (c) 2025 Oracle and/or its affiliates. + ** + ** The Universal Permissive License (UPL), Version 1.0 + ** + ** Subject to the condition set forth below, permission is hereby granted to any + ** person obtaining a copy of this software, associated documentation and/or data + ** (collectively the "Software"), free of charge and under any and all copyright + ** rights in the Software, and any and all patent rights owned or freely + ** licensable by each licensor hereunder covering either (i) the unmodified + ** Software as contributed to or provided by such licensor, or (ii) the Larger + ** Works (as defined below), to deal in both + ** + ** (a) the Software, and + ** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + ** one is included with the Software (each a "Larger Work" to which the Software + ** is contributed by such licensors), + ** + ** without restriction, including without limitation the rights to copy, create + ** derivative works of, display, perform, and distribute the Software and make, + ** use, sell, offer for sale, import, export, have made, and have sold the + ** Software and the Larger Work(s), and to sublicense the foregoing rights on + ** either these or other terms. + ** + ** This license is subject to the following condition: + ** The above copyright notice and either this complete permission notice or at + ** a minimum a reference to the UPL must be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + ** SOFTWARE. + */ package oracle.jdbc.provider.observability; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; @@ -35,7 +73,6 @@ import oracle.jdbc.DatabaseFunction; import oracle.jdbc.driver.OracleConnection; import oracle.jdbc.provider.TestProperties; -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; public class ObservabilityTraceEventListenerTest { String url = TestProperties.getOrAbort(ObservabilityTestProperties.OBSERVABILITY_URL); @@ -68,13 +105,14 @@ public class ObservabilityTraceEventListenerTest { @ValueSource(booleans = {true, false}) public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { - ObservabilityConfiguration.getInstance().setEnabledTracers("JFR"); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); + System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "JFR"); + System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", String.valueOf(sensitiveDataEnabled)); Configuration configuration = Configuration.getConfiguration("default"); String connectionId = null; try (Recording recording = new Recording(configuration)) { recording.start(); - try (Connection connection = DriverManager.getConnection(url, userName, password); + String jfrUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.name=test-jfr" + sensitiveDataEnabled; + try (Connection connection = DriverManager.getConnection(jfrUrl, userName, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { connectionId = ((OracleConnection)connection).getNetConnectionId(); @@ -84,16 +122,17 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { } recording.stop(); recording.dump(Path.of("dump" + sensitiveDataEnabled + ".jfr")); - + try (RecordingFile recordingFile = new RecordingFile(Path.of("dump" + sensitiveDataEnabled + ".jfr"))) { + int countRoundTrips = 0; while (recordingFile.hasMoreEvents()) { RecordedEvent event = recordingFile.readEvent(); if (event.getEventType().getCategoryNames().contains("Round trips")) { + countRoundTrips++; switch (event.getEventType().getName()) { case SESSION_KEY: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); - assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); @@ -102,7 +141,6 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case AUTH_CALL: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); - assertNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); @@ -112,7 +150,6 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case EXECUTE_QUERY: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); - assertNotNull(event.getString("tenant")); assertNotNull(event.getString("sqlID")); assertEquals(sensitiveDataEnabled, event.getString("originalSQLText") != null); assertEquals(sensitiveDataEnabled, event.getString("actualSQLText") != null); @@ -121,7 +158,6 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { case LOGOFF: assertEquals(connectionId, event.getString("connectionID")); assertNotNull(event.getString("databaseOperation")); - assertNotNull(event.getString("tenant")); assertNull(event.getString("sqlID")); assertNull(event.getString("originalSQLText")); assertNull(event.getString("actualSQLText")); @@ -132,6 +168,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { } } } + assertTrue(countRoundTrips > 0, "Application should have performed at least one round trip"); } } @@ -141,9 +178,9 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { @ValueSource(booleans = {true, false}) public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.clearInvocations(tracer, spanBuilder); - ObservabilityConfiguration.getInstance().setEnabledTracers("OTEL"); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(sensitiveDataEnabled); - String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider"; + System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "OTEL"); + System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", String.valueOf(sensitiveDataEnabled)); + String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.name=test-otel-" + sensitiveDataEnabled ; String connectionId = null; try (Connection connection = DriverManager.getConnection(otelUrl, userName, password); Statement statement = connection.createStatement(); @@ -171,7 +208,7 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Original SQL Text", "SELECT 'OK' FROM DUAL"); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Actual SQL Text", "SELECT 'OK' FROM DUAL"); } - Mockito.verify(span, atLeast(4)).end(Mockito.any()); + Mockito.verify(span, atLeast(4)).end(); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java deleted file mode 100644 index 2719e235..00000000 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/opentelemetry/BackwardCompatibilityTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package oracle.jdbc.provider.opentelemetry; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.lang.management.ManagementFactory; - -import javax.management.Attribute; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.junit.jupiter.api.Test; - -import oracle.jdbc.provider.observability.configuration.ObservabilityConfiguration; -import oracle.jdbc.provider.observability.tracers.TracerType; -import oracle.jdbc.spi.TraceEventListenerProvider; - -public class BackwardCompatibilityTest { - @Test - public void testConfiguration() throws Exception { - - // System properties - System.setProperty("oracle.jdbc.provider.opentelemetry.enabled", "true"); - System.setProperty("oracle.jdbc.provider.opentelemetry.sensitive-enabled", "true"); - - TraceEventListenerProvider provider = new OpenTelemetryTraceEventListenerProvider(); - provider.getTraceEventListener(null); - - assertEquals(true, ObservabilityConfiguration.getInstance().getEnabled()); - assertEquals("OTEL", ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals(true, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); - - assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); - - // MBean - ObjectName objectName = new ObjectName( - "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener"); - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - String enabled = server.getAttribute(objectName, "Enabled").toString(); - String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); - String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - - assertEquals(enabled, "true"); - assertEquals(enabledTracers, "OTEL"); - assertEquals(sensitiveDataEnabled, "true"); - - server.setAttribute(objectName, new Attribute("Enabled", false)); - server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); - - assertEquals(false, ObservabilityConfiguration.getInstance().getEnabled()); - assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); - - assertEquals("OTEL", ObservabilityConfiguration.getInstance().getEnabledTracers()); - assertEquals(false, ObservabilityConfiguration.getInstance().getSensitiveDataEnabled()); - - assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); - - // Singleton - ObservabilityConfiguration.getInstance().setEnabled(true); - ObservabilityConfiguration.getInstance().setSensitiveDataEnabled(true); - - enabled = server.getAttribute(objectName, "Enabled").toString(); - enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); - sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - - assertEquals("true", enabled); - assertEquals("OTEL", enabledTracers); - assertEquals("true", sensitiveDataEnabled); - - assertEquals(1, ObservabilityConfiguration.getInstance().getEnabledTracersSet().size()); - assertEquals(TracerType.OTEL, ObservabilityConfiguration.getInstance().getEnabledTracersSet().get(0)); - - } -} diff --git a/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java b/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java index 00ac32c7..ddd1a7d4 100644 --- a/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java +++ b/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java @@ -73,9 +73,9 @@ * * * The system properties - * {@value #OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED} + * {@value #OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED} * and - * {@value #OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED} + * {@value #OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED} * can be used * to enable/disable this listener and the use of sensitive data by this * listener. A MBean registered by the {@link @@ -88,12 +88,12 @@ public class OpenTelemetryTraceEventListener /** * Name of the property used to enable or disable this listener. */ - public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED = "oracle.jdbc.provider.opentelemetry.enabled"; + public static final String OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED = "oracle.jdbc.provider.opentelemetry.enabled"; /** * Name of the property used to enable or disable sensitive data for this * listener. */ - public static final String OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; + public static final String OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED = "oracle.jdbc.provider.opentelemetry.sensitive-enabled"; private static final String TRACE_KEY = "clientcontext.ora$opentelem$tracectx"; @@ -132,8 +132,8 @@ private enum Configuration { private AtomicBoolean sensitiveDataEnabled; private Configuration(boolean enabled, boolean sensitiveDataEnabled) { - String enabledStr = System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED); - String sensitiveStr = System.getProperty(OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED); + String enabledStr = System.getProperty(OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED); + String sensitiveStr = System.getProperty(OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED); this.enabled = new AtomicBoolean(enabledStr == null ? enabled : Boolean.parseBoolean(enabledStr)); this.sensitiveDataEnabled = new AtomicBoolean( sensitiveStr == null ? sensitiveDataEnabled : Boolean.parseBoolean(sensitiveStr)); diff --git a/ojdbc-provider-opentelemetry/src/test/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerTest.java b/ojdbc-provider-opentelemetry/src/test/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerTest.java index 8bac137e..3fd05dba 100644 --- a/ojdbc-provider-opentelemetry/src/test/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerTest.java +++ b/ojdbc-provider-opentelemetry/src/test/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListenerTest.java @@ -97,8 +97,8 @@ public void setupMocks() throws Exception { @Test void testPropertiesDisabled() throws Exception { - System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED, "false"); - System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "false"); + System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED, "false"); + System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "false"); OpenTelemetryTraceEventListener traceEventListener = new OpenTelemetryTraceEventListener(tracer); Assertions.assertFalse(traceEventListener.isEnabled(), "Set to false using system property"); Assertions.assertFalse(traceEventListener.isSensitiveDataEnabled(), "Set to false using system property"); @@ -106,8 +106,8 @@ void testPropertiesDisabled() throws Exception { @Test void testPropertiesEnabled() throws Exception { - System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_ENABLED, "true"); - System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMENTRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "true"); + System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMETRY_TRACE_EVENT_LISTENER_ENABLED, "true"); + System.setProperty(OpenTelemetryTraceEventListener.OPEN_TELEMETRY_TRACE_EVENT_LISTENER_SENSITIVE_ENABLED, "true"); OpenTelemetryTraceEventListener traceEventListener = new OpenTelemetryTraceEventListener(tracer); Assertions.assertTrue(traceEventListener.isEnabled(), "Set to false using system property"); Assertions.assertTrue(traceEventListener.isSensitiveDataEnabled(), "Set to false using system property"); From 65c7765c765bb20007ec3121bb832ef4fa7ac9b0 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 7 Mar 2025 09:33:06 +0100 Subject: [PATCH 21/25] Changed action version for deprecated action --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index ffaaedf7..1e5dd773 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -18,7 +18,7 @@ jobs: with: java-version: 11 - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} From f6e972f4bfbdc4f45adc0e16bd9f5885f85b0e25 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 7 Mar 2025 09:41:51 +0100 Subject: [PATCH 22/25] Set version in pom files correctly --- ojdbc-provider-jackson-oson/pom.xml | 1 - ojdbc-provider-observability/pom.xml | 2 -- 2 files changed, 3 deletions(-) diff --git a/ojdbc-provider-jackson-oson/pom.xml b/ojdbc-provider-jackson-oson/pom.xml index 179e20b7..6d6f9b6f 100644 --- a/ojdbc-provider-jackson-oson/pom.xml +++ b/ojdbc-provider-jackson-oson/pom.xml @@ -21,7 +21,6 @@ com.oracle.database.jdbc ojdbc-provider-common - 1.0.3 com.oracle.database.jdbc diff --git a/ojdbc-provider-observability/pom.xml b/ojdbc-provider-observability/pom.xml index ead8150e..8a7601cb 100644 --- a/ojdbc-provider-observability/pom.xml +++ b/ojdbc-provider-observability/pom.xml @@ -13,7 +13,6 @@ Oracle JDBC Observability Provider com.oracle.database.jdbc ojdbc-provider-observability - 1.0.3 1.44.1 @@ -49,7 +48,6 @@ ojdbc-provider-common com.oracle.database.jdbc - 1.0.2 tests test-jar From 8f7b15db374e3bbfc4e37f148b29f762a86c0017 Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 7 Mar 2025 09:52:22 +0100 Subject: [PATCH 23/25] Fixed tests when running in the same JVM --- .../provider/observability/ObservabilityConfigurationTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index b9f91bd9..8c5904de 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -49,13 +49,12 @@ import org.junit.jupiter.api.Test; -import oracle.jdbc.TraceEventListener; import oracle.jdbc.spi.TraceEventListenerProvider; import oracle.jdbc.spi.OracleResourceProvider.Parameter; public class ObservabilityConfigurationTest { - private static final String INSTANCE_NAME = "test-instance"; + private static final String INSTANCE_NAME = "configuration-test-instance"; MBeanServer server = ManagementFactory.getPlatformMBeanServer(); From 1157aa3c553e2d820fc2de2be24a203f829c21bf Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Fri, 7 Mar 2025 18:28:06 +0100 Subject: [PATCH 24/25] Unique identifier and refactoring. --- ojdbc-provider-observability/README.md | 12 +- .../ObservabilityConfiguration.java | 2 +- .../ObservabilityTraceEventListener.java | 89 +++++------ ...servabilityTraceEventListenerProvider.java | 31 ++-- ...enTelemetryTraceEventListenerProvider.java | 4 +- .../observability/tracers/jfr/JFRTracer.java | 13 +- .../tracers/otel/OTelTracer.java | 10 +- .../BackwardCompatibilityTest.java | 5 +- .../ObservabilityConfigurationTest.java | 146 ++++++++++++++---- .../ObservabilityTraceEventListenerTest.java | 13 +- .../OpenTelemetryTraceEventListener.java | 2 +- 11 files changed, 216 insertions(+), 111 deletions(-) diff --git a/ojdbc-provider-observability/README.md b/ojdbc-provider-observability/README.md index cc17d12f..dcf99623 100644 --- a/ojdbc-provider-observability/README.md +++ b/ojdbc-provider-observability/README.md @@ -59,6 +59,16 @@ application's classpath and set the following connection property: oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider ``` +A unique identifier connection property allows to identify the trace event +listener. Connections setting the same unique identifier use the same trace +event listener and share the same configuration. + +```java +oracle.jdbc.provider.traceEventListener.unique_identifier= +``` + +If no unique identifier is provided, the unique idetifier "default" is used. + ## Configuration The provider can be configured by: @@ -69,7 +79,7 @@ System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", "t ``` * or using the MBean. ```java -ObservabilityTraceEventListener listener = ObservabilityTraceEventListener.getTraceEventListener(""); +ObservabilityTraceEventListener listener = ObservabilityTraceEventListener.getTraceEventListener(""); ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java index 4f417b7d..0fc81a11 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityConfiguration.java @@ -256,7 +256,7 @@ public String getEnabledTracers() { public void setEnabledTracers(String tracers){ observabilityConfigurationLock.lock(); try { - String[] items = tracers.replaceAll("\\s", tracers).split(","); + String[] items = tracers.replaceAll("\\s", "").split(","); enabledTracers = Arrays.asList(items); } finally { observabilityConfigurationLock.unlock(); diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java index 1032ef3c..9fd33725 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListener.java @@ -99,13 +99,18 @@ public class ObservabilityTraceEventListener implements TraceEventListener { /** * MBean object name format */ - private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration,name=%s"; - private static final String MBEAN_OBJECT_NAME_OLD = "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener,name=%s"; + private static final String MBEAN_OBJECT_NAME = "com.oracle.jdbc.provider.observability:type=ObservabilityConfiguration,uniqueIdentifier=%s"; + private static final String MBEAN_OBJECT_NAME_OTEL = "com.oracle.jdbc.extension.opentelemetry:type=OpenTelemetryTraceEventListener,uniqueIdentifier=%s"; + + /** + * Default unique identifier, if parameter not set. + */ + static final CharSequence DEFAULT_UNIQUE_IDENTIFIER = "default"; /** * MBean server */ - protected static final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + private static final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); /** * Logger @@ -118,24 +123,30 @@ public class ObservabilityTraceEventListener implements TraceEventListener { */ private final ObservabilityConfiguration configuration; + /** + * Static map linking the name of the listener to its instance. + */ + private static final Map INSTANCES + = new ConcurrentHashMap<>(); - private final String mBeanObjectName; + private ObjectName mBeanObjectName; /** * Create a trace event listener identified by the given name. - * @param name the name of the trace event listener. + * @param uniqueIdentifier the name of the trace event listener. * @param configurationType configuration type for backward compatibility. */ - private ObservabilityTraceEventListener(String name, ObservabilityConfigurationType configurationType) { + private ObservabilityTraceEventListener(String uniqueIdentifier, + ObservabilityConfigurationType configurationType) { // Create the configuration for this instance and register MBean - mBeanObjectName = ObservabilityConfigurationType.OTEL.equals(configurationType) ? - String.format(MBEAN_OBJECT_NAME_OLD, name) : - String.format(MBEAN_OBJECT_NAME, name); + final String mBeanName = ObservabilityConfigurationType.OTEL.equals(configurationType) ? + String.format(MBEAN_OBJECT_NAME_OTEL, uniqueIdentifier) : + String.format(MBEAN_OBJECT_NAME, uniqueIdentifier); this.configuration = new ObservabilityConfiguration(configurationType); try { - final ObjectName objectName = new ObjectName(mBeanObjectName); - if (!server.isRegistered(objectName)) { - server.registerMBean(configuration, objectName); + mBeanObjectName = new ObjectName(mBeanName); + if (!server.isRegistered(mBeanObjectName)) { + server.registerMBean(configuration, mBeanObjectName); logger.log(Level.FINEST, "MBean and tracers registered"); } } catch (InstanceAlreadyExistsException | MBeanRegistrationException | @@ -147,12 +158,6 @@ private ObservabilityTraceEventListener(String name, ObservabilityConfigurationT configuration.registerTracer(new JFRTracer(configuration)); } - /** - * Static map linking the name of the listener to its instance. - */ - private static final Map INSTANCES - = new ConcurrentHashMap<>(); - @Override @SuppressWarnings("unchecked") public Object roundTrip(Sequence sequence, TraceContext traceContext, Object userContext) { @@ -220,53 +225,51 @@ public boolean isDesiredEvent(JdbcExecutionEvent event) { return true; } + /** - * Returns the trace event listener identified by the given name. + * Returns the MBean object name assiciated with the configuration of the + * listener. * - * @param name the name of the listener. - * @return the trace event listener identified by the given name, or {@code - * null} if no trace event listener with that name was found. + * @return the MBean object name. */ - public static ObservabilityTraceEventListener getTraceEventListener(String name) { - return INSTANCES.get(name); + public ObjectName getMBeanObjectName() { + return mBeanObjectName; } /** - * Returns the configuration for a given listener. + * Returns the listener's configuration. * - * @param name the name of the listener. - * @return then configuration instance associated to that listener, or {@code - * null} if not trace event listener with that name was found. + * @return the configuration instance associated to the listener. */ - public static ObservabilityConfiguration getObservabilityConfiguration(String name) { - ObservabilityTraceEventListener listener = INSTANCES.get(name); - if (listener != null) { - return listener.configuration; - } - return null; + public ObservabilityConfiguration getObservabilityConfiguration() { + return configuration; } + /** - * Returns the MBean object name assiciated with the configuration of the - * listener. + * Returns the trace event listener identified by the given unique idetifier. * - * @return the MBean object name. + * @param uniqueIdentifier the unique identifier, if no unique identifier was + * provided as a connection property, the unique identifier is "default". + * @return the trace event listener identified by the given unique idetifier, + * or {@code null} if no trace event listener with that unique idetifier was + * found. */ - public String getMBeanObjectName() { - return mBeanObjectName; + public static ObservabilityTraceEventListener getTraceEventListener(String uniqueIdentifier) { + return INSTANCES.get(uniqueIdentifier); } - /** + /** * Gets or creates an instance of {@link ObservabilityTraceEventListener} * associated to the name. - * @param name the name of the listener instance. + * @param uniqueIdentifier the name of the listener instance. * @param configurationType configuration type for backward compatibility. * * @return an instance of {@link ObservabilityTraceEventListener}. */ - static ObservabilityTraceEventListener getOrCreateInstance(String name, + static ObservabilityTraceEventListener getOrCreateInstance(String uniqueIdentifier, ObservabilityConfigurationType configurationType) { - return INSTANCES.computeIfAbsent(name, n -> new ObservabilityTraceEventListener(n, configurationType)); + return INSTANCES.computeIfAbsent(uniqueIdentifier, n -> new ObservabilityTraceEventListener(n, configurationType)); } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java index af4f6f53..26b726a7 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerProvider.java @@ -37,13 +37,9 @@ */ package oracle.jdbc.provider.observability; -import java.lang.management.ManagementFactory; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.logging.Logger; - -import javax.management.MBeanServer; import oracle.jdbc.TraceEventListener; import oracle.jdbc.provider.observability.ObservabilityConfiguration.ObservabilityConfigurationType; @@ -63,13 +59,13 @@ public class ObservabilityTraceEventListenerProvider implements TraceEventListen /** * Name Parameter name, identifies the listener */ - private static final String NAME_PARAMETER_NAME = "NAME"; + private static final String UNIQUE_IDENTIFIER_PARAMETER_NAME = "UNIQUE_IDENTIFIER"; /** - * Name Parameter, identifies the listener + * Unique identifier, identifies a {@link ObservabilityTraceEventListener}. */ - protected static final Parameter nameParameter = new Parameter() { + protected static final Parameter uniqueIdentifierParameter = new Parameter() { @Override public boolean isSensitive() { @@ -78,26 +74,25 @@ public boolean isSensitive() { @Override public String name() { - return NAME_PARAMETER_NAME; + return UNIQUE_IDENTIFIER_PARAMETER_NAME; } }; - - + /** * Constructs a new instance of ObservabilityTraceEventListenerProvider. This * constructor will be called by the driver's service provider to create a new * instance. */ - public ObservabilityTraceEventListenerProvider() { - - - } - + public ObservabilityTraceEventListenerProvider() { } + @Override public TraceEventListener getTraceEventListener(Map map) { - String name = map.get(nameParameter).toString(); - return ObservabilityTraceEventListener.getOrCreateInstance(name, ObservabilityConfigurationType.OBSERVABILITY); + String uniqueIdentifier = + map.getOrDefault( + uniqueIdentifierParameter, + (CharSequence)ObservabilityTraceEventListener.DEFAULT_UNIQUE_IDENTIFIER).toString(); + return ObservabilityTraceEventListener.getOrCreateInstance(uniqueIdentifier, ObservabilityConfigurationType.OBSERVABILITY); } @Override @@ -107,7 +102,7 @@ public String getName() { @Override public Collection getParameters() { - return Collections.singletonList(nameParameter); + return Collections.singletonList(uniqueIdentifierParameter); } } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java index 3e3d3369..b815bcea 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/OpenTelemetryTraceEventListenerProvider.java @@ -70,8 +70,8 @@ public String getName() { @Override public TraceEventListener getTraceEventListener(Map map) { - String name = map.get(nameParameter).toString(); - return ObservabilityTraceEventListener.getOrCreateInstance(name, + String uniqueIdentifier = map.get(uniqueIdentifierParameter).toString(); + return ObservabilityTraceEventListener.getOrCreateInstance(uniqueIdentifier, ObservabilityConfigurationType.OTEL); } diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java index 814c4e99..2c195506 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/jfr/JFRTracer.java @@ -37,6 +37,9 @@ */ package oracle.jdbc.provider.observability.tracers.jfr; +import java.util.logging.Level; +import java.util.logging.Logger; + import jdk.jfr.Event; import oracle.jdbc.TraceEventListener.JdbcExecutionEvent; import oracle.jdbc.TraceEventListener.Sequence; @@ -55,6 +58,11 @@ public class JFRTracer implements ObservabilityTracer{ */ private final ObservabilityConfiguration configuration; + /** + * Logger. + */ + private static Logger logger = Logger.getLogger(JFRTracer.class.getPackageName()); + /** * Creates a new instance. * @@ -83,9 +91,12 @@ public Object traceRoundTrip(Sequence sequence, TraceContext traceContext, Objec event.setValues(traceContext, configuration); // stop the measuring event durating and commit event.commit(); + } else { + logger.log(Level.WARNING, "Unknown or null user context received from the driver on " + + "database operation: " + traceContext.databaseOperation()); } + return null; } - return null; } @Override diff --git a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java index f4dd8eb8..f922004f 100644 --- a/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java +++ b/ojdbc-provider-observability/src/main/java/oracle/jdbc/provider/observability/tracers/otel/OTelTracer.java @@ -89,7 +89,7 @@ public class OTelTracer implements ObservabilityTracer { /** * Logger. */ - private static Logger logger = Logger.getLogger(OTelTracer.class.getName()); + private static Logger logger = Logger.getLogger(OTelTracer.class.getPackageName()); /** * Configuraiton @@ -123,12 +123,14 @@ public Object traceRoundTrip(Sequence sequence, TraceContext traceContext, Objec return span; } else { // End the Span after the round-trip. - if (userContext instanceof Span) { + if (userContext != null) { final Span span = (Span) userContext; span.setStatus(traceContext.isCompletedExceptionally() ? StatusCode.ERROR : StatusCode.OK); span.end(); + } else { + logger.log(Level.WARNING, "Unknown or null user context received from the driver on " + + "database operation: " + traceContext.databaseOperation()); } - logger.log(Level.WARNING, "Unknown or null user context received from the driver."); return null; } } @@ -195,7 +197,6 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { .setAttribute("thread.name", Thread.currentThread().getName()) .setAttribute("Connection ID", traceContext.getConnectionId()) .setAttribute("Database Operation", traceContext.databaseOperation()) - .setAttribute("Database User", traceContext.user()) .setAttribute("Database Tenant", traceContext.tenant()) .setAttribute("SQL ID", traceContext.getSqlId()); @@ -203,6 +204,7 @@ private Span initAndGetSpan(TraceContext traceContext, String spanName) { if (configuration.getSensitiveDataEnabled()) { logger.log(Level.FINEST, "Sensitive information on"); spanBuilder + .setAttribute("Database User", traceContext.user()) .setAttribute("Original SQL Text", traceContext.originalSqlText()) .setAttribute("Actual SQL Text", traceContext.actualSqlText()); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java index ca3f32cc..81e4e7f9 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/BackwardCompatibilityTest.java @@ -68,8 +68,7 @@ public void testConfiguration() throws Exception { parameters.put(parameter, (CharSequence)INSTANCE_NAME); }); ObservabilityTraceEventListener listener = (ObservabilityTraceEventListener)provider.getTraceEventListener(parameters); - - ObservabilityConfiguration configuration = ObservabilityTraceEventListener.getObservabilityConfiguration(INSTANCE_NAME); + ObservabilityConfiguration configuration = listener.getObservabilityConfiguration(); assertEquals(true, configuration.getEnabled()); assertEquals("OTEL", configuration.getEnabledTracers()); @@ -79,7 +78,7 @@ public void testConfiguration() throws Exception { assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); // MBean - ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); + ObjectName objectName = listener.getMBeanObjectName(); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); String enabled = server.getAttribute(objectName, "Enabled").toString(); String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java index 8c5904de..df8e2ab6 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityConfigurationTest.java @@ -54,7 +54,9 @@ public class ObservabilityConfigurationTest { - private static final String INSTANCE_NAME = "configuration-test-instance"; + private static final String INSTANCE_NAME = "configuration-single"; + private static final String INSTANCE_NAME_1 = "configuration-test-one"; + private static final String INSTANCE_NAME_2 = "configuration-test-two"; MBeanServer server = ManagementFactory.getPlatformMBeanServer(); @@ -69,52 +71,132 @@ public void testConfiguration() throws Exception { // Create a TraceEventListner named test-instance TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); - Map parameters = new HashMap<>(); - provider.getParameters().forEach(parameter -> { - parameters.put(parameter, (CharSequence)INSTANCE_NAME); - }); - ObservabilityTraceEventListener listener = (ObservabilityTraceEventListener)provider.getTraceEventListener(parameters); + ObservabilityTraceEventListener listener = createTraceEventListener(provider, INSTANCE_NAME); // Get the configuration object - ObservabilityConfiguration configuration = ObservabilityTraceEventListener.getObservabilityConfiguration(INSTANCE_NAME); + ObservabilityConfiguration configuration = listener.getObservabilityConfiguration(); - // Verify that the configuration matches the configuration set using system properties - assertEquals("JFR", configuration.getEnabledTracers()); - assertEquals(true, configuration.getSensitiveDataEnabled()); - assertEquals(1, configuration.getEnabledTracersAsList().size()); - assertEquals("JFR", configuration.getEnabledTracersAsList().get(0)); + // Verify that listener one is configured with values from system properties + verifyConfiguration(configuration, listener.getMBeanObjectName(), "JFR", 1, true); - // Get the MBean for the configuration - ObjectName objectName = new ObjectName(listener.getMBeanObjectName()); + // Update configuration using MBean + server.setAttribute(listener.getMBeanObjectName(), new Attribute("EnabledTracers", "OTEL, JFR")); + server.setAttribute(listener.getMBeanObjectName(), new Attribute("SensitiveDataEnabled", false)); - // Get configuration using MBean and check that it matches the configuration set using system properties - String enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); - String sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - assertEquals(enabledTracers, "JFR"); - assertEquals(sensitiveDataEnabled, "true"); + // check that the values have been updated using the instance of the configuration + verifyConfiguration(configuration, listener.getMBeanObjectName(), "OTEL,JFR", 2, false); + + // Update the configuration using the instance of the configuration + configuration.setEnabledTracers("OTEL"); + configuration.setSensitiveDataEnabled(true); + + // Check that the values returned by the MBean correspond to the values set using the instance + verifyConfiguration(configuration, listener.getMBeanObjectName(), "OTEL", 1, true); + + } + + @Test + public void testConfigurationWith2Instances() throws Exception { + + // Create a TraceEventListner named test-instance + TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); + ObservabilityTraceEventListener listener1 = createTraceEventListener(provider, INSTANCE_NAME_1); + ObservabilityTraceEventListener listener2 = createTraceEventListener(provider, INSTANCE_NAME_2); + + // Verify that listener one is configured with values from system properties + verifyConfiguration(listener1.getObservabilityConfiguration(), + listener1.getMBeanObjectName(), "JFR", 1, true); + + // Verify that listener two is configured with values from system properties + verifyConfiguration(listener2.getObservabilityConfiguration(), + listener2.getMBeanObjectName(), "JFR", 1, true); + + // Update configuration one using MBean + server.setAttribute(listener1.getMBeanObjectName(), new Attribute("EnabledTracers", "OTEL,JFR")); + server.setAttribute(listener1.getMBeanObjectName(), new Attribute("SensitiveDataEnabled", false)); + + // Verify that listener one's configuration with the values set using the MBean + verifyConfiguration(listener1.getObservabilityConfiguration(), + listener1.getMBeanObjectName(), "OTEL,JFR", 2, false); + + // Verify that listener two's configuration did not change + verifyConfiguration(listener2.getObservabilityConfiguration(), + listener2.getMBeanObjectName(), "JFR", 1, true); + + // Update the configuration using the instance of the configuration + ObservabilityConfiguration configuration2 = listener2.getObservabilityConfiguration(); + configuration2.setEnabledTracers("OTEL"); + configuration2.setSensitiveDataEnabled(false); + + // Verify that listener one's configuration did not change + verifyConfiguration(listener1.getObservabilityConfiguration(), + listener1.getMBeanObjectName(), "OTEL,JFR", 2, false); + + // Verify that listener two's configuration has been updated + verifyConfiguration(listener2.getObservabilityConfiguration(), + listener2.getMBeanObjectName(), "OTEL", 1, false); + + } + + @Test + public void testDefaultUniqueIdentifier() throws Exception { + + // Create a TraceEventListner named test-instance + TraceEventListenerProvider provider = new ObservabilityTraceEventListenerProvider(); + ObservabilityTraceEventListener listener = (ObservabilityTraceEventListener)provider.getTraceEventListener(new HashMap<>()); + + // Get the configuration object + ObservabilityConfiguration configuration = listener.getObservabilityConfiguration(); + + // Verify that listener one is configured with values from system properties + verifyConfiguration(configuration, listener.getMBeanObjectName(), "JFR", 1, true); // Update configuration using MBean - server.setAttribute(objectName, new Attribute("EnabledTracers", "OTEL,JFR")); - server.setAttribute(objectName, new Attribute("SensitiveDataEnabled", false)); + server.setAttribute(listener.getMBeanObjectName(), new Attribute("EnabledTracers", "OTEL, JFR")); + server.setAttribute(listener.getMBeanObjectName(), new Attribute("SensitiveDataEnabled", false)); // check that the values have been updated using the instance of the configuration - assertEquals("OTEL,JFR", configuration.getEnabledTracers()); - assertEquals(false, configuration.getSensitiveDataEnabled()); - assertEquals(2, configuration.getEnabledTracersAsList().size()); - assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); - assertEquals("JFR", configuration.getEnabledTracersAsList().get(1)); + verifyConfiguration(configuration, listener.getMBeanObjectName(), "OTEL,JFR", 2, false); // Update the configuration using the instance of the configuration configuration.setEnabledTracers("OTEL"); configuration.setSensitiveDataEnabled(true); // Check that the values returned by the MBean correspond to the values set using the instance - enabledTracers = server.getAttribute(objectName, "EnabledTracers").toString(); - sensitiveDataEnabled = server.getAttribute(objectName, "SensitiveDataEnabled").toString(); - assertEquals("OTEL", enabledTracers); - assertEquals("true", sensitiveDataEnabled); - assertEquals(1, configuration.getEnabledTracersAsList().size()); - assertEquals("OTEL", configuration.getEnabledTracersAsList().get(0)); + verifyConfiguration(configuration, listener.getMBeanObjectName(), "OTEL", 1, true); + + } + + private ObservabilityTraceEventListener createTraceEventListener(TraceEventListenerProvider provider, + String instanceName) { + Map parameters = new HashMap<>(); + provider.getParameters().forEach(parameter -> { + parameters.put(parameter, (CharSequence)instanceName); + }); + return (ObservabilityTraceEventListener)provider.getTraceEventListener(parameters); + } + + private void verifyConfiguration(ObservabilityConfiguration configuration, + ObjectName mBeanObjectName, + String expectedTracers, + int expectedTracerCount, + boolean expectedSensitiveDataEnabled) throws Exception{ + + String[] expectedTracersArray = expectedTracers.split(","); + // Verify that the configuration matches the configuration set using system properties + assertEquals(expectedTracers, configuration.getEnabledTracers()); + assertEquals(expectedSensitiveDataEnabled, configuration.getSensitiveDataEnabled()); + assertEquals(expectedTracerCount, configuration.getEnabledTracersAsList().size()); + assertEquals(expectedTracerCount, expectedTracersArray.length, "Wrong number of tracers."); + for (int i = 0; i < expectedTracerCount; i++) { + assertEquals(expectedTracersArray[i], configuration.getEnabledTracersAsList().get(i)); + } + + // Get configuration using MBean and check that it matches the configuration set using system properties + String enabledTracers = server.getAttribute(mBeanObjectName, "EnabledTracers").toString(); + String sensitiveDataEnabled = server.getAttribute(mBeanObjectName, "SensitiveDataEnabled").toString(); + assertEquals(enabledTracers, expectedTracers); + assertEquals(Boolean.parseBoolean(sensitiveDataEnabled), expectedSensitiveDataEnabled); } diff --git a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java index 74b4a592..52432893 100644 --- a/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java +++ b/ojdbc-provider-observability/src/test/java/oracle/jdbc/provider/observability/ObservabilityTraceEventListenerTest.java @@ -111,7 +111,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { String connectionId = null; try (Recording recording = new Recording(configuration)) { recording.start(); - String jfrUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.name=test-jfr" + sensitiveDataEnabled; + String jfrUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.unique_identifier=test-jfr" + sensitiveDataEnabled; try (Connection connection = DriverManager.getConnection(jfrUrl, userName, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT 'OK' FROM DUAL")) { @@ -122,7 +122,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { } recording.stop(); recording.dump(Path.of("dump" + sensitiveDataEnabled + ".jfr")); - + try (RecordingFile recordingFile = new RecordingFile(Path.of("dump" + sensitiveDataEnabled + ".jfr"))) { int countRoundTrips = 0; while (recordingFile.hasMoreEvents()) { @@ -171,7 +171,7 @@ public void JFRTraceTest(boolean sensitiveDataEnabled) throws Exception { assertTrue(countRoundTrips > 0, "Application should have performed at least one round trip"); } } - + } @ParameterizedTest(name = "OTELTraceTest - {arguments}") @@ -180,7 +180,7 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.clearInvocations(tracer, spanBuilder); System.setProperty("oracle.jdbc.provider.observability.enabledTracers", "OTEL"); System.setProperty("oracle.jdbc.provider.observability.sensitiveDataEnabled", String.valueOf(sensitiveDataEnabled)); - String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.name=test-otel-" + sensitiveDataEnabled ; + String otelUrl = url + "?oracle.jdbc.provider.traceEventListener=observability-trace-event-listener-provider&oracle.jdbc.provider.traceEventListener.unique_identifier=test-otel-" + sensitiveDataEnabled ; String connectionId = null; try (Connection connection = DriverManager.getConnection(otelUrl, userName, password); Statement statement = connection.createStatement(); @@ -207,10 +207,13 @@ public void OTELTraceTest(boolean sensitiveDataEnabled) throws Exception { Mockito.verify(spanBuilder, Mockito.times(4)).setAttribute("Database User", userName); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Original SQL Text", "SELECT 'OK' FROM DUAL"); Mockito.verify(spanBuilder, Mockito.times(1)).setAttribute("Actual SQL Text", "SELECT 'OK' FROM DUAL"); + } else { + Mockito.verify(spanBuilder, Mockito.times(0)).setAttribute("Database User", userName); + Mockito.verify(spanBuilder, Mockito.times(0)).setAttribute("Original SQL Text", "SELECT 'OK' FROM DUAL"); + Mockito.verify(spanBuilder, Mockito.times(0)).setAttribute("Actual SQL Text", "SELECT 'OK' FROM DUAL"); } Mockito.verify(span, atLeast(4)).end(); - } private static void configureOTEL() { diff --git a/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java b/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java index ddd1a7d4..4c63944d 100644 --- a/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java +++ b/ojdbc-provider-opentelemetry/src/main/java/oracle/jdbc/provider/opentelemetry/OpenTelemetryTraceEventListener.java @@ -107,7 +107,7 @@ public class OpenTelemetryTraceEventListener } }; - private static Logger logger = Logger.getLogger(OpenTelemetryTraceEventListener.class.getName()); + private static Logger logger = Logger.getLogger(OpenTelemetryTraceEventListener.class.getPackageName()); private Tracer tracer; From dd9de05c36854c47dbc07096069738848c223dff Mon Sep 17 00:00:00 2001 From: Fernanda Meheust Date: Mon, 10 Mar 2025 11:48:04 +0100 Subject: [PATCH 25/25] Corrected copyright --- ojdbc-provider-observability/example-test.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ojdbc-provider-observability/example-test.properties b/ojdbc-provider-observability/example-test.properties index feafff3b..85a2cb3e 100644 --- a/ojdbc-provider-observability/example-test.properties +++ b/ojdbc-provider-observability/example-test.properties @@ -1,5 +1,5 @@ ################################################################################ -# Copyright (c) 2024 Oracle and/or its affiliates. +# Copyright (c) 2025 Oracle and/or its affiliates. # # The Universal Permissive License (UPL), Version 1.0 #