org.slf4j
slf4j-api
diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java
index 7032ad5336..9a027abb07 100644
--- a/driver/src/main/java/org/neo4j/driver/Config.java
+++ b/driver/src/main/java/org/neo4j/driver/Config.java
@@ -36,6 +36,7 @@
import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil;
import org.neo4j.driver.internal.retry.RetrySettings;
import org.neo4j.driver.net.ServerAddressResolver;
+import org.neo4j.driver.util.Experimental;
import org.neo4j.driver.util.Immutable;
import static java.lang.String.format;
@@ -96,9 +97,9 @@ public class Config implements Serializable
private final RetrySettings retrySettings;
private final ServerAddressResolver resolver;
- private final boolean isMetricsEnabled;
private final int eventLoopThreads;
private final String userAgent;
+ private final MetricsAdapter metricsAdapter;
private Config( ConfigBuilder builder )
{
@@ -122,7 +123,7 @@ private Config( ConfigBuilder builder )
this.fetchSize = builder.fetchSize;
this.eventLoopThreads = builder.eventLoopThreads;
- this.isMetricsEnabled = builder.isMetricsEnabled;
+ this.metricsAdapter = builder.metricsAdapter;
}
/**
@@ -260,7 +261,12 @@ public int eventLoopThreads()
*/
public boolean isMetricsEnabled()
{
- return isMetricsEnabled;
+ return this.metricsAdapter != MetricsAdapter.DEV_NULL;
+ }
+
+ public MetricsAdapter metricsAdapter()
+ {
+ return this.metricsAdapter;
}
/**
@@ -290,7 +296,7 @@ public static class ConfigBuilder
private int connectionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis( 30 );
private RetrySettings retrySettings = RetrySettings.DEFAULT;
private ServerAddressResolver resolver;
- private boolean isMetricsEnabled = false;
+ private MetricsAdapter metricsAdapter = MetricsAdapter.DEV_NULL;
private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE;
private int eventLoopThreads = 0;
@@ -703,13 +709,13 @@ public ConfigBuilder withResolver( ServerAddressResolver resolver )
}
/**
- * Enable driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}.
+ * Enable driver metrics backed by internal basic implementation. The metrics can be obtained afterwards via {@link Driver#metrics()}.
+ *
* @return this builder.
*/
public ConfigBuilder withDriverMetrics()
{
- this.isMetricsEnabled = true;
- return this;
+ return withMetricsEnabled( true );
}
/**
@@ -718,7 +724,36 @@ public ConfigBuilder withDriverMetrics()
*/
public ConfigBuilder withoutDriverMetrics()
{
- this.isMetricsEnabled = false;
+ return withMetricsEnabled( false );
+ }
+
+ private ConfigBuilder withMetricsEnabled( boolean enabled )
+ {
+ if ( !enabled )
+ {
+ withMetricsAdapter( MetricsAdapter.DEV_NULL );
+ }
+ else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.DEV_NULL )
+ {
+ withMetricsAdapter( MetricsAdapter.DEFAULT );
+ }
+ return this;
+ }
+
+ /**
+ * Enable driver metrics with given {@link MetricsAdapter}.
+ *
+ * {@link MetricsAdapter#MICROMETER} enables implementation based on Micrometer. The metrics can be obtained
+ * afterwards via Micrometer means and {@link Driver#metrics()}. Micrometer must be on classpath when using this option.
+ *
+ *
+ * @param metricsAdapter the metrics adapter to use. Use {@link MetricsAdapter#DEV_NULL} to disable metrics.
+ * @return this builder.
+ */
+ @Experimental
+ public ConfigBuilder withMetricsAdapter( MetricsAdapter metricsAdapter )
+ {
+ this.metricsAdapter = Objects.requireNonNull( metricsAdapter, "metricsAdapter" );
return this;
}
diff --git a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java
index 548f8c5beb..3c9c55115a 100644
--- a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java
+++ b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java
@@ -30,8 +30,9 @@
public interface ConnectionPoolMetrics
{
/**
- * An unique id that identifies this pool metrics.
- * @return An unique name
+ * A unique id that identifies this pool metrics.
+ *
+ * @return A unique name
*/
String id();
@@ -57,9 +58,9 @@ public interface ConnectionPoolMetrics
int creating();
/**
- * A counter to record how many connections have been successfully created with this pool since the pool is created.
+ * A counter to record how many connections have been successfully created with this pool since the pool was created.
* This number increases every time when a connection is successfully created.
- * @return The amount of connections have ever been created by this pool.
+ * @return The amount of connections that have ever been created by this pool.
*/
long created();
diff --git a/driver/src/main/java/org/neo4j/driver/Driver.java b/driver/src/main/java/org/neo4j/driver/Driver.java
index 98218ed599..b5f1d48840 100644
--- a/driver/src/main/java/org/neo4j/driver/Driver.java
+++ b/driver/src/main/java/org/neo4j/driver/Driver.java
@@ -148,11 +148,10 @@ public interface Driver extends AutoCloseable
/**
* Returns the driver metrics if metrics reporting is enabled via {@link Config.ConfigBuilder#withDriverMetrics()}.
- * Otherwise a {@link ClientException} will be thrown.
+ * Otherwise, a {@link ClientException} will be thrown.
* @return the driver metrics if enabled.
* @throws ClientException if the driver metrics reporting is not enabled.
*/
- @Experimental
Metrics metrics();
/**
@@ -160,7 +159,6 @@ public interface Driver extends AutoCloseable
*
* @return true if the metrics reporting is enabled.
*/
- @Experimental
boolean isMetricsEnabled();
/**
diff --git a/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java
new file mode 100644
index 0000000000..e78e93ba0a
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver;
+
+/**
+ * Defines which metrics consumer to use: Should metrics be consumed and exposed via driver's default consumer or provided with one of the external facades.
+ */
+public enum MetricsAdapter
+{
+ /**
+ * Disables metrics.
+ */
+ DEV_NULL,
+
+ /**
+ * Consumes and publishes metrics via the driver itself.
+ */
+ DEFAULT,
+
+ /**
+ * Consumes and publishes metrics via Micrometer. Ensure that Micrometer is on classpath when using this option.
+ */
+ MICROMETER
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
index 968db9d367..63035a0f8e 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
@@ -31,6 +31,7 @@
import org.neo4j.driver.Driver;
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
+import org.neo4j.driver.MetricsAdapter;
import org.neo4j.driver.internal.async.connection.BootstrapFactory;
import org.neo4j.driver.internal.async.connection.ChannelConnector;
import org.neo4j.driver.internal.async.connection.ChannelConnectorImpl;
@@ -42,8 +43,10 @@
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer;
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancingStrategy;
import org.neo4j.driver.internal.logging.NettyLogging;
+import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
import org.neo4j.driver.internal.metrics.InternalMetricsProvider;
import org.neo4j.driver.internal.metrics.MetricsProvider;
+import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider;
import org.neo4j.driver.internal.retry.ExponentialBackoffRetryLogic;
import org.neo4j.driver.internal.retry.RetryLogic;
import org.neo4j.driver.internal.retry.RetrySettings;
@@ -56,7 +59,6 @@
import static org.neo4j.driver.internal.Scheme.isRoutingScheme;
import static org.neo4j.driver.internal.cluster.IdentityResolver.IDENTITY_RESOLVER;
-import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER;
import static org.neo4j.driver.internal.util.ErrorUtil.addSuppressed;
public class DriverFactory
@@ -94,7 +96,7 @@ public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings r
EventExecutorGroup eventExecutorGroup = bootstrap.config().group();
RetryLogic retryLogic = createRetryLogic( retrySettings, eventExecutorGroup, config.logging() );
- MetricsProvider metricsProvider = createDriverMetrics( config, createClock() );
+ MetricsProvider metricsProvider = getOrCreateMetricsProvider( config, createClock() );
ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config,
ownsEventLoopGroup, newRoutingSettings.routingContext() );
@@ -114,16 +116,24 @@ protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan
return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsProvider.metricsListener(), config.logging(), clock, ownsEventLoopGroup );
}
- protected static MetricsProvider createDriverMetrics( Config config, Clock clock )
+ protected static MetricsProvider getOrCreateMetricsProvider( Config config, Clock clock )
{
- if( config.isMetricsEnabled() )
+ MetricsAdapter metricsAdapter = config.metricsAdapter();
+ // This can actually only happen when someone mocks the config
+ if ( metricsAdapter == null )
{
- return new InternalMetricsProvider( clock, config.logging() );
+ metricsAdapter = config.isMetricsEnabled() ? MetricsAdapter.DEFAULT : MetricsAdapter.DEV_NULL;
}
- else
+ switch ( metricsAdapter )
{
- return METRICS_DISABLED_PROVIDER;
+ case DEV_NULL:
+ return DevNullMetricsProvider.INSTANCE;
+ case DEFAULT:
+ return new InternalMetricsProvider( clock, config.logging() );
+ case MICROMETER:
+ return MicrometerMetricsProvider.forGlobalRegistry();
}
+ throw new IllegalStateException( "Unknown or unsupported MetricsAdapter: " + metricsAdapter );
}
protected ChannelConnector createConnector( ConnectionSettings settings, SecurityPlan securityPlan,
diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java
index b2c975da1c..8d9acaa9cb 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java
@@ -25,12 +25,13 @@
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
import org.neo4j.driver.Metrics;
+import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.async.AsyncSession;
import org.neo4j.driver.internal.async.InternalAsyncSession;
import org.neo4j.driver.internal.async.NetworkSession;
-import org.neo4j.driver.internal.metrics.MetricsProvider;
+import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
import org.neo4j.driver.internal.reactive.InternalRxSession;
import org.neo4j.driver.internal.security.SecurityPlan;
import org.neo4j.driver.internal.types.InternalTypeSystem;
@@ -102,7 +103,7 @@ public Metrics metrics()
@Override
public boolean isMetricsEnabled()
{
- return metricsProvider.isMetricsEnabled();
+ return metricsProvider != DevNullMetricsProvider.INSTANCE;
}
@Override
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java
index 314d38850e..db46e716a8 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java
@@ -47,6 +47,7 @@
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.util.Clock;
import org.neo4j.driver.internal.util.Futures;
+import org.neo4j.driver.net.ServerAddress;
import static java.lang.String.format;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setAuthorizationStateListener;
@@ -159,13 +160,13 @@ public void retainAll( Set addressesToRetain )
}
@Override
- public int inUseConnections( BoltServerAddress address )
+ public int inUseConnections( ServerAddress address )
{
return nettyChannelTracker.inUseChannelCount( address );
}
@Override
- public int idleConnections( BoltServerAddress address )
+ public int idleConnections( ServerAddress address )
{
return nettyChannelTracker.idleChannelCount( address );
}
@@ -284,8 +285,8 @@ private ExtendedChannelPool getOrCreatePool( BoltServerAddress address )
if ( pool == null )
{
pool = newPool( address );
- // before the connection pool is added I can add the metrics for the pool.
- metricsListener.putPoolMetrics( pool.id(), address, this );
+ // before the connection pool is added I can register the metrics for the pool.
+ metricsListener.registerPoolMetrics( pool.id(), address, () -> this.inUseConnections( address ), () -> this.idleConnections( address ) );
addressToPool.put( address, pool );
}
return pool;
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelTracker.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelTracker.java
index 341bf9a8cb..44bde86033 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelTracker.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelTracker.java
@@ -37,6 +37,7 @@
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.metrics.ListenerEvent;
import org.neo4j.driver.internal.metrics.MetricsListener;
+import org.neo4j.driver.net.ServerAddress;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.poolId;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.serverAddress;
@@ -46,8 +47,8 @@ public class NettyChannelTracker implements ChannelPoolHandler
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock read = lock.readLock();
private final Lock write = lock.writeLock();
- private final Map addressToInUseChannelCount = new HashMap<>();
- private final Map addressToIdleChannelCount = new HashMap<>();
+ private final Map addressToInUseChannelCount = new HashMap<>();
+ private final Map addressToIdleChannelCount = new HashMap<>();
private final Logger log;
private final MetricsListener metricsListener;
private final ChannelFutureListener closeListener = future -> channelClosed( future.channel() );
@@ -152,12 +153,12 @@ public void channelClosed( Channel channel )
metricsListener.afterClosed( poolId( channel ) );
}
- public int inUseChannelCount( BoltServerAddress address )
+ public int inUseChannelCount( ServerAddress address )
{
return retrieveInReadLock( () -> addressToInUseChannelCount.getOrDefault( address, 0 ) );
}
- public int idleChannelCount( BoltServerAddress address )
+ public int idleChannelCount( ServerAddress address )
{
return retrieveInReadLock( () -> addressToIdleChannelCount.getOrDefault( address, 0 ) );
}
@@ -213,9 +214,9 @@ private void decrementIdle( Channel channel )
addressToIdleChannelCount.put( address, count - 1 );
}
- private void increment( Channel channel, Map countMap )
+ private void increment( Channel channel, Map countMap )
{
- BoltServerAddress address = serverAddress( channel );
+ ServerAddress address = serverAddress( channel );
Integer count = countMap.computeIfAbsent( address, k -> 0 );
countMap.put( address, count + 1 );
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java
index 647694e707..3ca86713f6 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java
@@ -18,17 +18,17 @@
*/
package org.neo4j.driver.internal.metrics;
-public interface ConnectionPoolMetricsListener
+interface ConnectionPoolMetricsListener
{
/**
* Invoked before a connection is creating.
*/
- void beforeCreating( ListenerEvent listenerEvent );
+ void beforeCreating( ListenerEvent> listenerEvent );
/**
* Invoked after a connection is created successfully.
*/
- void afterCreated( ListenerEvent listenerEvent );
+ void afterCreated( ListenerEvent> listenerEvent );
/**
* Invoked after a connection is failed to create due to timeout, any kind of error.
@@ -42,9 +42,10 @@ public interface ConnectionPoolMetricsListener
/**
* Invoked before acquiring or creating a connection.
+ *
* @param acquireEvent
*/
- void beforeAcquiringOrCreating( ListenerEvent acquireEvent );
+ void beforeAcquiringOrCreating( ListenerEvent> acquireEvent );
/**
* Invoked after a connection is being acquired or created regardless weather it is successful or not.
@@ -53,9 +54,10 @@ public interface ConnectionPoolMetricsListener
/**
* Invoked after a connection is acquired or created successfully.
+ *
* @param acquireEvent
*/
- void afterAcquiredOrCreated( ListenerEvent acquireEvent );
+ void afterAcquiredOrCreated( ListenerEvent> acquireEvent );
/**
* Invoked after it is timed out to acquire or create a connection.
@@ -64,77 +66,16 @@ public interface ConnectionPoolMetricsListener
/**
* After a connection is acquired from the pool.
+ *
* @param inUseEvent
*/
- void acquired( ListenerEvent inUseEvent );
+ void acquired( ListenerEvent> inUseEvent );
/**
* After a connection is released back to pool.
+ *
* @param inUseEvent
*/
- void released( ListenerEvent inUseEvent );
-
- ConnectionPoolMetricsListener DEV_NULL_POOL_METRICS_LISTENER = new ConnectionPoolMetricsListener()
- {
- @Override
- public void beforeCreating( ListenerEvent listenerEvent )
- {
-
- }
-
- @Override
- public void afterCreated( ListenerEvent listenerEvent )
- {
-
- }
-
- @Override
- public void afterFailedToCreate()
- {
-
- }
-
- @Override
- public void afterClosed()
- {
-
- }
-
- @Override
- public void beforeAcquiringOrCreating( ListenerEvent acquireEvent )
- {
-
- }
-
- @Override
- public void afterAcquiringOrCreating()
- {
-
- }
-
- @Override
- public void afterAcquiredOrCreated( ListenerEvent acquireEvent )
- {
-
- }
-
- @Override
- public void afterTimedOutToAcquireOrCreate()
- {
-
- }
-
- @Override
- public void acquired( ListenerEvent inUseEvent )
- {
-
- }
-
- @Override
- public void released( ListenerEvent inUseEvent )
- {
-
- }
- };
+ void released( ListenerEvent> inUseEvent );
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java
new file mode 100644
index 0000000000..6c17eab971
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+enum DevNullListenerEvent implements ListenerEvent
+{
+ INSTANCE;
+
+ @Override
+ public void start()
+ {
+ }
+
+ @Override
+ public Long getSample()
+ {
+ return 0L;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java
new file mode 100644
index 0000000000..4915906800
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import java.util.function.IntSupplier;
+
+import org.neo4j.driver.net.ServerAddress;
+
+public enum DevNullMetricsListener implements MetricsListener
+{
+ INSTANCE;
+
+ @Override
+ public void beforeCreating( String poolId, ListenerEvent> creatingEvent )
+ {
+ }
+
+ @Override
+ public void afterCreated( String poolId, ListenerEvent> creatingEvent )
+ {
+ }
+
+ @Override
+ public void afterFailedToCreate( String poolId )
+ {
+ }
+
+ @Override
+ public void afterClosed( String poolId )
+ {
+ }
+
+ @Override
+ public void beforeAcquiringOrCreating( String poolId, ListenerEvent> acquireEvent )
+ {
+ }
+
+ @Override
+ public void afterAcquiringOrCreating( String poolId )
+ {
+ }
+
+ @Override
+ public void afterAcquiredOrCreated( String poolId, ListenerEvent> acquireEvent )
+ {
+ }
+
+ @Override
+ public void afterTimedOutToAcquireOrCreate( String poolId )
+ {
+ }
+
+ @Override
+ public void afterConnectionCreated( String poolId, ListenerEvent> inUseEvent )
+ {
+ }
+
+ @Override
+ public void afterConnectionReleased( String poolId, ListenerEvent> inUseEvent )
+ {
+ }
+
+ @Override
+ public ListenerEvent> createListenerEvent()
+ {
+ return DevNullListenerEvent.INSTANCE;
+ }
+
+ @Override
+ public void registerPoolMetrics( String poolId, ServerAddress serverAddress, IntSupplier inUseSupplier, IntSupplier idleSupplier )
+ {
+ }
+
+ @Override
+ public void removePoolMetrics( String poolId )
+ {
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Driver metrics are not available if they are not enabled.";
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java
new file mode 100644
index 0000000000..3cf250cb4d
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import org.neo4j.driver.Metrics;
+import org.neo4j.driver.exceptions.ClientException;
+
+public enum DevNullMetricsProvider implements MetricsProvider
+{
+ INSTANCE;
+
+ @Override
+ public Metrics metrics()
+ {
+ // To outside users, we forbid access to the metrics API
+ throw new ClientException(
+ "Driver metrics are not enabled. You need to enable driver metrics in driver configuration in order to access them." );
+ }
+
+ @Override
+ public MetricsListener metricsListener()
+ {
+ // Internally we can still register callbacks to this empty metrics listener.
+ return DevNullMetricsListener.INSTANCE;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java
new file mode 100644
index 0000000000..3d4dcc74e6
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+enum DevNullPoolMetricsListener implements ConnectionPoolMetricsListener
+{
+ INSTANCE;
+
+ @Override
+ public void beforeCreating( ListenerEvent> listenerEvent )
+ {
+ }
+
+ @Override
+ public void afterCreated( ListenerEvent> listenerEvent )
+ {
+ }
+
+ @Override
+ public void afterFailedToCreate()
+ {
+ }
+
+ @Override
+ public void afterClosed()
+ {
+ }
+
+ @Override
+ public void beforeAcquiringOrCreating( ListenerEvent> acquireEvent )
+ {
+ }
+
+ @Override
+ public void afterAcquiringOrCreating()
+ {
+ }
+
+ @Override
+ public void afterAcquiredOrCreated( ListenerEvent> acquireEvent )
+ {
+ }
+
+ @Override
+ public void afterTimedOutToAcquireOrCreate()
+ {
+ }
+
+ @Override
+ public void acquired( ListenerEvent> inUseEvent )
+ {
+ }
+
+ @Override
+ public void released( ListenerEvent> inUseEvent )
+ {
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java
deleted file mode 100644
index 88eba87128..0000000000
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) "Neo4j"
- * Neo4j Sweden AB [http://neo4j.com]
- *
- * This file is part of Neo4j.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.neo4j.driver.internal.metrics;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.neo4j.driver.ConnectionPoolMetrics;
-import org.neo4j.driver.Metrics;
-import org.neo4j.driver.internal.BoltServerAddress;
-import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl;
-
-public abstract class InternalAbstractMetrics implements Metrics, MetricsListener
-{
- public static final InternalAbstractMetrics DEV_NULL_METRICS = new InternalAbstractMetrics()
- {
-
- @Override
- public void beforeCreating( String poolId, ListenerEvent creatingEvent )
- {
-
- }
-
- @Override
- public void afterCreated( String poolId, ListenerEvent creatingEvent )
- {
-
- }
-
- @Override
- public void afterFailedToCreate( String poolId )
- {
-
- }
-
- @Override
- public void afterClosed( String poolId )
- {
-
- }
-
- @Override
- public void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent )
- {
-
- }
-
- @Override
- public void afterAcquiringOrCreating( String poolId )
- {
-
- }
-
- @Override
- public void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent )
- {
-
- }
-
- @Override
- public void afterTimedOutToAcquireOrCreate( String poolId )
- {
-
- }
-
- @Override
- public void afterConnectionCreated( String poolId, ListenerEvent inUseEvent )
- {
-
- }
-
- @Override
- public void afterConnectionReleased( String poolId, ListenerEvent inUseEvent )
- {
-
- }
-
- @Override
- public ListenerEvent createListenerEvent()
- {
- return ListenerEvent.DEV_NULL_LISTENER_EVENT;
- }
-
- @Override
- public void putPoolMetrics( String id, BoltServerAddress address, ConnectionPoolImpl connectionPool )
- {
-
- }
-
- @Override
- public void removePoolMetrics( String poolId )
- {
-
- }
-
- @Override
- public Collection connectionPoolMetrics()
- {
- return Collections.emptySet();
- }
-
- @Override
- public String toString()
- {
- return "Driver metrics not available while driver metrics is not enabled.";
- }
- };
-}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalConnectionPoolMetrics.java
index 073a4a1952..ba9c80fef8 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalConnectionPoolMetrics.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalConnectionPoolMetrics.java
@@ -21,17 +21,18 @@
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.IntSupplier;
import org.neo4j.driver.ConnectionPoolMetrics;
-import org.neo4j.driver.internal.BoltServerAddress;
-import org.neo4j.driver.internal.spi.ConnectionPool;
+import org.neo4j.driver.net.ServerAddress;
import static java.lang.String.format;
-public class InternalConnectionPoolMetrics implements ConnectionPoolMetrics, ConnectionPoolMetricsListener
+final class InternalConnectionPoolMetrics implements ConnectionPoolMetrics, ConnectionPoolMetricsListener
{
- private final BoltServerAddress address;
- private final ConnectionPool pool;
+ private final ServerAddress address;
+ private final IntSupplier inUseSupplier;
+ private final IntSupplier idleSupplier;
private final AtomicLong closed = new AtomicLong();
@@ -52,18 +53,20 @@ public class InternalConnectionPoolMetrics implements ConnectionPoolMetrics, Con
private final AtomicLong totalInUseCount = new AtomicLong();
private final String id;
- InternalConnectionPoolMetrics( String poolId, BoltServerAddress address, ConnectionPool pool )
+ InternalConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier )
{
Objects.requireNonNull( address );
- Objects.requireNonNull( pool );
+ Objects.requireNonNull( inUseSupplier );
+ Objects.requireNonNull( idleSupplier );
this.id = poolId;
this.address = address;
- this.pool = pool;
+ this.inUseSupplier = inUseSupplier;
+ this.idleSupplier = idleSupplier;
}
@Override
- public void beforeCreating( ListenerEvent connEvent )
+ public void beforeCreating( ListenerEvent> connEvent )
{
creating.incrementAndGet();
connEvent.start();
@@ -77,13 +80,13 @@ public void afterFailedToCreate()
}
@Override
- public void afterCreated( ListenerEvent connEvent )
+ public void afterCreated( ListenerEvent> connEvent )
{
created.incrementAndGet();
creating.decrementAndGet();
- long elapsed = connEvent.elapsed();
+ long sample = ((TimeRecorderListenerEvent) connEvent).getSample();
- totalConnectionTime.addAndGet( elapsed );
+ totalConnectionTime.addAndGet( sample );
}
@Override
@@ -93,7 +96,7 @@ public void afterClosed()
}
@Override
- public void beforeAcquiringOrCreating( ListenerEvent acquireEvent )
+ public void beforeAcquiringOrCreating( ListenerEvent> acquireEvent )
{
acquireEvent.start();
acquiring.incrementAndGet();
@@ -106,12 +109,12 @@ public void afterAcquiringOrCreating()
}
@Override
- public void afterAcquiredOrCreated( ListenerEvent acquireEvent )
+ public void afterAcquiredOrCreated( ListenerEvent> acquireEvent )
{
acquired.incrementAndGet();
- long elapsed = acquireEvent.elapsed();
+ long sample = ((TimeRecorderListenerEvent) acquireEvent).getSample();
- totalAcquisitionTime.addAndGet( elapsed );
+ totalAcquisitionTime.addAndGet( sample );
}
@Override
@@ -121,18 +124,18 @@ public void afterTimedOutToAcquireOrCreate()
}
@Override
- public void acquired( ListenerEvent inUseEvent )
+ public void acquired( ListenerEvent> inUseEvent )
{
inUseEvent.start();
}
@Override
- public void released( ListenerEvent inUseEvent )
+ public void released( ListenerEvent> inUseEvent )
{
totalInUseCount.incrementAndGet();
- long elapsed = inUseEvent.elapsed();
+ long sample = ((TimeRecorderListenerEvent) inUseEvent).getSample();
- totalInUseTime.addAndGet( elapsed );
+ totalInUseTime.addAndGet( sample );
}
@Override
@@ -144,13 +147,13 @@ public String id()
@Override
public int inUse()
{
- return pool.inUseConnections( address );
+ return inUseSupplier.getAsInt();
}
@Override
public int idle()
{
- return pool.idleConnections( address );
+ return idleSupplier.getAsInt();
}
@Override
@@ -230,8 +233,8 @@ public String toString()
totalAcquisitionTime(), totalConnectionTime(), totalInUseTime(), totalInUseCount() );
}
- // This method is for purposes testing only
- public BoltServerAddress getAddress()
+ // This method is for testing purposes only
+ public ServerAddress getAddress()
{
return address;
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetrics.java
index a83b033529..9cda445b71 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetrics.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetrics.java
@@ -22,19 +22,19 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntSupplier;
import org.neo4j.driver.ConnectionPoolMetrics;
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.internal.BoltServerAddress;
-import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl;
+import org.neo4j.driver.Metrics;
import org.neo4j.driver.internal.util.Clock;
+import org.neo4j.driver.net.ServerAddress;
import static java.lang.String.format;
import static java.util.Collections.unmodifiableCollection;
-import static org.neo4j.driver.internal.metrics.ConnectionPoolMetricsListener.DEV_NULL_POOL_METRICS_LISTENER;
-public class InternalMetrics extends InternalAbstractMetrics
+final class InternalMetrics implements Metrics, MetricsListener
{
private final Map connectionPoolMetrics;
private final Clock clock;
@@ -49,9 +49,9 @@ public class InternalMetrics extends InternalAbstractMetrics
}
@Override
- public void putPoolMetrics( String poolId, BoltServerAddress serverAddress, ConnectionPoolImpl pool )
+ public void registerPoolMetrics( String poolId, ServerAddress serverAddress, IntSupplier inUseSupplier, IntSupplier idleSupplier )
{
- this.connectionPoolMetrics.put( poolId, new InternalConnectionPoolMetrics( poolId, serverAddress, pool ) );
+ this.connectionPoolMetrics.put( poolId, new InternalConnectionPoolMetrics( poolId, serverAddress, inUseSupplier, idleSupplier ) );
}
@Override
@@ -61,13 +61,13 @@ public void removePoolMetrics( String id )
}
@Override
- public void beforeCreating( String poolId, ListenerEvent creatingEvent )
+ public void beforeCreating( String poolId, ListenerEvent> creatingEvent )
{
poolMetrics( poolId ).beforeCreating( creatingEvent );
}
@Override
- public void afterCreated( String poolId, ListenerEvent creatingEvent )
+ public void afterCreated( String poolId, ListenerEvent> creatingEvent )
{
poolMetrics( poolId ).afterCreated( creatingEvent );
}
@@ -85,7 +85,7 @@ public void afterClosed( String poolId )
}
@Override
- public void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent )
+ public void beforeAcquiringOrCreating( String poolId, ListenerEvent> acquireEvent )
{
poolMetrics( poolId ).beforeAcquiringOrCreating( acquireEvent );
}
@@ -97,19 +97,19 @@ public void afterAcquiringOrCreating( String poolId )
}
@Override
- public void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent )
+ public void afterAcquiredOrCreated( String poolId, ListenerEvent> acquireEvent )
{
poolMetrics( poolId ).afterAcquiredOrCreated( acquireEvent );
}
@Override
- public void afterConnectionCreated( String poolId, ListenerEvent inUseEvent )
+ public void afterConnectionCreated( String poolId, ListenerEvent> inUseEvent )
{
poolMetrics( poolId ).acquired( inUseEvent );
}
@Override
- public void afterConnectionReleased( String poolId, ListenerEvent inUseEvent )
+ public void afterConnectionReleased( String poolId, ListenerEvent> inUseEvent )
{
poolMetrics( poolId ).released( inUseEvent );
}
@@ -121,7 +121,7 @@ public void afterTimedOutToAcquireOrCreate( String poolId )
}
@Override
- public ListenerEvent createListenerEvent()
+ public ListenerEvent> createListenerEvent()
{
return new TimeRecorderListenerEvent( clock );
}
@@ -144,7 +144,7 @@ private ConnectionPoolMetricsListener poolMetrics( String poolId )
if ( poolMetrics == null )
{
log.warn( format( "Failed to find pool metrics with id `%s` in %s.", poolId, this.connectionPoolMetrics ) );
- return DEV_NULL_POOL_METRICS_LISTENER;
+ return DevNullPoolMetricsListener.INSTANCE;
}
return poolMetrics;
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java
index b807f055c8..0980dbf218 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java
@@ -22,7 +22,7 @@
import org.neo4j.driver.internal.util.Clock;
import org.neo4j.driver.Metrics;
-public class InternalMetricsProvider implements MetricsProvider
+public final class InternalMetricsProvider implements MetricsProvider
{
private final InternalMetrics metrics;
@@ -42,10 +42,4 @@ public MetricsListener metricsListener()
{
return metrics;
}
-
- @Override
- public boolean isMetricsEnabled()
- {
- return true;
- }
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java
index ddbf09617d..543ee0e723 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java
@@ -18,23 +18,10 @@
*/
package org.neo4j.driver.internal.metrics;
-public interface ListenerEvent
+public interface ListenerEvent
{
- ListenerEvent DEV_NULL_LISTENER_EVENT = new ListenerEvent()
- {
- @Override
- public void start()
- {
- }
-
- @Override
- public long elapsed()
- {
- return 0;
- }
- };
-
void start();
- long elapsed();
+
+ T getSample();
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java
index c96e018048..48e5710b2a 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java
@@ -19,26 +19,27 @@
package org.neo4j.driver.internal.metrics;
import java.util.concurrent.TimeUnit;
+import java.util.function.IntSupplier;
-import org.neo4j.driver.internal.BoltServerAddress;
-import org.neo4j.driver.internal.async.NetworkConnection;
-import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl;
import org.neo4j.driver.Config;
+import org.neo4j.driver.net.ServerAddress;
public interface MetricsListener
{
/**
* Before creating a netty channel.
- * @param poolId the id of the pool where the netty channel lives.
+ *
+ * @param poolId the id of the pool where the netty channel lives.
* @param creatingEvent a connection listener event registered when a connection is creating.
*/
- void beforeCreating( String poolId, ListenerEvent creatingEvent );
+ void beforeCreating( String poolId, ListenerEvent> creatingEvent );
/**
* After a netty channel is created successfully.
+ *
* @param poolId the id of the pool where the netty channel lives.
*/
- void afterCreated( String poolId, ListenerEvent creatingEvent );
+ void afterCreated( String poolId, ListenerEvent> creatingEvent );
/**
* After a netty channel is created with a failure.
@@ -54,10 +55,11 @@ public interface MetricsListener
/**
* Before acquiring or creating a new netty channel from pool.
- * @param poolId the id of the pool where the netty channel lives.
+ *
+ * @param poolId the id of the pool where the netty channel lives.
* @param acquireEvent a pool listener event registered in pool for this acquire event.
*/
- void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent );
+ void beforeAcquiringOrCreating( String poolId, ListenerEvent> acquireEvent );
/**
* After acquiring or creating a new netty channel from pool regardless it is successful or not.
@@ -67,10 +69,11 @@ public interface MetricsListener
/**
* After acquiring or creating a new netty channel from pool successfully.
- * @param poolId the id of the pool where the netty channel lives.
+ *
+ * @param poolId the id of the pool where the netty channel lives.
* @param acquireEvent a pool listener event registered in pool for this acquire event.
*/
- void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent );
+ void afterAcquiredOrCreated( String poolId, ListenerEvent> acquireEvent );
/**
* After we failed to acquire a connection from pool within maximum connection acquisition timeout set by
@@ -81,21 +84,23 @@ public interface MetricsListener
/**
* After acquiring or creating a new netty channel from pool successfully.
- * @param poolId the id of the pool where the netty channel lives.
- * @param inUseEvent a connection listener registered with a {@link NetworkConnection} when created.
+ *
+ * @param poolId the id of the pool where the netty channel lives.
+ * @param inUseEvent a connection listener event fired from the newly created connection.
*/
- void afterConnectionCreated( String poolId, ListenerEvent inUseEvent );
+ void afterConnectionCreated( String poolId, ListenerEvent> inUseEvent );
/**
* After releasing a netty channel back to pool successfully.
- * @param poolId the id of the pool where the netty channel lives.
- * @param inUseEvent a connection listener registered with a {@link NetworkConnection} when destroyed.
+ *
+ * @param poolId the id of the pool where the netty channel lives.
+ * @param inUseEvent a connection listener event fired from the connection being released.
*/
- void afterConnectionReleased( String poolId, ListenerEvent inUseEvent );
+ void afterConnectionReleased( String poolId, ListenerEvent> inUseEvent );
- ListenerEvent createListenerEvent();
+ ListenerEvent> createListenerEvent();
- void putPoolMetrics( String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool );
+ void registerPoolMetrics( String poolId, ServerAddress serverAddress, IntSupplier inUseSupplier, IntSupplier idleSupplier );
void removePoolMetrics( String poolId );
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java
index 8d476fa381..a2cfb5e1b7 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java
@@ -19,39 +19,19 @@
package org.neo4j.driver.internal.metrics;
import org.neo4j.driver.Metrics;
-import org.neo4j.driver.exceptions.ClientException;
-
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
+/**
+ * An adapter that collects driver metrics via {@link MetricsListener} and publishes them via {@link Metrics} instance.
+ */
public interface MetricsProvider
{
- MetricsProvider METRICS_DISABLED_PROVIDER = new MetricsProvider()
- {
- @Override
- public Metrics metrics()
- {
- // To outside users, we forbidden their access to the metrics API
- throw new ClientException( "Driver metrics not enabled. To access driver metrics, " +
- "you need to enabled driver metrics in the driver's configuration." );
- }
-
- @Override
- public MetricsListener metricsListener()
- {
- // Internally we can still register callbacks to this empty metrics listener.
- return DEV_NULL_METRICS;
- }
-
- @Override
- public boolean isMetricsEnabled()
- {
- return false;
- }
- };
-
+ /**
+ * @return The actual metrics type to use
+ */
Metrics metrics();
+ /**
+ * @return A listener that will be notified on certain events so that it can collect metrics about them.
+ */
MetricsListener metricsListener();
-
- boolean isMetricsEnabled();
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java
new file mode 100644
index 0000000000..0e53c15f3b
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Tags;
+import io.micrometer.core.instrument.Timer;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntSupplier;
+
+import org.neo4j.driver.ConnectionPoolMetrics;
+import org.neo4j.driver.internal.BoltServerAddress;
+import org.neo4j.driver.net.ServerAddress;
+
+import static java.lang.String.format;
+
+final class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsListener, ConnectionPoolMetrics
+{
+ public static final String PREFIX = "neo4j.driver.connections";
+ public static final String IN_USE = PREFIX + ".in.use";
+ public static final String IDLE = PREFIX + ".idle";
+ public static final String CREATING = PREFIX + ".creating";
+ public static final String FAILED = PREFIX + ".failed";
+ public static final String CLOSED = PREFIX + ".closed";
+ public static final String ACQUIRING = PREFIX + ".acquiring";
+ public static final String ACQUISITION_TIMEOUT = PREFIX + ".acquisition.timeout";
+ public static final String ACQUISITION = PREFIX + ".acquisition";
+ public static final String CREATION = PREFIX + ".creation";
+ public static final String USAGE = PREFIX + ".usage";
+
+ private final IntSupplier inUseSupplier;
+ private final IntSupplier idleSupplier;
+
+ private final String id;
+
+ private final AtomicInteger creating = new AtomicInteger();
+ private final Counter failedToCreate;
+ private final Counter closed;
+ private final AtomicInteger acquiring = new AtomicInteger();
+ private final Counter timedOutToAcquire;
+ private final Timer totalAcquisitionTimer;
+ private final Timer totalConnectionTimer;
+ private final Timer totalInUseTimer;
+
+ MicrometerConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier, MeterRegistry registry )
+ {
+ this( poolId, address, inUseSupplier, idleSupplier, registry, Tags.empty() );
+ }
+
+ MicrometerConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier, MeterRegistry registry, Iterable initialTags )
+ {
+ Objects.requireNonNull( poolId );
+ Objects.requireNonNull( address );
+ Objects.requireNonNull( inUseSupplier );
+ Objects.requireNonNull( idleSupplier );
+ Objects.requireNonNull( registry );
+
+ this.id = poolId;
+ this.inUseSupplier = inUseSupplier;
+ this.idleSupplier = idleSupplier;
+ String host = address instanceof BoltServerAddress ? ((BoltServerAddress) address).connectionHost() : address.host();
+ Iterable tags = Tags.concat( initialTags,
+ "address", String.format( "%s:%d", host, address.port() ) );
+
+ Gauge.builder( IN_USE, this::inUse ).tags( tags ).register( registry );
+ Gauge.builder( IDLE, this::idle ).tags( tags ).register( registry );
+ Gauge.builder( CREATING, creating, AtomicInteger::get ).tags( tags ).register( registry );
+ failedToCreate = Counter.builder( FAILED ).tags( tags ).register( registry );
+ closed = Counter.builder( CLOSED ).tags( tags ).register( registry );
+ Gauge.builder( ACQUIRING, acquiring, AtomicInteger::get ).tags( tags ).register( registry );
+ timedOutToAcquire = Counter.builder( ACQUISITION_TIMEOUT ).tags( tags ).register( registry );
+ totalAcquisitionTimer = Timer.builder( ACQUISITION ).tags( tags ).register( registry );
+ totalConnectionTimer = Timer.builder( CREATION ).tags( tags ).register( registry );
+ totalInUseTimer = Timer.builder( USAGE ).tags( tags ).register( registry );
+ }
+
+ @Override
+ public void beforeCreating( ListenerEvent> connEvent )
+ {
+ creating.incrementAndGet();
+ connEvent.start();
+ }
+
+ @Override
+ public void afterFailedToCreate()
+ {
+ failedToCreate.increment();
+ creating.decrementAndGet();
+ }
+
+ @Override
+ public void afterCreated( ListenerEvent> connEvent )
+ {
+ creating.decrementAndGet();
+ Timer.Sample sample = ((MicrometerTimerListenerEvent) connEvent).getSample();
+ sample.stop( totalConnectionTimer );
+ }
+
+ @Override
+ public void afterClosed()
+ {
+ closed.increment();
+ }
+
+ @Override
+ public void beforeAcquiringOrCreating( ListenerEvent> acquireEvent )
+ {
+ acquireEvent.start();
+ acquiring.incrementAndGet();
+ }
+
+ @Override
+ public void afterAcquiringOrCreating()
+ {
+ acquiring.decrementAndGet();
+ }
+
+ @Override
+ public void afterAcquiredOrCreated( ListenerEvent> acquireEvent )
+ {
+ Timer.Sample sample = ((MicrometerTimerListenerEvent) acquireEvent).getSample();
+ sample.stop( totalAcquisitionTimer );
+ }
+
+ @Override
+ public void afterTimedOutToAcquireOrCreate()
+ {
+ timedOutToAcquire.increment();
+ }
+
+ @Override
+ public void acquired( ListenerEvent> inUseEvent )
+ {
+ inUseEvent.start();
+ }
+
+ @Override
+ public void released( ListenerEvent> inUseEvent )
+ {
+ Timer.Sample sample = ((MicrometerTimerListenerEvent) inUseEvent).getSample();
+ sample.stop( totalInUseTimer );
+ }
+
+ @Override
+ public String id()
+ {
+ return this.id;
+ }
+
+ @Override
+ public int inUse()
+ {
+ return inUseSupplier.getAsInt();
+ }
+
+ @Override
+ public int idle()
+ {
+ return idleSupplier.getAsInt();
+ }
+
+ @Override
+ public int creating()
+ {
+ return creating.get();
+ }
+
+ @Override
+ public long created()
+ {
+ return totalConnectionTimer.count();
+ }
+
+ @Override
+ public long failedToCreate()
+ {
+ return count( failedToCreate );
+ }
+
+ @Override
+ public long closed()
+ {
+ return count( closed );
+ }
+
+ @Override
+ public int acquiring()
+ {
+ return acquiring.get();
+ }
+
+ @Override
+ public long acquired()
+ {
+ return totalAcquisitionTimer.count();
+ }
+
+ @Override
+ public long timedOutToAcquire()
+ {
+ return count( timedOutToAcquire );
+ }
+
+ @Override
+ public long totalAcquisitionTime()
+ {
+ return (long) totalAcquisitionTimer.totalTime( TimeUnit.MILLISECONDS );
+ }
+
+ @Override
+ public long totalConnectionTime()
+ {
+ return (long) totalConnectionTimer.totalTime( TimeUnit.MILLISECONDS );
+ }
+
+ @Override
+ public long totalInUseTime()
+ {
+ return (long) totalInUseTimer.totalTime( TimeUnit.MILLISECONDS );
+ }
+
+ @Override
+ public long totalInUseCount()
+ {
+ return totalInUseTimer.count();
+ }
+
+ @Override
+ public String toString()
+ {
+ return format( "%s=[created=%s, closed=%s, creating=%s, failedToCreate=%s, acquiring=%s, acquired=%s, " +
+ "timedOutToAcquire=%s, inUse=%s, idle=%s, " +
+ "totalAcquisitionTime=%s, totalConnectionTime=%s, totalInUseTime=%s, totalInUseCount=%s]",
+ id(), created(), closed(), creating(), failedToCreate(), acquiring(), acquired(),
+ timedOutToAcquire(), inUse(), idle(),
+ totalAcquisitionTime(), totalConnectionTime(), totalInUseTime(), totalInUseCount() );
+ }
+
+ private long count( Counter counter )
+ {
+ return (long) counter.count();
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java
new file mode 100644
index 0000000000..f3b4eaf134
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntSupplier;
+
+import org.neo4j.driver.ConnectionPoolMetrics;
+import org.neo4j.driver.Metrics;
+import org.neo4j.driver.net.ServerAddress;
+
+final class MicrometerMetrics implements Metrics, MetricsListener
+{
+ private final MeterRegistry meterRegistry;
+ private final Map connectionPoolMetrics;
+
+ public MicrometerMetrics( MeterRegistry meterRegistry )
+ {
+ this.meterRegistry = meterRegistry;
+ this.connectionPoolMetrics = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public Collection connectionPoolMetrics()
+ {
+ return Collections.unmodifiableCollection( this.connectionPoolMetrics.values() );
+ }
+
+ @Override
+ public void beforeCreating( String poolId, ListenerEvent> creatingEvent )
+ {
+ poolMetricsListener( poolId ).beforeCreating( creatingEvent );
+ }
+
+ @Override
+ public void afterCreated( String poolId, ListenerEvent> creatingEvent )
+ {
+ poolMetricsListener( poolId ).afterCreated( creatingEvent );
+ }
+
+ @Override
+ public void afterFailedToCreate( String poolId )
+ {
+ poolMetricsListener( poolId ).afterFailedToCreate();
+ }
+
+ @Override
+ public void afterClosed( String poolId )
+ {
+ poolMetricsListener( poolId ).afterClosed();
+ }
+
+ @Override
+ public void beforeAcquiringOrCreating( String poolId, ListenerEvent> acquireEvent )
+ {
+ poolMetricsListener( poolId ).beforeAcquiringOrCreating( acquireEvent );
+ }
+
+ @Override
+ public void afterAcquiringOrCreating( String poolId )
+ {
+ poolMetricsListener( poolId ).afterAcquiringOrCreating();
+ }
+
+ @Override
+ public void afterAcquiredOrCreated( String poolId, ListenerEvent> acquireEvent )
+ {
+ poolMetricsListener( poolId ).afterAcquiredOrCreated( acquireEvent );
+ }
+
+ @Override
+ public void afterTimedOutToAcquireOrCreate( String poolId )
+ {
+ poolMetricsListener( poolId ).afterTimedOutToAcquireOrCreate();
+ }
+
+ @Override
+ public void afterConnectionCreated( String poolId, ListenerEvent> inUseEvent )
+ {
+ poolMetricsListener( poolId ).acquired( inUseEvent );
+ }
+
+ @Override
+ public void afterConnectionReleased( String poolId, ListenerEvent> inUseEvent )
+ {
+ poolMetricsListener( poolId ).released( inUseEvent );
+ }
+
+ @Override
+ public ListenerEvent> createListenerEvent()
+ {
+ return new MicrometerTimerListenerEvent( this.meterRegistry );
+ }
+
+ @Override
+ public void registerPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier )
+ {
+ this.connectionPoolMetrics.put( poolId, new MicrometerConnectionPoolMetrics( poolId, address, inUseSupplier, idleSupplier, this.meterRegistry ) );
+ }
+
+ // For testing purposes only
+ void putPoolMetrics( String poolId, ConnectionPoolMetrics poolMetrics )
+ {
+ this.connectionPoolMetrics.put( poolId, poolMetrics );
+ }
+
+ @Override
+ public void removePoolMetrics( String poolId )
+ {
+ this.connectionPoolMetrics.remove( poolId );
+ }
+
+ private ConnectionPoolMetricsListener poolMetricsListener( String poolId )
+ {
+ ConnectionPoolMetricsListener poolMetrics = (ConnectionPoolMetricsListener) this.connectionPoolMetrics.get( poolId );
+ if ( poolMetrics == null )
+ {
+ return DevNullPoolMetricsListener.INSTANCE;
+ }
+ return poolMetrics;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java
new file mode 100644
index 0000000000..3b766a6bfd
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+
+import org.neo4j.driver.Metrics;
+
+/**
+ * An adapter to bridge between driver metrics and Micrometer {@link MeterRegistry meter registry}.
+ */
+public final class MicrometerMetricsProvider implements MetricsProvider
+{
+ private final MicrometerMetrics metrics;
+
+ public static MetricsProvider forGlobalRegistry()
+ {
+ return of( io.micrometer.core.instrument.Metrics.globalRegistry );
+ }
+
+ public static MetricsProvider of( MeterRegistry meterRegistry )
+ {
+ return new MicrometerMetricsProvider( meterRegistry );
+ }
+
+ private MicrometerMetricsProvider( MeterRegistry meterRegistry )
+ {
+ this.metrics = new MicrometerMetrics( meterRegistry );
+ }
+
+ @Override
+ public Metrics metrics()
+ {
+ return this.metrics;
+ }
+
+ @Override
+ public MetricsListener metricsListener()
+ {
+ return this.metrics;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java
new file mode 100644
index 0000000000..9258666783
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+
+final class MicrometerTimerListenerEvent implements ListenerEvent
+{
+ private final MeterRegistry meterRegistry;
+ private Timer.Sample sample;
+
+ public MicrometerTimerListenerEvent( MeterRegistry meterRegistry )
+ {
+ this.meterRegistry = meterRegistry;
+ }
+
+ @Override
+ public void start()
+ {
+ this.sample = Timer.start( this.meterRegistry );
+ }
+
+ @Override
+ public Timer.Sample getSample()
+ {
+ return this.sample;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/TimeRecorderListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/TimeRecorderListenerEvent.java
index d9cdfba7ae..c286de7001 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/metrics/TimeRecorderListenerEvent.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/TimeRecorderListenerEvent.java
@@ -20,10 +20,10 @@
import org.neo4j.driver.internal.util.Clock;
-public class TimeRecorderListenerEvent implements ListenerEvent
+final class TimeRecorderListenerEvent implements ListenerEvent
{
- private long startTime;
private final Clock clock;
+ private long startTime;
TimeRecorderListenerEvent( Clock clock )
{
@@ -37,7 +37,7 @@ public void start()
}
@Override
- public long elapsed()
+ public Long getSample()
{
return clock.millis() - startTime;
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/spi/ConnectionPool.java b/driver/src/main/java/org/neo4j/driver/internal/spi/ConnectionPool.java
index 0bd91db8fe..f86242b9ee 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/spi/ConnectionPool.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/spi/ConnectionPool.java
@@ -22,6 +22,7 @@
import java.util.concurrent.CompletionStage;
import org.neo4j.driver.internal.BoltServerAddress;
+import org.neo4j.driver.net.ServerAddress;
public interface ConnectionPool
{
@@ -31,9 +32,9 @@ public interface ConnectionPool
void retainAll( Set addressesToRetain );
- int inUseConnections( BoltServerAddress address );
+ int inUseConnections( ServerAddress address );
- int idleConnections( BoltServerAddress address );
+ int idleConnections( ServerAddress address );
CompletionStage close();
diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java
index a68f5da3b6..64bdbe95d3 100644
--- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java
+++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java
@@ -362,33 +362,61 @@ void shouldErrorWithInvalidUserAgent()
assertThrows( IllegalArgumentException.class, () -> Config.builder().withUserAgent( "" ).build() );
}
+ @Test
+ void shouldNotHaveMeterRegistryByDefault()
+ {
+ Config config = Config.builder().build();
+ MetricsAdapter metricsAdapter = config.metricsAdapter();
+
+ assertEquals( MetricsAdapter.DEV_NULL, metricsAdapter );
+ assertFalse( config.isMetricsEnabled() );
+ }
+
+ @Test
+ void shouldNotAcceptNullMeterRegistry()
+ {
+ Config.ConfigBuilder builder = Config.builder();
+ assertThrows( NullPointerException.class, () -> builder.withMetricsAdapter( null ) );
+ }
+
+ @Test
+ void shouldSetMetricsAdapter()
+ {
+ Config config = Config.builder()
+ .withMetricsAdapter( MetricsAdapter.DEFAULT )
+ .build();
+ MetricsAdapter metricsAdapter = config.metricsAdapter();
+
+ assertEquals( MetricsAdapter.DEFAULT, metricsAdapter );
+ assertTrue( config.isMetricsEnabled() );
+ }
+
@Nested
class SerializationTest
{
-
@Test
void shouldSerialize() throws Exception
{
Config config = Config.builder()
- .withMaxConnectionPoolSize( 123 )
- .withConnectionTimeout( 6543L, TimeUnit.MILLISECONDS )
- .withConnectionAcquisitionTimeout( 5432L, TimeUnit.MILLISECONDS )
- .withConnectionLivenessCheckTimeout( 4321L, TimeUnit.MILLISECONDS )
- .withMaxConnectionLifetime( 4711, TimeUnit.MILLISECONDS )
- .withMaxTransactionRetryTime( 3210L, TimeUnit.MILLISECONDS )
- .withFetchSize( 9876L )
- .withEventLoopThreads( 4 )
- .withoutEncryption()
- .withTrustStrategy( Config.TrustStrategy.trustCustomCertificateSignedBy( new File( "doesntMatter" )) )
- .withUserAgent( "user-agent" )
- .withDriverMetrics()
- .withRoutingTablePurgeDelay( 50000, TimeUnit.MILLISECONDS )
- .withLeakedSessionsLogging()
- .build();
+ .withMaxConnectionPoolSize( 123 )
+ .withConnectionTimeout( 6543L, TimeUnit.MILLISECONDS )
+ .withConnectionAcquisitionTimeout( 5432L, TimeUnit.MILLISECONDS )
+ .withConnectionLivenessCheckTimeout( 4321L, TimeUnit.MILLISECONDS )
+ .withMaxConnectionLifetime( 4711, TimeUnit.MILLISECONDS )
+ .withMaxTransactionRetryTime( 3210L, TimeUnit.MILLISECONDS )
+ .withFetchSize( 9876L )
+ .withEventLoopThreads( 4 )
+ .withoutEncryption()
+ .withTrustStrategy( Config.TrustStrategy.trustCustomCertificateSignedBy( new File( "doesntMatter" ) ) )
+ .withUserAgent( "user-agent" )
+ .withDriverMetrics()
+ .withRoutingTablePurgeDelay( 50000, TimeUnit.MILLISECONDS )
+ .withLeakedSessionsLogging()
+ .withMetricsAdapter( MetricsAdapter.MICROMETER )
+ .build();
Config verify = TestUtil.serializeAndReadBack( config, Config.class );
-
assertEquals( config.maxConnectionPoolSize(), verify.maxConnectionPoolSize() );
assertEquals( config.connectionTimeoutMillis(), verify.connectionTimeoutMillis() );
assertEquals( config.connectionAcquisitionTimeoutMillis(), verify.connectionAcquisitionTimeoutMillis() );
@@ -406,6 +434,7 @@ void shouldSerialize() throws Exception
assertEquals( config.trustStrategy().revocationStrategy(), verify.trustStrategy().revocationStrategy() );
assertEquals( config.userAgent(), verify.userAgent() );
assertEquals( config.isMetricsEnabled(), verify.isMetricsEnabled() );
+ assertEquals( config.metricsAdapter(), verify.metricsAdapter() );
assertEquals( config.routingSettings().routingTablePurgeDelayMs(), verify.routingSettings().routingTablePurgeDelayMs() );
assertEquals( config.logLeakedSessions(), verify.logLeakedSessions() );
}
@@ -413,7 +442,6 @@ void shouldSerialize() throws Exception
@Test
void shouldSerializeSerializableLogging() throws IOException, ClassNotFoundException
{
-
Config config = Config.builder().withLogging( Logging.javaUtilLogging( Level.ALL ) ).build();
Config verify = TestUtil.serializeAndReadBack( config, Config.class );
diff --git a/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java b/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java
index b45be04669..551910430b 100644
--- a/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java
+++ b/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java
@@ -54,6 +54,7 @@
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.cluster.RoutingSettings;
import org.neo4j.driver.internal.metrics.MetricsProvider;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.retry.RetrySettings;
import org.neo4j.driver.internal.security.SecurityPlan;
import org.neo4j.driver.internal.security.SecurityPlanImpl;
@@ -81,7 +82,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.neo4j.driver.Values.parameters;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.internal.util.Neo4jFeature.BOLT_V4;
import static org.neo4j.driver.util.TestUtil.await;
@@ -496,7 +496,7 @@ private static class MemorizingConnectionPool extends ConnectionPoolImpl
MemorizingConnectionPool( ChannelConnector connector, Bootstrap bootstrap, PoolSettings settings,
Logging logging, Clock clock, boolean ownsEventLoopGroup )
{
- super( connector, bootstrap, settings, DEV_NULL_METRICS, logging, clock, ownsEventLoopGroup );
+ super( connector, bootstrap, settings, DevNullMetricsListener.INSTANCE, logging, clock, ownsEventLoopGroup );
}
void startMemorizing()
diff --git a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java
new file mode 100644
index 0000000000..4c777a90ef
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.integration;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import org.neo4j.driver.Config;
+import org.neo4j.driver.Driver;
+import org.neo4j.driver.GraphDatabase;
+import org.neo4j.driver.MetricsAdapter;
+import org.neo4j.driver.QueryRunner;
+import org.neo4j.driver.Result;
+import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider;
+import org.neo4j.driver.util.DatabaseExtension;
+import org.neo4j.driver.util.ParallelizableIT;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.neo4j.driver.Values.parameters;
+
+@ParallelizableIT
+class MetricsIT
+{
+ @RegisterExtension
+ static final DatabaseExtension neo4j = new DatabaseExtension();
+
+ private Driver driver;
+ private MeterRegistry meterRegistry = new SimpleMeterRegistry();
+
+ @BeforeEach
+ void createDriver()
+ {
+ driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(),
+ Config.builder().withMetricsAdapter( MetricsAdapter.MICROMETER ).build() );
+ }
+
+ @AfterEach
+ void closeDriver()
+ {
+ driver.close();
+ }
+
+ @Test
+ void driverMetricsUpdatedWithDriverUse()
+ {
+ Result result = createNodesInNewSession( 12 );
+ // assert in use
+ Timer acquisitionTimer = meterRegistry.get( "neo4j.driver.connections.acquisition" ).timer();
+ Timer creationTimer = meterRegistry.get( "neo4j.driver.connections.creation" ).timer();
+ Timer usageTimer = meterRegistry.get( "neo4j.driver.connections.usage" ).timer();
+ assertEquals( 1, acquisitionTimer.count() );
+ assertEquals( 1, creationTimer.count() );
+ assertEquals( 0, usageTimer.count() );
+
+ result.consume();
+ // assert released
+ assertEquals( 1, acquisitionTimer.count() );
+ assertEquals( 1, creationTimer.count() );
+ assertEquals( 1, usageTimer.count() );
+ }
+
+ private Result createNodesInNewSession( int nodesToCreate )
+ {
+ return createNodes( nodesToCreate, driver.session() );
+ }
+
+ private Result createNodes( int nodesToCreate, QueryRunner queryRunner )
+ {
+ return queryRunner.run( "UNWIND range(1, $nodesToCreate) AS i CREATE (n {index: i}) RETURN n",
+ parameters( "nodesToCreate", nodesToCreate ) );
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java
index 8ce2979f7c..9f4c77c002 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java
@@ -18,6 +18,7 @@
*/
package org.neo4j.driver.internal;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.netty.bootstrap.Bootstrap;
import io.netty.util.concurrent.EventExecutorGroup;
import org.junit.jupiter.api.Test;
@@ -25,6 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import java.net.URI;
+import java.util.Optional;
import java.util.stream.Stream;
import org.neo4j.driver.AuthToken;
@@ -32,6 +34,7 @@
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Logging;
+import org.neo4j.driver.MetricsAdapter;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.internal.async.LeakLoggingNetworkSession;
import org.neo4j.driver.internal.async.NetworkSession;
@@ -39,8 +42,10 @@
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.cluster.RoutingSettings;
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer;
+import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
import org.neo4j.driver.internal.metrics.InternalMetricsProvider;
import org.neo4j.driver.internal.metrics.MetricsProvider;
+import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider;
import org.neo4j.driver.internal.retry.RetryLogic;
import org.neo4j.driver.internal.retry.RetrySettings;
import org.neo4j.driver.internal.security.SecurityPlan;
@@ -51,6 +56,7 @@
import org.neo4j.driver.internal.util.Clock;
import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.junit.MatcherAssert.assertThat;
@@ -64,7 +70,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.neo4j.driver.Config.defaultConfig;
-import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER;
import static org.neo4j.driver.internal.util.Futures.completedWithNull;
import static org.neo4j.driver.internal.util.Futures.failedFuture;
import static org.neo4j.driver.internal.util.Matchers.clusterDriver;
@@ -152,9 +157,9 @@ void shouldNotCreateDriverMetrics()
Config config = mock( Config.class );
when( config.isMetricsEnabled() ).thenReturn( false );
// When
- MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM );
+ MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM );
// Then
- assertThat( provider, is( METRICS_DISABLED_PROVIDER ) );
+ assertThat( provider, is(equalTo( DevNullMetricsProvider.INSTANCE ) ) );
}
@Test
@@ -165,12 +170,25 @@ void shouldCreateDriverMetricsIfMonitoringEnabled()
when( config.isMetricsEnabled() ).thenReturn( true );
when( config.logging() ).thenReturn( Logging.none() );
// When
- MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM );
+ MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM );
// Then
- assertThat( provider.isMetricsEnabled(), is( true ) );
assertThat( provider instanceof InternalMetricsProvider, is( true ) );
}
+ @Test
+ void shouldCreateMicrometerDriverMetricsIfMonitoringEnabled()
+ {
+ // Given
+ Config config = mock( Config.class );
+ when( config.isMetricsEnabled() ).thenReturn( true );
+ when( config.metricsAdapter() ).thenReturn( MetricsAdapter.MICROMETER );
+ when( config.logging() ).thenReturn( Logging.none() );
+ // When
+ MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM );
+ // Then
+ assertThat( provider instanceof MicrometerMetricsProvider, is( true ) );
+ }
+
@ParameterizedTest
@MethodSource( "testUris" )
void shouldCreateAppropriateDriverType( String uri )
diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java
index 69af2458f1..4893526544 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java
@@ -24,22 +24,22 @@
import org.neo4j.driver.Config;
import org.neo4j.driver.Metrics;
+import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
+import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.exceptions.ServiceUnavailableException;
-import org.neo4j.driver.internal.metrics.InternalMetrics;
-import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.internal.security.SecurityPlanImpl;
import org.neo4j.driver.internal.util.Clock;
import static org.junit.Assert.assertTrue;
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.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
-import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER;
import static org.neo4j.driver.internal.util.Futures.completedWithNull;
import static org.neo4j.driver.internal.util.Futures.failedFuture;
import static org.neo4j.driver.util.TestUtil.await;
@@ -103,11 +103,11 @@ void shouldThrowClientExceptionIfMetricsNotEnabled() throws Throwable
ClientException error = assertThrows( ClientException.class, driver::metrics );
// Then
- assertTrue( error.getMessage().contains( "Driver metrics not enabled." ) );
+ assertTrue( error.getMessage().contains( "Driver metrics are not enabled." ) );
}
@Test
- void shouldReturnMetricsIfMetricsEnabled() throws Throwable
+ void shouldReturnMetricsIfMetricsEnabled()
{
// Given
InternalDriver driver = newDriver( true );
@@ -116,12 +116,12 @@ void shouldReturnMetricsIfMetricsEnabled() throws Throwable
Metrics metrics = driver.metrics();
// Then we shall have no problem to get the metrics
- assertTrue( metrics instanceof InternalMetrics );
+ assertNotNull( metrics );
}
private static InternalDriver newDriver( SessionFactory sessionFactory )
{
- return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, METRICS_DISABLED_PROVIDER, DEV_NULL_LOGGING );
+ return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, DevNullMetricsProvider.INSTANCE, DEV_NULL_LOGGING );
}
private static SessionFactory sessionFactoryMock()
@@ -140,7 +140,7 @@ private static InternalDriver newDriver( boolean isMetricsEnabled )
config = Config.builder().withDriverMetrics().build();
}
- MetricsProvider metricsProvider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM );
+ MetricsProvider metricsProvider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM );
return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, metricsProvider, DEV_NULL_LOGGING );
}
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/NetworkConnectionTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/NetworkConnectionTest.java
index a6fd53fc27..c67018f113 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/NetworkConnectionTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/NetworkConnectionTest.java
@@ -42,6 +42,7 @@
import org.neo4j.driver.internal.async.pool.ExtendedChannelPool;
import org.neo4j.driver.internal.handlers.NoOpResponseHandler;
import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.spi.ResponseHandler;
import org.neo4j.driver.internal.util.FakeClock;
import org.neo4j.driver.internal.util.ServerVersion;
@@ -63,7 +64,6 @@
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL;
import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.internal.util.Iterables.single;
import static org.neo4j.driver.util.DaemonThreadFactory.daemon;
import static org.neo4j.driver.util.TestUtil.DEFAULT_TEST_PROTOCOL_VERSION;
@@ -645,7 +645,7 @@ private static NetworkConnection newConnection( Channel channel )
private static NetworkConnection newConnection( Channel channel, ExtendedChannelPool pool )
{
- return new NetworkConnection( channel, pool, new FakeClock(), DEV_NULL_METRICS, DEV_NULL_LOGGING );
+ return new NetworkConnection( channel, pool, new FakeClock(), DevNullMetricsListener.INSTANCE, DEV_NULL_LOGGING );
}
private static void assertConnectionReleasedError( IllegalStateException e )
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplIT.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplIT.java
index 5c219e33fd..c3caebc761 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplIT.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplIT.java
@@ -35,6 +35,7 @@
import org.neo4j.driver.internal.async.connection.ChannelConnector;
import org.neo4j.driver.internal.async.connection.ChannelConnectorImpl;
import org.neo4j.driver.internal.cluster.RoutingContext;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.security.SecurityPlanImpl;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.util.FakeClock;
@@ -50,7 +51,6 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.util.TestUtil.await;
@ParallelizableIT
@@ -151,7 +151,7 @@ private ConnectionPoolImpl newPool() throws Exception
DEV_NULL_LOGGING, clock, RoutingContext.EMPTY, DefaultDomainNameResolver.getInstance() );
PoolSettings poolSettings = newSettings();
Bootstrap bootstrap = BootstrapFactory.newBootstrap( 1 );
- return new ConnectionPoolImpl( connector, bootstrap, poolSettings, DEV_NULL_METRICS, DEV_NULL_LOGGING, clock, true );
+ return new ConnectionPoolImpl( connector, bootstrap, poolSettings, DevNullMetricsListener.INSTANCE, DEV_NULL_LOGGING, clock, true );
}
private static PoolSettings newSettings()
{
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplTest.java
index d18aa10395..b49d6bec82 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImplTest.java
@@ -27,6 +27,7 @@
import java.util.concurrent.ExecutionException;
import org.neo4j.driver.internal.BoltServerAddress;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.util.FakeClock;
import static java.util.Arrays.asList;
@@ -41,7 +42,6 @@
import static org.neo4j.driver.internal.BoltServerAddress.LOCAL_DEFAULT;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.authorizationStateListener;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
class ConnectionPoolImplTest
{
@@ -144,7 +144,7 @@ private static TestConnectionPool newConnectionPool( NettyChannelTracker nettyCh
private static TestConnectionPool newConnectionPool( NettyChannelTracker nettyChannelTracker, NettyChannelHealthChecker nettyChannelHealthChecker )
{
- return new TestConnectionPool( mock( Bootstrap.class ), nettyChannelTracker, nettyChannelHealthChecker, newSettings(), DEV_NULL_METRICS,
+ return new TestConnectionPool( mock( Bootstrap.class ), nettyChannelTracker, nettyChannelHealthChecker, newSettings(), DevNullMetricsListener.INSTANCE,
DEV_NULL_LOGGING,
new FakeClock(), true );
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelPoolIT.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelPoolIT.java
index 52d8d935d6..63af5b70a2 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelPoolIT.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelPoolIT.java
@@ -39,6 +39,7 @@
import org.neo4j.driver.internal.async.connection.BootstrapFactory;
import org.neo4j.driver.internal.async.connection.ChannelConnectorImpl;
import org.neo4j.driver.internal.cluster.RoutingContext;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.security.InternalAuthToken;
import org.neo4j.driver.internal.security.SecurityPlanImpl;
import org.neo4j.driver.internal.util.FakeClock;
@@ -57,7 +58,6 @@
import static org.mockito.Mockito.verify;
import static org.neo4j.driver.Values.value;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.util.TestUtil.await;
@ParallelizableIT
@@ -156,7 +156,7 @@ void shouldLimitNumberOfConcurrentConnections() throws Exception
@Test
void shouldTrackActiveChannels() throws Exception
{
- NettyChannelTracker tracker = new NettyChannelTracker( DEV_NULL_METRICS, new ImmediateSchedulingEventExecutor(), DEV_NULL_LOGGING );
+ NettyChannelTracker tracker = new NettyChannelTracker( DevNullMetricsListener.INSTANCE, new ImmediateSchedulingEventExecutor(), DEV_NULL_LOGGING );
poolHandler = tracker;
pool = newPool( neo4j.authToken() );
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelTrackerTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelTrackerTest.java
index 0923db4aae..70612084e4 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelTrackerTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/NettyChannelTrackerTest.java
@@ -28,6 +28,7 @@
import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher;
import org.neo4j.driver.internal.messaging.request.GoodbyeMessage;
import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -41,12 +42,11 @@
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setProtocolVersion;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setServerAddress;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
class NettyChannelTrackerTest
{
private final BoltServerAddress address = BoltServerAddress.LOCAL_DEFAULT;
- private final NettyChannelTracker tracker = new NettyChannelTracker( DEV_NULL_METRICS, mock( ChannelGroup.class ), DEV_NULL_LOGGING );
+ private final NettyChannelTracker tracker = new NettyChannelTracker( DevNullMetricsListener.INSTANCE, mock( ChannelGroup.class ), DEV_NULL_LOGGING );
@Test
void shouldIncrementIdleCountWhenChannelCreated()
@@ -194,7 +194,7 @@ void shouldAddChannelToGroupWhenChannelCreated()
Channel channel = newChannel();
Channel anotherChannel = newChannel();
ChannelGroup group = mock( ChannelGroup.class );
- NettyChannelTracker tracker = new NettyChannelTracker( DEV_NULL_METRICS, group, DEV_NULL_LOGGING );
+ NettyChannelTracker tracker = new NettyChannelTracker( DevNullMetricsListener.INSTANCE, group, DEV_NULL_LOGGING );
tracker.channelCreated( channel, null );
tracker.channelCreated( anotherChannel, null );
@@ -211,7 +211,7 @@ void shouldDelegateToProtocolPrepareToClose()
ChannelGroup group = mock( ChannelGroup.class );
when( group.iterator() ).thenReturn( new Arrays.Iterator<>( new Channel[]{channel, anotherChannel} ) );
- NettyChannelTracker tracker = new NettyChannelTracker( DEV_NULL_METRICS, group, DEV_NULL_LOGGING );
+ NettyChannelTracker tracker = new NettyChannelTracker( DevNullMetricsListener.INSTANCE, group, DEV_NULL_LOGGING );
tracker.prepareToCloseChannels();
diff --git a/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/RoutingTableAndConnectionPoolTest.java b/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/RoutingTableAndConnectionPoolTest.java
index f11b5f487b..48356abf69 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/RoutingTableAndConnectionPoolTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/RoutingTableAndConnectionPoolTest.java
@@ -42,6 +42,7 @@
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
+import org.neo4j.driver.internal.metrics.MetricsListener;
import org.neo4j.driver.exceptions.FatalDiscoveryException;
import org.neo4j.driver.exceptions.ProtocolException;
import org.neo4j.driver.internal.BoltServerAddress;
@@ -57,7 +58,7 @@
import org.neo4j.driver.internal.cluster.RoutingTable;
import org.neo4j.driver.internal.cluster.RoutingTableRegistry;
import org.neo4j.driver.internal.cluster.RoutingTableRegistryImpl;
-import org.neo4j.driver.internal.metrics.InternalAbstractMetrics;
+import org.neo4j.driver.internal.metrics.DevNullMetricsListener;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.util.Clock;
@@ -77,7 +78,6 @@
import static org.neo4j.driver.internal.DatabaseNameUtil.database;
import static org.neo4j.driver.internal.cluster.RediscoveryUtil.contextWithDatabase;
import static org.neo4j.driver.internal.cluster.RoutingSettings.STALE_ROUTING_TABLE_PURGE_DELAY_MS;
-import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS;
import static org.neo4j.driver.util.TestUtil.await;
class RoutingTableAndConnectionPoolTest
@@ -323,7 +323,7 @@ private void acquireAndReleaseConnections( LoadBalancer loadBalancer ) throws In
private ConnectionPool newConnectionPool()
{
- InternalAbstractMetrics metrics = DEV_NULL_METRICS;
+ MetricsListener metrics = DevNullMetricsListener.INSTANCE;
PoolSettings poolSettings = new PoolSettings( 10, 5000, -1, -1 );
Bootstrap bootstrap = BootstrapFactory.newBootstrap( 1 );
NettyChannelTracker channelTracker = new NettyChannelTracker( metrics, bootstrap.config().group().next(), logging );
diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java
new file mode 100644
index 0000000000..ea9891b3c0
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntSupplier;
+
+import org.neo4j.driver.ConnectionPoolMetrics;
+import org.neo4j.driver.internal.BoltServerAddress;
+import org.neo4j.driver.internal.spi.ConnectionPool;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+
+class MicrometerConnectionPoolMetricsTest
+{
+ static final String ID = "id";
+
+ MicrometerConnectionPoolMetrics metrics;
+ BoltServerAddress address;
+ ConnectionPool pool;
+ MeterRegistry registry;
+ AtomicInteger inUse = new AtomicInteger(0);
+ IntSupplier inUseSupplier = inUse::get;
+ AtomicInteger idle = new AtomicInteger(0);
+ IntSupplier idleSupplier = idle::get;
+
+ @BeforeEach
+ void beforeEach()
+ {
+ address = new BoltServerAddress( "host", "127.0.0.1", 7687 );
+ pool = mock( ConnectionPool.class );
+ registry = new SimpleMeterRegistry();
+ metrics = new MicrometerConnectionPoolMetrics( ID, address, inUseSupplier, idleSupplier, registry );
+ }
+
+ @Test
+ void shouldIncrementCreatingAndStartTimerOnBeforeCreating()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.creating() ).willReturn( 1 );
+ ListenerEvent> event = mock( ListenerEvent.class );
+
+ // WHEN
+ metrics.beforeCreating( event );
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ then( event ).should().start();
+ }
+
+ @Test
+ void shouldIncrementFailedToCreateAndDecrementCreatingOnAfterFailedToCreate()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.failedToCreate() ).willReturn( 1L );
+ given( expectedMetrics.creating() ).willReturn( -1 );
+
+ // WHEN
+ metrics.afterFailedToCreate();
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ }
+
+ @Test
+ void shouldDecrementCreatingAndIncrementCreatedAndStopTimerOnAfterCreated()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.creating() ).willReturn( -1 );
+ given( expectedMetrics.created() ).willReturn( 1L );
+ Timer timer = registry.get( MicrometerConnectionPoolMetrics.CREATION ).timer();
+ long timerCount = timer.count();
+ MicrometerTimerListenerEvent event = new MicrometerTimerListenerEvent( registry );
+ event.start();
+
+ // WHEN
+ metrics.afterCreated( event );
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ assertEquals( timerCount + 1, timer.count() );
+ }
+
+ @Test
+ void shouldIncrementClosedOnAfterClosed()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.closed() ).willReturn( 1L );
+
+ // WHEN
+ metrics.afterClosed();
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ }
+
+ @Test
+ void shouldStartTimerAndIncrementAcquiringOnBeforeAcquiringOrCreating()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.acquiring() ).willReturn( 1 );
+
+ // WHEN
+ metrics.beforeAcquiringOrCreating( event );
+
+ // THEN
+ then( event ).should().start();
+ verifyMetrics( expectedMetrics, metrics );
+ }
+
+ @Test
+ void shouldDecrementAcquiringOnAfterAcquiringOrCreating()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.acquiring() ).willReturn( -1 );
+
+ // WHEN
+ metrics.afterAcquiringOrCreating();
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ }
+
+ @Test
+ void shouldIncrementAcquiredAndStopTimerOnAfterAcquiredOrCreated()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.acquired() ).willReturn( 1L );
+ Timer timer = registry.get( MicrometerConnectionPoolMetrics.ACQUISITION ).timer();
+ long timerCount = timer.count();
+ MicrometerTimerListenerEvent event = new MicrometerTimerListenerEvent( registry );
+ event.start();
+
+ // WHEN
+ metrics.afterAcquiredOrCreated( event );
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ assertEquals( timerCount + 1, timer.count() );
+ }
+
+ @Test
+ void shouldIncrementTimedOutToAcquireOnAfterTimedOutToAcquireOrCreate()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.timedOutToAcquire() ).willReturn( 1L );
+
+ // WHEN
+ metrics.afterTimedOutToAcquireOrCreate();
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ }
+
+ @Test
+ void shouldStartTimerOnAcquired()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+
+ // WHEN
+ metrics.acquired( event );
+
+ // THEN
+ then( event ).should().start();
+ }
+
+ @Test
+ void shouldIncrementReleasedAndStopTimerOnReleased()
+ {
+ // GIVEN
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.totalInUseCount() ).willReturn( 1L );
+ Timer timer = registry.get( MicrometerConnectionPoolMetrics.USAGE ).timer();
+ long timerCount = timer.count();
+ MicrometerTimerListenerEvent event = new MicrometerTimerListenerEvent( registry );
+ event.start();
+
+ // WHEN
+ metrics.released( event );
+
+ // THEN
+ verifyMetrics( expectedMetrics, metrics );
+ assertEquals( timerCount + 1, timer.count() );
+ }
+
+ @Test
+ void shouldUseInUseSupplier()
+ {
+ try
+ {
+ // GIVEN
+ int expected = 5;
+ inUse.compareAndSet( 0, expected );
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.inUse() ).willReturn( expected );
+
+ // WHEN
+ int actual = metrics.inUse();
+
+ // THEN
+ assertEquals( expected, actual );
+ verifyMetrics( expectedMetrics, metrics );
+ } finally
+ {
+ inUse.set( 0 );
+ }
+ }
+
+ @Test
+ void shouldUseIdleSupplier()
+ {
+ try
+ {
+ // GIVEN
+ int expected = 5;
+ idle.compareAndSet( 0, expected );
+ ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class );
+ given( expectedMetrics.idle() ).willReturn( expected );
+
+ // WHEN
+ int actual = metrics.idle();
+
+ // THEN
+ assertEquals( expected, actual );
+ verifyMetrics( expectedMetrics, metrics );
+ } finally
+ {
+ idle.set( 0 );
+ }
+ }
+
+ void verifyMetrics( ConnectionPoolMetrics expected, ConnectionPoolMetrics actual )
+ {
+ assertEquals( ID, actual.id() );
+ assertEquals( expected.inUse(), actual.inUse() );
+ assertEquals( expected.inUse(), registry.get( MicrometerConnectionPoolMetrics.IN_USE ).gauge().value() );
+ assertEquals( expected.idle(), actual.idle() );
+ assertEquals( expected.idle(), registry.get( MicrometerConnectionPoolMetrics.IDLE ).gauge().value() );
+ assertEquals( expected.creating(), actual.creating() );
+ assertEquals( expected.creating(), registry.get( MicrometerConnectionPoolMetrics.CREATING ).gauge().value() );
+ assertEquals( expected.created(), actual.created() );
+ assertEquals( expected.created(), registry.get( MicrometerConnectionPoolMetrics.CREATION ).timer().count() );
+ assertEquals( expected.failedToCreate(), actual.failedToCreate() );
+ assertEquals( expected.failedToCreate(), registry.get( MicrometerConnectionPoolMetrics.FAILED ).counter().count() );
+ assertEquals( expected.closed(), actual.closed() );
+ assertEquals( expected.closed(), registry.get( MicrometerConnectionPoolMetrics.CLOSED ).counter().count() );
+ assertEquals( expected.acquiring(), actual.acquiring() );
+ assertEquals( expected.acquiring(), registry.get( MicrometerConnectionPoolMetrics.ACQUIRING ).gauge().value() );
+ assertEquals( expected.acquired(), actual.acquired() );
+ assertEquals( expected.acquired(), registry.get( MicrometerConnectionPoolMetrics.ACQUISITION ).timer().count() );
+ assertEquals( expected.timedOutToAcquire(), actual.timedOutToAcquire() );
+ assertEquals( expected.timedOutToAcquire(), registry.get( MicrometerConnectionPoolMetrics.ACQUISITION_TIMEOUT ).counter().count() );
+ assertEquals( expected.totalAcquisitionTime(), actual.totalAcquisitionTime() );
+ assertEquals( expected.totalAcquisitionTime(),
+ (long) registry.get( MicrometerConnectionPoolMetrics.ACQUISITION ).timer().totalTime( TimeUnit.MILLISECONDS ) );
+ assertEquals( expected.totalConnectionTime(), actual.totalConnectionTime() );
+ assertEquals( expected.totalConnectionTime(),
+ (long) registry.get( MicrometerConnectionPoolMetrics.CREATION ).timer().totalTime( TimeUnit.MILLISECONDS ) );
+ assertEquals( expected.totalInUseTime(), actual.totalInUseTime() );
+ assertEquals( expected.totalInUseTime(), (long) registry.get( MicrometerConnectionPoolMetrics.USAGE ).timer().totalTime( TimeUnit.MILLISECONDS ) );
+ assertEquals( expected.totalInUseCount(), actual.totalInUseCount() );
+ assertEquals( expected.totalInUseCount(), registry.get( MicrometerConnectionPoolMetrics.USAGE ).timer().count() );
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java
new file mode 100644
index 0000000000..9d4a8bd694
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import org.neo4j.driver.Metrics;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class MicrometerMetricsProviderTest
+{
+ MetricsProvider provider;
+
+ @BeforeEach
+ void beforeEach()
+ {
+ provider = MicrometerMetricsProvider.forGlobalRegistry();
+ }
+
+ @Test
+ void shouldReturnMicrometerMetricsOnMetrics()
+ {
+ // GIVEN & WHEN
+ Metrics metrics = provider.metrics();
+
+ // THEN
+ assertTrue( metrics instanceof MicrometerMetrics );
+ }
+
+ @Test
+ void shouldReturnMicrometerMetricsOnMetricsListener()
+ {
+ // GIVEN & WHEN
+ MetricsListener listener = provider.metricsListener();
+
+ // THEN
+ assertTrue( listener instanceof MicrometerMetrics );
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java
new file mode 100644
index 0000000000..f4dae3fe02
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Collection;
+
+import org.neo4j.driver.ConnectionPoolMetrics;
+import org.neo4j.driver.internal.BoltServerAddress;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+
+class MicrometerMetricsTest
+{
+ static final String ID = "id";
+
+ MicrometerMetrics metrics;
+ MeterRegistry registry;
+ ConnectionPoolMetrics poolMetrics;
+ ConnectionPoolMetricsListener poolMetricsListener;
+
+ @BeforeEach
+ void beforeEach()
+ {
+ registry = new SimpleMeterRegistry();
+ metrics = new MicrometerMetrics( registry );
+ poolMetricsListener = mock( ConnectionPoolMetricsListener.class, Mockito.withSettings().extraInterfaces( ConnectionPoolMetrics.class ) );
+ poolMetrics = (ConnectionPoolMetrics) poolMetricsListener;
+ }
+
+ @Test
+ void shouldReturnEmptyConnectionPoolMetrics()
+ {
+ // GIVEN & WHEN
+ Collection collection = metrics.connectionPoolMetrics();
+
+ // THEN
+ assertTrue( collection.isEmpty() );
+ }
+
+ @Test
+ void shouldDelegateBeforeCreating()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.beforeCreating( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().beforeCreating( event );
+ }
+
+ @Test
+ void shouldDelegateAfterCreated()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterCreated( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterCreated( event );
+ }
+
+ @Test
+ void shouldDelegateAfterFailedToCreate()
+ {
+ // GIVEN
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterFailedToCreate( ID );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterFailedToCreate();
+ }
+
+ @Test
+ void shouldDelegateAfterClosed()
+ {
+ // GIVEN
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterClosed( ID );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterClosed();
+ }
+
+ @Test
+ void shouldDelegateBeforeAcquiringOrCreating()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.beforeAcquiringOrCreating( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().beforeAcquiringOrCreating( event );
+ }
+
+ @Test
+ void shouldDelegateAfterAcquiringOrCreating()
+ {
+ // GIVEN
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterAcquiringOrCreating( ID );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterAcquiringOrCreating();
+ }
+
+ @Test
+ void shouldDelegateAfterAcquiredOrCreated()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterAcquiredOrCreated( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterAcquiredOrCreated( event );
+ }
+
+ @Test
+ void shouldDelegateAfterTimedOutToAcquireOrCreate()
+ {
+ // GIVEN
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterTimedOutToAcquireOrCreate( ID );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().afterTimedOutToAcquireOrCreate();
+ }
+
+ @Test
+ void shouldDelegateAfterConnectionCreated()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterConnectionCreated( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().acquired( event );
+ }
+
+ @Test
+ void shouldDelegateAfterConnectionReleased()
+ {
+ // GIVEN
+ ListenerEvent> event = mock( ListenerEvent.class );
+ metrics.putPoolMetrics( ID, poolMetrics );
+
+ // WHEN
+ metrics.afterConnectionReleased( ID, event );
+
+ // THEN
+ assertEquals( 1, metrics.connectionPoolMetrics().size() );
+ then( poolMetricsListener ).should().released( event );
+ }
+
+ @Test
+ void shouldCreateListenerEvent()
+ {
+ // GIVEN & WHEN
+ ListenerEvent> event = metrics.createListenerEvent();
+
+ // THEN
+ assertTrue( event instanceof MicrometerTimerListenerEvent );
+ }
+
+ @Test
+ void shouldPutPoolMetrics()
+ {
+ // GIVEN
+ int size = metrics.connectionPoolMetrics().size();
+
+ // WHEN
+ metrics.registerPoolMetrics( ID, BoltServerAddress.LOCAL_DEFAULT, () -> 23, () -> 42 );
+
+ // THEN
+ assertEquals( size + 1, metrics.connectionPoolMetrics().size() );
+ }
+
+ @Test
+ void shouldRemovePoolMetrics()
+ {
+ // GIVEN
+ metrics.putPoolMetrics( ID, poolMetrics );
+ int size = metrics.connectionPoolMetrics().size();
+
+ // WHEN
+ metrics.removePoolMetrics( ID );
+
+ // THEN
+ assertEquals( size - 1, metrics.connectionPoolMetrics().size() );
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java
new file mode 100644
index 0000000000..4513ae532b
--- /dev/null
+++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.neo4j.driver.internal.metrics;
+
+import io.micrometer.core.instrument.Timer;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class MicrometerTimerListenerEventTest
+{
+ MicrometerTimerListenerEvent event;
+
+ @BeforeEach
+ void beforeEach()
+ {
+ event = new MicrometerTimerListenerEvent( new SimpleMeterRegistry() );
+ }
+
+ @Test
+ void shouldCreateTimerSampleOnStartAndReturnOnGetSample()
+ {
+ // GIVEN
+ Timer.Sample initialSample = event.getSample();
+
+ // WHEN
+ event.start();
+
+ // THEN
+ Timer.Sample sample = event.getSample();
+ assertNull( initialSample );
+ assertNotNull( sample );
+ }
+}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java b/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java
index 57bb9b3c5b..a9790538a9 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java
@@ -27,16 +27,17 @@
import org.neo4j.driver.AuthToken;
import org.neo4j.driver.Config;
+import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.DriverFactory;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.messaging.Message;
-import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.internal.security.SecurityPlan;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.spi.ResponseHandler;
+import org.neo4j.driver.net.ServerAddress;
public class FailingConnectionDriverFactory extends DriverFactory
{
@@ -82,13 +83,13 @@ public void retainAll( Set addressesToRetain )
}
@Override
- public int inUseConnections( BoltServerAddress address )
+ public int inUseConnections( ServerAddress address )
{
return delegate.inUseConnections( address );
}
@Override
- public int idleConnections( BoltServerAddress address )
+ public int idleConnections( ServerAddress address )
{
return delegate.idleConnections( address );
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/io/ChannelTrackingDriverFactory.java b/driver/src/test/java/org/neo4j/driver/internal/util/io/ChannelTrackingDriverFactory.java
index cad9053fd3..893ddc28fe 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/util/io/ChannelTrackingDriverFactory.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/util/io/ChannelTrackingDriverFactory.java
@@ -25,6 +25,8 @@
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.neo4j.driver.AuthToken;
+import org.neo4j.driver.Config;
import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.ConnectionSettings;
import org.neo4j.driver.internal.async.connection.BootstrapFactory;
@@ -35,8 +37,6 @@
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.util.Clock;
import org.neo4j.driver.internal.util.DriverFactoryWithClock;
-import org.neo4j.driver.AuthToken;
-import org.neo4j.driver.Config;
public class ChannelTrackingDriverFactory extends DriverFactoryWithClock
{
diff --git a/pom.xml b/pom.xml
index e3687223aa..44d053c697 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,7 @@
2.13.1
1.18.22
21.3.1
+ 1.8.2
@@ -119,6 +120,12 @@
slf4j-api
${slf4j-api.version}
+