Use metrics batch API in connection pool instrumentations (#6231)
* Use metrics batch API in connection pool instrumentations * Fix vibur muzzle * Fix vibur muzzle
This commit is contained in:
parent
814985e620
commit
afee828846
|
@ -10,13 +10,14 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
|||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.DoubleHistogram;
|
||||
import io.opentelemetry.api.metrics.LongCounter;
|
||||
import io.opentelemetry.api.metrics.Meter;
|
||||
import io.opentelemetry.api.metrics.MeterBuilder;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.api.metrics.ObservableMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
/**
|
||||
* A helper class that models the <a
|
||||
|
@ -54,64 +55,53 @@ public final class DbConnectionPoolMetrics {
|
|||
idleConnectionsAttributes = attributes.toBuilder().put(CONNECTION_STATE, STATE_IDLE).build();
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter usedConnections(LongSupplier usedConnectionsGetter) {
|
||||
public ObservableLongMeasurement connections() {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.usage")
|
||||
.setUnit("connections")
|
||||
.setDescription(
|
||||
"The number of connections that are currently in state described by the state attribute.")
|
||||
.buildWithCallback(
|
||||
measurement ->
|
||||
measurement.record(usedConnectionsGetter.getAsLong(), usedConnectionsAttributes));
|
||||
.buildObserver();
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter idleConnections(LongSupplier idleConnectionsGetter) {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.usage")
|
||||
.setUnit("connections")
|
||||
.setDescription(
|
||||
"The number of connections that are currently in state described by the state attribute.")
|
||||
.buildWithCallback(
|
||||
measurement ->
|
||||
measurement.record(idleConnectionsGetter.getAsLong(), idleConnectionsAttributes));
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter minIdleConnections(LongSupplier minIdleConnectionsGetter) {
|
||||
public ObservableLongMeasurement minIdleConnections() {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.idle.min")
|
||||
.setUnit("connections")
|
||||
.setDescription("The minimum number of idle open connections allowed.")
|
||||
.buildWithCallback(
|
||||
measurement -> measurement.record(minIdleConnectionsGetter.getAsLong(), attributes));
|
||||
.buildObserver();
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter maxIdleConnections(LongSupplier maxIdleConnectionsGetter) {
|
||||
public ObservableLongMeasurement maxIdleConnections() {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.idle.max")
|
||||
.setUnit("connections")
|
||||
.setDescription("The maximum number of idle open connections allowed.")
|
||||
.buildWithCallback(
|
||||
measurement -> measurement.record(maxIdleConnectionsGetter.getAsLong(), attributes));
|
||||
.buildObserver();
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter maxConnections(LongSupplier maxConnectionsGetter) {
|
||||
public ObservableLongMeasurement maxConnections() {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.max")
|
||||
.setUnit("connections")
|
||||
.setDescription("The maximum number of open connections allowed.")
|
||||
.buildWithCallback(
|
||||
measurement -> measurement.record(maxConnectionsGetter.getAsLong(), attributes));
|
||||
.buildObserver();
|
||||
}
|
||||
|
||||
public ObservableLongUpDownCounter pendingRequestsForConnection(
|
||||
LongSupplier pendingRequestsGetter) {
|
||||
public ObservableLongMeasurement pendingRequestsForConnection() {
|
||||
return meter
|
||||
.upDownCounterBuilder("db.client.connections.pending_requests")
|
||||
.setUnit("requests")
|
||||
.setDescription(
|
||||
"The number of pending requests for an open connection, cumulative for the entire pool.")
|
||||
.buildWithCallback(
|
||||
measurement -> measurement.record(pendingRequestsGetter.getAsLong(), attributes));
|
||||
.buildObserver();
|
||||
}
|
||||
|
||||
public BatchCallback batchCallback(
|
||||
Runnable callback,
|
||||
ObservableMeasurement observableMeasurement,
|
||||
ObservableMeasurement... additionalMeasurements) {
|
||||
return meter.batchCallback(callback, observableMeasurement, additionalMeasurements);
|
||||
}
|
||||
|
||||
// TODO: should be a BoundLongCounter
|
||||
|
@ -151,8 +141,15 @@ public final class DbConnectionPoolMetrics {
|
|||
.build();
|
||||
}
|
||||
|
||||
// TODO: should be removed once bound instruments are back
|
||||
public Attributes getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public Attributes getUsedConnectionsAttributes() {
|
||||
return usedConnectionsAttributes;
|
||||
}
|
||||
|
||||
public Attributes getIdleConnectionsAttributes() {
|
||||
return idleConnectionsAttributes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
package io.opentelemetry.instrumentation.apachedbcp;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.apache.commons.dbcp2.BasicDataSourceMXBean;
|
||||
|
@ -20,31 +20,44 @@ final class DataSourceMetrics {
|
|||
// a weak map does not make sense here because each Meter holds a reference to the dataSource
|
||||
// all instrumented/known implementations of BasicDataSourceMXBean do not implement
|
||||
// equals()/hashCode(), so it's safe to keep them in a plain ConcurrentHashMap
|
||||
private static final Map<BasicDataSourceMXBean, List<ObservableLongUpDownCounter>>
|
||||
dataSourceMetrics = new ConcurrentHashMap<>();
|
||||
private static final Map<BasicDataSourceMXBean, BatchCallback> dataSourceMetrics =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerMetrics(
|
||||
OpenTelemetry openTelemetry, BasicDataSourceMXBean dataSource, String dataSourceName) {
|
||||
DbConnectionPoolMetrics metrics =
|
||||
DbConnectionPoolMetrics.create(openTelemetry, INSTRUMENTATION_NAME, dataSourceName);
|
||||
|
||||
List<ObservableLongUpDownCounter> meters =
|
||||
Arrays.asList(
|
||||
metrics.usedConnections(dataSource::getNumActive),
|
||||
metrics.idleConnections(dataSource::getNumIdle),
|
||||
metrics.minIdleConnections(dataSource::getMinIdle),
|
||||
metrics.maxIdleConnections(dataSource::getMaxIdle),
|
||||
metrics.maxConnections(dataSource::getMaxTotal));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement minIdleConnections = metrics.minIdleConnections();
|
||||
ObservableLongMeasurement maxIdleConnections = metrics.maxIdleConnections();
|
||||
ObservableLongMeasurement maxConnections = metrics.maxConnections();
|
||||
|
||||
dataSourceMetrics.put(dataSource, meters);
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
BatchCallback callback =
|
||||
metrics.batchCallback(
|
||||
() -> {
|
||||
connections.record(dataSource.getNumActive(), usedConnectionsAttributes);
|
||||
connections.record(dataSource.getNumIdle(), idleConnectionsAttributes);
|
||||
minIdleConnections.record(dataSource.getMinIdle(), attributes);
|
||||
maxIdleConnections.record(dataSource.getMaxIdle(), attributes);
|
||||
maxConnections.record(dataSource.getMaxTotal(), attributes);
|
||||
},
|
||||
connections,
|
||||
minIdleConnections,
|
||||
maxIdleConnections,
|
||||
maxConnections);
|
||||
|
||||
dataSourceMetrics.put(dataSource, callback);
|
||||
}
|
||||
|
||||
public static void unregisterMetrics(BasicDataSourceMXBean dataSource) {
|
||||
List<ObservableLongUpDownCounter> observableInstruments = dataSourceMetrics.remove(dataSource);
|
||||
if (observableInstruments != null) {
|
||||
for (ObservableLongUpDownCounter observable : observableInstruments) {
|
||||
observable.close();
|
||||
}
|
||||
BatchCallback callback = dataSourceMetrics.remove(dataSource);
|
||||
if (callback != null) {
|
||||
callback.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,38 +7,42 @@ package io.opentelemetry.instrumentation.c3p0;
|
|||
|
||||
import com.mchange.v2.c3p0.PooledDataSource;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class ConnectionPoolMetrics {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ConnectionPoolMetrics.class.getName());
|
||||
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.c3p0-0.9";
|
||||
|
||||
// a weak map does not make sense here because each Meter holds a reference to the dataSource
|
||||
// PooledDataSource implements equals() & hashCode() in IdentityTokenResolvable,
|
||||
// that's why we wrap it with IdentityDataSourceKey that uses identity comparison instead
|
||||
private static final Map<IdentityDataSourceKey, List<ObservableLongUpDownCounter>>
|
||||
dataSourceMetrics = new ConcurrentHashMap<>();
|
||||
private static final Map<IdentityDataSourceKey, BatchCallback> dataSourceMetrics =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerMetrics(OpenTelemetry openTelemetry, PooledDataSource dataSource) {
|
||||
dataSourceMetrics.compute(
|
||||
new IdentityDataSourceKey(dataSource),
|
||||
(key, existingCounters) ->
|
||||
ConnectionPoolMetrics.createMeters(openTelemetry, key, existingCounters));
|
||||
(key, existingCallback) ->
|
||||
ConnectionPoolMetrics.createMeters(openTelemetry, key, existingCallback));
|
||||
}
|
||||
|
||||
private static List<ObservableLongUpDownCounter> createMeters(
|
||||
private static BatchCallback createMeters(
|
||||
OpenTelemetry openTelemetry,
|
||||
IdentityDataSourceKey key,
|
||||
List<ObservableLongUpDownCounter> existingCounters) {
|
||||
@Nullable BatchCallback existingCallback) {
|
||||
// remove old counters from the registry in case they were already there
|
||||
removeMetersFromRegistry(existingCounters);
|
||||
removeMetersFromRegistry(existingCallback);
|
||||
|
||||
PooledDataSource dataSource = key.dataSource;
|
||||
|
||||
|
@ -46,25 +50,38 @@ final class ConnectionPoolMetrics {
|
|||
DbConnectionPoolMetrics.create(
|
||||
openTelemetry, INSTRUMENTATION_NAME, dataSource.getDataSourceName());
|
||||
|
||||
return Arrays.asList(
|
||||
metrics.usedConnections(wrapThrowingSupplier(dataSource::getNumBusyConnectionsDefaultUser)),
|
||||
metrics.idleConnections(wrapThrowingSupplier(dataSource::getNumIdleConnectionsDefaultUser)),
|
||||
metrics.pendingRequestsForConnection(
|
||||
wrapThrowingSupplier(dataSource::getNumThreadsAwaitingCheckoutDefaultUser)));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement pendingRequestsForConnection = metrics.pendingRequestsForConnection();
|
||||
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
return metrics.batchCallback(
|
||||
() -> {
|
||||
try {
|
||||
connections.record(
|
||||
dataSource.getNumBusyConnectionsDefaultUser(), usedConnectionsAttributes);
|
||||
connections.record(
|
||||
dataSource.getNumIdleConnectionsDefaultUser(), idleConnectionsAttributes);
|
||||
pendingRequestsForConnection.record(
|
||||
dataSource.getNumThreadsAwaitingCheckoutDefaultUser(), attributes);
|
||||
} catch (SQLException e) {
|
||||
logger.log(Level.FINE, "Failed to get C3P0 datasource metric", e);
|
||||
}
|
||||
},
|
||||
connections,
|
||||
pendingRequestsForConnection);
|
||||
}
|
||||
|
||||
public static void unregisterMetrics(PooledDataSource dataSource) {
|
||||
List<ObservableLongUpDownCounter> meters =
|
||||
dataSourceMetrics.remove(new IdentityDataSourceKey(dataSource));
|
||||
removeMetersFromRegistry(meters);
|
||||
BatchCallback callback = dataSourceMetrics.remove(new IdentityDataSourceKey(dataSource));
|
||||
removeMetersFromRegistry(callback);
|
||||
}
|
||||
|
||||
private static void removeMetersFromRegistry(
|
||||
@Nullable List<ObservableLongUpDownCounter> observableInstruments) {
|
||||
if (observableInstruments != null) {
|
||||
for (ObservableLongUpDownCounter observable : observableInstruments) {
|
||||
observable.close();
|
||||
}
|
||||
private static void removeMetersFromRegistry(@Nullable BatchCallback callback) {
|
||||
if (callback != null) {
|
||||
callback.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,20 +120,5 @@ final class ConnectionPoolMetrics {
|
|||
}
|
||||
}
|
||||
|
||||
static LongSupplier wrapThrowingSupplier(DataSourceIntSupplier supplier) {
|
||||
return () -> {
|
||||
try {
|
||||
return supplier.getAsInt();
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException("Failed to get C3P0 datasource metric", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface DataSourceIntSupplier {
|
||||
int getAsInt() throws SQLException;
|
||||
}
|
||||
|
||||
private ConnectionPoolMetrics() {}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@ package io.opentelemetry.instrumentation.hikaricp;
|
|||
|
||||
import com.zaxxer.hikari.metrics.IMetricsTracker;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.DoubleHistogram;
|
||||
import io.opentelemetry.api.metrics.LongCounter;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
final class OpenTelemetryMetricsTracker implements IMetricsTracker {
|
||||
|
@ -19,7 +18,7 @@ final class OpenTelemetryMetricsTracker implements IMetricsTracker {
|
|||
|
||||
private final IMetricsTracker userMetricsTracker;
|
||||
|
||||
private final List<ObservableLongUpDownCounter> observableInstruments;
|
||||
private final BatchCallback callback;
|
||||
private final LongCounter timeouts;
|
||||
private final DoubleHistogram createTime;
|
||||
private final DoubleHistogram waitTime;
|
||||
|
@ -28,14 +27,14 @@ final class OpenTelemetryMetricsTracker implements IMetricsTracker {
|
|||
|
||||
OpenTelemetryMetricsTracker(
|
||||
IMetricsTracker userMetricsTracker,
|
||||
List<ObservableLongUpDownCounter> observableInstruments,
|
||||
BatchCallback callback,
|
||||
LongCounter timeouts,
|
||||
DoubleHistogram createTime,
|
||||
DoubleHistogram waitTime,
|
||||
DoubleHistogram useTime,
|
||||
Attributes attributes) {
|
||||
this.userMetricsTracker = userMetricsTracker;
|
||||
this.observableInstruments = observableInstruments;
|
||||
this.callback = callback;
|
||||
this.timeouts = timeouts;
|
||||
this.createTime = createTime;
|
||||
this.waitTime = waitTime;
|
||||
|
@ -70,9 +69,7 @@ final class OpenTelemetryMetricsTracker implements IMetricsTracker {
|
|||
|
||||
@Override
|
||||
public void close() {
|
||||
for (ObservableLongUpDownCounter observable : observableInstruments) {
|
||||
observable.close();
|
||||
}
|
||||
callback.close();
|
||||
userMetricsTracker.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ import com.zaxxer.hikari.metrics.IMetricsTracker;
|
|||
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
|
||||
import com.zaxxer.hikari.metrics.PoolStats;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class OpenTelemetryMetricsTrackerFactory implements MetricsTrackerFactory {
|
||||
|
@ -38,17 +38,32 @@ final class OpenTelemetryMetricsTrackerFactory implements MetricsTrackerFactory
|
|||
DbConnectionPoolMetrics metrics =
|
||||
DbConnectionPoolMetrics.create(openTelemetry, INSTRUMENTATION_NAME, poolName);
|
||||
|
||||
List<ObservableLongUpDownCounter> observableInstruments =
|
||||
Arrays.asList(
|
||||
metrics.usedConnections(poolStats::getActiveConnections),
|
||||
metrics.idleConnections(poolStats::getIdleConnections),
|
||||
metrics.minIdleConnections(poolStats::getMinConnections),
|
||||
metrics.maxConnections(poolStats::getMaxConnections),
|
||||
metrics.pendingRequestsForConnection(poolStats::getPendingThreads));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement minIdleConnections = metrics.minIdleConnections();
|
||||
ObservableLongMeasurement maxConnections = metrics.maxConnections();
|
||||
ObservableLongMeasurement pendingRequestsForConnection = metrics.pendingRequestsForConnection();
|
||||
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
BatchCallback callback =
|
||||
metrics.batchCallback(
|
||||
() -> {
|
||||
connections.record(poolStats.getActiveConnections(), usedConnectionsAttributes);
|
||||
connections.record(poolStats.getIdleConnections(), idleConnectionsAttributes);
|
||||
minIdleConnections.record(poolStats.getMinConnections(), attributes);
|
||||
maxConnections.record(poolStats.getMaxConnections(), attributes);
|
||||
pendingRequestsForConnection.record(poolStats.getPendingThreads(), attributes);
|
||||
},
|
||||
connections,
|
||||
minIdleConnections,
|
||||
maxConnections,
|
||||
pendingRequestsForConnection);
|
||||
|
||||
return new OpenTelemetryMetricsTracker(
|
||||
userMetricsTracker,
|
||||
observableInstruments,
|
||||
callback,
|
||||
metrics.connectionTimeouts(),
|
||||
metrics.connectionCreateTime(),
|
||||
metrics.connectionWaitTime(),
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
package io.opentelemetry.instrumentation.oracleucp;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import oracle.ucp.UniversalConnectionPool;
|
||||
|
@ -20,8 +20,8 @@ final class ConnectionPoolMetrics {
|
|||
// a weak map does not make sense here because each Meter holds a reference to the connection pool
|
||||
// none of the UniversalConnectionPool implementations contain equals()/hashCode(), so it's safe
|
||||
// to keep them in a plain ConcurrentHashMap
|
||||
private static final Map<UniversalConnectionPool, List<ObservableLongUpDownCounter>>
|
||||
dataSourceMetrics = new ConcurrentHashMap<>();
|
||||
private static final Map<UniversalConnectionPool, BatchCallback> dataSourceMetrics =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerMetrics(
|
||||
OpenTelemetry openTelemetry, UniversalConnectionPool connectionPool) {
|
||||
|
@ -29,27 +29,40 @@ final class ConnectionPoolMetrics {
|
|||
connectionPool, (unused) -> createMeters(openTelemetry, connectionPool));
|
||||
}
|
||||
|
||||
private static List<ObservableLongUpDownCounter> createMeters(
|
||||
private static BatchCallback createMeters(
|
||||
OpenTelemetry openTelemetry, UniversalConnectionPool connectionPool) {
|
||||
DbConnectionPoolMetrics metrics =
|
||||
DbConnectionPoolMetrics.create(
|
||||
openTelemetry, INSTRUMENTATION_NAME, connectionPool.getName());
|
||||
|
||||
return Arrays.asList(
|
||||
metrics.usedConnections(connectionPool::getBorrowedConnectionsCount),
|
||||
metrics.idleConnections(connectionPool::getAvailableConnectionsCount),
|
||||
metrics.maxConnections(() -> connectionPool.getStatistics().getPeakConnectionsCount()),
|
||||
metrics.pendingRequestsForConnection(
|
||||
() -> connectionPool.getStatistics().getPendingRequestsCount()));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement maxConnections = metrics.maxConnections();
|
||||
ObservableLongMeasurement pendingRequestsForConnection = metrics.pendingRequestsForConnection();
|
||||
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
return metrics.batchCallback(
|
||||
() -> {
|
||||
connections.record(
|
||||
connectionPool.getBorrowedConnectionsCount(), usedConnectionsAttributes);
|
||||
connections.record(
|
||||
connectionPool.getAvailableConnectionsCount(), idleConnectionsAttributes);
|
||||
maxConnections.record(
|
||||
connectionPool.getStatistics().getPeakConnectionsCount(), attributes);
|
||||
pendingRequestsForConnection.record(
|
||||
connectionPool.getStatistics().getPendingRequestsCount(), attributes);
|
||||
},
|
||||
connections,
|
||||
maxConnections,
|
||||
pendingRequestsForConnection);
|
||||
}
|
||||
|
||||
public static void unregisterMetrics(UniversalConnectionPool connectionPool) {
|
||||
List<ObservableLongUpDownCounter> observableInstruments =
|
||||
dataSourceMetrics.remove(connectionPool);
|
||||
if (observableInstruments != null) {
|
||||
for (ObservableLongUpDownCounter observable : observableInstruments) {
|
||||
observable.close();
|
||||
}
|
||||
BatchCallback callback = dataSourceMetrics.remove(connectionPool);
|
||||
if (callback != null) {
|
||||
callback.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ package io.opentelemetry.javaagent.instrumentation.tomcat.jdbc;
|
|||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.apache.tomcat.jdbc.pool.DataSourceProxy;
|
||||
|
@ -23,34 +23,48 @@ public final class TomcatConnectionPoolMetrics {
|
|||
// a weak map does not make sense here because each Meter holds a reference to the dataSource
|
||||
// DataSourceProxy does not implement equals()/hashCode(), so it's safe to keep them in a plain
|
||||
// ConcurrentHashMap
|
||||
private static final Map<DataSourceProxy, List<ObservableLongUpDownCounter>> dataSourceMetrics =
|
||||
private static final Map<DataSourceProxy, BatchCallback> dataSourceMetrics =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerMetrics(DataSourceProxy dataSource) {
|
||||
dataSourceMetrics.computeIfAbsent(dataSource, TomcatConnectionPoolMetrics::createCounters);
|
||||
dataSourceMetrics.computeIfAbsent(dataSource, TomcatConnectionPoolMetrics::createInstruments);
|
||||
}
|
||||
|
||||
private static List<ObservableLongUpDownCounter> createCounters(DataSourceProxy dataSource) {
|
||||
|
||||
private static BatchCallback createInstruments(DataSourceProxy dataSource) {
|
||||
DbConnectionPoolMetrics metrics =
|
||||
DbConnectionPoolMetrics.create(
|
||||
openTelemetry, INSTRUMENTATION_NAME, dataSource.getPoolName());
|
||||
|
||||
return Arrays.asList(
|
||||
metrics.usedConnections(dataSource::getActive),
|
||||
metrics.idleConnections(dataSource::getIdle),
|
||||
metrics.minIdleConnections(dataSource::getMinIdle),
|
||||
metrics.maxIdleConnections(dataSource::getMaxIdle),
|
||||
metrics.maxConnections(dataSource::getMaxActive),
|
||||
metrics.pendingRequestsForConnection(dataSource::getWaitCount));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement minIdleConnections = metrics.minIdleConnections();
|
||||
ObservableLongMeasurement maxIdleConnections = metrics.maxIdleConnections();
|
||||
ObservableLongMeasurement maxConnections = metrics.maxConnections();
|
||||
ObservableLongMeasurement pendingRequestsForConnection = metrics.pendingRequestsForConnection();
|
||||
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
return metrics.batchCallback(
|
||||
() -> {
|
||||
connections.record(dataSource.getActive(), usedConnectionsAttributes);
|
||||
connections.record(dataSource.getIdle(), idleConnectionsAttributes);
|
||||
minIdleConnections.record(dataSource.getMinIdle(), attributes);
|
||||
maxIdleConnections.record(dataSource.getMaxIdle(), attributes);
|
||||
maxConnections.record(dataSource.getMaxActive(), attributes);
|
||||
pendingRequestsForConnection.record(dataSource.getWaitCount(), attributes);
|
||||
},
|
||||
connections,
|
||||
minIdleConnections,
|
||||
maxIdleConnections,
|
||||
maxConnections,
|
||||
pendingRequestsForConnection);
|
||||
}
|
||||
|
||||
public static void unregisterMetrics(DataSourceProxy dataSource) {
|
||||
List<ObservableLongUpDownCounter> counters = dataSourceMetrics.remove(dataSource);
|
||||
if (counters != null) {
|
||||
for (ObservableLongUpDownCounter meter : counters) {
|
||||
meter.close();
|
||||
}
|
||||
BatchCallback callback = dataSourceMetrics.remove(dataSource);
|
||||
if (callback != null) {
|
||||
callback.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.viburdbcp;
|
||||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class ViburDbcpInstrumentationModule extends InstrumentationModule {
|
||||
|
@ -18,6 +20,14 @@ public class ViburDbcpInstrumentationModule extends InstrumentationModule {
|
|||
super("vibur-dbcp", "vibur-dbcp-11.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||
// ViburDBCPConfig was renamed to ViburConfig in 10.0; this matcher excludes all versions < 10.0
|
||||
// in 11.0, the ViburDBCPDataSource#getPool() method signature was changed - this is detected by
|
||||
// muzzle
|
||||
return hasClassesNamed("org.vibur.dbcp.ViburConfig");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ViburDbcpDataSourceInstrumentation());
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
package io.opentelemetry.instrumentation.viburdbcp;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.BatchCallback;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.vibur.dbcp.ViburDBCPDataSource;
|
||||
|
@ -20,31 +20,40 @@ final class ConnectionPoolMetrics {
|
|||
// a weak map does not make sense here because each Meter holds a reference to the dataSource
|
||||
// ViburDBCPDataSource does not implement equals()/hashCode(), so it's safe to keep them in a
|
||||
// plain ConcurrentHashMap
|
||||
private static final Map<ViburDBCPDataSource, List<ObservableLongUpDownCounter>>
|
||||
dataSourceMetrics = new ConcurrentHashMap<>();
|
||||
private static final Map<ViburDBCPDataSource, BatchCallback> dataSourceMetrics =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerMetrics(OpenTelemetry openTelemetry, ViburDBCPDataSource dataSource) {
|
||||
dataSourceMetrics.computeIfAbsent(
|
||||
dataSource, (unused) -> createMeters(openTelemetry, dataSource));
|
||||
}
|
||||
|
||||
private static List<ObservableLongUpDownCounter> createMeters(
|
||||
private static BatchCallback createMeters(
|
||||
OpenTelemetry openTelemetry, ViburDBCPDataSource dataSource) {
|
||||
DbConnectionPoolMetrics metrics =
|
||||
DbConnectionPoolMetrics.create(openTelemetry, INSTRUMENTATION_NAME, dataSource.getName());
|
||||
|
||||
return Arrays.asList(
|
||||
metrics.usedConnections(() -> dataSource.getPool().taken()),
|
||||
metrics.idleConnections(() -> dataSource.getPool().remainingCreated()),
|
||||
metrics.maxConnections(dataSource::getPoolMaxSize));
|
||||
ObservableLongMeasurement connections = metrics.connections();
|
||||
ObservableLongMeasurement maxConnections = metrics.maxConnections();
|
||||
|
||||
Attributes attributes = metrics.getAttributes();
|
||||
Attributes usedConnectionsAttributes = metrics.getUsedConnectionsAttributes();
|
||||
Attributes idleConnectionsAttributes = metrics.getIdleConnectionsAttributes();
|
||||
|
||||
return metrics.batchCallback(
|
||||
() -> {
|
||||
connections.record(dataSource.getPool().taken(), usedConnectionsAttributes);
|
||||
connections.record(dataSource.getPool().remainingCreated(), idleConnectionsAttributes);
|
||||
maxConnections.record(dataSource.getPoolMaxSize(), attributes);
|
||||
},
|
||||
connections,
|
||||
maxConnections);
|
||||
}
|
||||
|
||||
public static void unregisterMetrics(ViburDBCPDataSource dataSource) {
|
||||
List<ObservableLongUpDownCounter> observableInstruments = dataSourceMetrics.remove(dataSource);
|
||||
if (observableInstruments != null) {
|
||||
for (ObservableLongUpDownCounter observable : observableInstruments) {
|
||||
observable.close();
|
||||
}
|
||||
BatchCallback callback = dataSourceMetrics.remove(dataSource);
|
||||
if (callback != null) {
|
||||
callback.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue