From e2a4e733b296e7a7e12f12c4cf10cac12b18f268 Mon Sep 17 00:00:00 2001 From: Tommy Ludwig <8924140+shakuzen@users.noreply.github.com> Date: Wed, 15 Dec 2021 01:06:07 +0900 Subject: [PATCH 01/24] [WIP] Micrometer metrics instrumentation This is a work-in-progress attempt at instrumenting the driver with Micrometer as an optional alternative metrics implementation to the existing internal one. --- bundle/pom.xml | 5 + driver/pom.xml | 5 + .../main/java/org/neo4j/driver/Config.java | 15 +- .../MicrometerConnectionPoolMetrics.java | 215 ++++++++++++++++++ .../internal/metrics/MicrometerMetrics.java | 175 ++++++++++++++ .../metrics/MicrometerMetricsProvider.java | 48 ++++ .../metrics/MicrometerTimerListenerEvent.java | 47 ++++ .../neo4j/driver/integration/MetricsIT.java | 86 +++++++ ...eterConnectionPoolMetricsListenerTest.java | 23 ++ pom.xml | 6 + 10 files changed, 624 insertions(+), 1 deletion(-) create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java create mode 100644 driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java diff --git a/bundle/pom.xml b/bundle/pom.xml index 7fcc84bfec..90f06abfaa 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -37,6 +37,11 @@ slf4j-api true + + io.micrometer + micrometer-core + true + org.graalvm.nativeimage svm diff --git a/driver/pom.xml b/driver/pom.xml index d2e9e8cfb6..c0ac6cbec1 100644 --- a/driver/pom.xml +++ b/driver/pom.xml @@ -37,6 +37,11 @@ + + io.micrometer + micrometer-core + true + 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 4a5398225e..9f86f18d71 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -30,7 +30,10 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil; +import org.neo4j.driver.internal.metrics.InternalMetricsProvider; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.retry.RetrySettings; +import org.neo4j.driver.internal.util.Clock; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.Immutable; @@ -699,11 +702,21 @@ public ConfigBuilder withResolver( ServerAddressResolver resolver ) } /** - * Enable driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}. + * Enable the default driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}. * @return this builder. */ public ConfigBuilder withDriverMetrics() { + return withDriverMetrics(new InternalMetricsProvider(Clock.SYSTEM, this.logging)); + } + + /** + * Enable driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}. + * @param provider which implementation of metrics to use + * @return this builder. + */ + // TODO Figure out how a user configures a different metrics implementation + public ConfigBuilder withDriverMetrics(MetricsProvider provider) { this.isMetricsEnabled = true; return this; } 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..d9788664ec --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -0,0 +1,215 @@ +/* + * 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.*; +import org.neo4j.driver.ConnectionPoolMetrics; +import org.neo4j.driver.internal.BoltServerAddress; +import org.neo4j.driver.internal.spi.ConnectionPool; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsListener, ConnectionPoolMetrics +{ + private static final String PREFIX = "neo4j.driver.connections"; + + // address and pool are not used. + private final BoltServerAddress address; + private final ConnectionPool pool; + + private final Counter closed; + + // creating = created + failedToCreate + private final AtomicInteger creating = new AtomicInteger(); + private final Counter failedToCreate; + + // acquiring = acquired + timedOutToAcquire + failedToAcquireDueToOtherFailures (which we do not keep track) + private final AtomicInteger acquiring = new AtomicInteger(); + private final Counter timedOutToAcquire; + + private final String id; + private final MeterRegistry registry; + private final Iterable tags; + + MicrometerConnectionPoolMetrics(String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry ) + { + this(poolId, address, pool, registry, Tags.empty()); + } + + MicrometerConnectionPoolMetrics(String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry, Iterable tags ) { + Objects.requireNonNull( address ); + Objects.requireNonNull( pool ); + Objects.requireNonNull( registry ); + + this.id = poolId; + this.address = address; + this.pool = pool; + this.registry = registry; + this.tags = Tags.concat(tags, "poolId", poolId); + + Gauge.builder(PREFIX + ".creating", creating, AtomicInteger::get).tags(this.tags).register(this.registry); + Gauge.builder(PREFIX + ".acquiring", acquiring, AtomicInteger::get).tags(this.tags).register(this.registry); + failedToCreate = Counter.builder(PREFIX + ".failed").tags(this.tags).register(this.registry); + timedOutToAcquire = Counter.builder(PREFIX + ".acquisition.timeout").tags(this.tags).register(this.registry); + closed = Counter.builder(PREFIX + ".closed").tags(this.tags).register(this.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(Timer.builder(PREFIX + ".creation").tags(this.tags).register(this.registry)); + } + + @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(); + // We can't time failed acquisitions currently + // Same for creation Timer and in-use Timer + sample.stop(Timer.builder(PREFIX + ".acquisition").tags(this.tags).register(this.registry)); + } + + @Override + public void afterTimedOutToAcquireOrCreate() + { + // if we could access the ListenerEvent here, we could use the Timer with acquisition timeouts + timedOutToAcquire.increment(); + } + + @Override + public void acquired( ListenerEvent inUseEvent ) + { + inUseEvent.start(); + } + + @Override + public void released( ListenerEvent inUseEvent ) + { + Timer.Sample sample = ((MicrometerTimerListenerEvent) inUseEvent).getSample(); + sample.stop(Timer.builder(PREFIX + ".usage").tags(this.tags).register(registry)); + } + + @Override + public String id() { + return this.id; + } + + // no-ops below here + @Override + public int inUse() { + return 0; + } + + @Override + public int idle() { + return 0; + } + + @Override + public int creating() { + return 0; + } + + @Override + public long created() { + return 0; + } + + @Override + public long failedToCreate() { + return 0; + } + + @Override + public long closed() { + return 0; + } + + @Override + public int acquiring() { + return 0; + } + + @Override + public long acquired() { + return 0; + } + + @Override + public long timedOutToAcquire() { + return 0; + } + + @Override + public long totalAcquisitionTime() { + return 0; + } + + @Override + public long totalConnectionTime() { + return 0; + } + + @Override + public long totalInUseTime() { + return 0; + } + + @Override + public long totalInUseCount() { + return 0; + } +} 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..f245f6467d --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java @@ -0,0 +1,175 @@ +/* + * 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.ConnectionPoolMetrics; +import org.neo4j.driver.Metrics; +import org.neo4j.driver.internal.BoltServerAddress; +import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public 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) { + poolMetrics(poolId).beforeCreating(creatingEvent); + } + + @Override + public void afterCreated(String poolId, ListenerEvent creatingEvent) { + poolMetrics(poolId).afterCreated(creatingEvent); + } + + @Override + public void afterFailedToCreate(String poolId) { + poolMetrics(poolId).afterFailedToCreate(); + } + + @Override + public void afterClosed(String poolId) { + poolMetrics(poolId).afterClosed(); + } + + @Override + public void beforeAcquiringOrCreating(String poolId, ListenerEvent acquireEvent) { + poolMetrics(poolId).beforeAcquiringOrCreating(acquireEvent); + } + + @Override + public void afterAcquiringOrCreating(String poolId) { + poolMetrics(poolId).afterAcquiringOrCreating(); + } + + @Override + public void afterAcquiredOrCreated(String poolId, ListenerEvent acquireEvent) { + poolMetrics(poolId).afterAcquiredOrCreated(acquireEvent); + } + + @Override + public void afterTimedOutToAcquireOrCreate(String poolId) { + poolMetrics(poolId).afterTimedOutToAcquireOrCreate(); + } + + @Override + public void afterConnectionCreated(String poolId, ListenerEvent inUseEvent) { + poolMetrics(poolId).acquired(inUseEvent); + } + + @Override + public void afterConnectionReleased(String poolId, ListenerEvent inUseEvent) { + poolMetrics(poolId).released(inUseEvent); + } + + @Override + public ListenerEvent createListenerEvent() { + return new MicrometerTimerListenerEvent(this.meterRegistry); + } + + @Override + public void putPoolMetrics(String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool) { + this.connectionPoolMetrics.put(poolId, new MicrometerConnectionPoolMetrics(poolId, address, connectionPool, this.meterRegistry)); + } + + @Override + public void removePoolMetrics(String poolId) { + // TODO should we unregister metrics registered for this poolId? + this.connectionPoolMetrics.remove(poolId); + } + + private ConnectionPoolMetricsListener poolMetrics( String poolId ) + { + InternalConnectionPoolMetrics poolMetrics = (InternalConnectionPoolMetrics) this.connectionPoolMetrics.get( poolId ); + if ( poolMetrics == null ) + { + return DEV_NULL_POOL_METRICS_LISTENER; + } + return poolMetrics; + } + + 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 ) + { + } + }; +} 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..eececa2c00 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java @@ -0,0 +1,48 @@ +/* + * 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; + +public class MicrometerMetricsProvider implements MetricsProvider { + + private final MeterRegistry meterRegistry; + private final MicrometerMetrics metrics; + + public MicrometerMetricsProvider(MeterRegistry meterRegistry) { + this.meterRegistry = meterRegistry; + this.metrics = new MicrometerMetrics(this.meterRegistry); + } + + @Override + public Metrics metrics() { + return this.metrics; + } + + @Override + public MetricsListener metricsListener() { + return this.metrics; + } + + @Override + public boolean isMetricsEnabled() { + return true; + } +} 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..75470f9f99 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java @@ -0,0 +1,47 @@ +/* + * 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; + +public 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); + } + + public Timer.Sample getSample() { + return this.sample; + } + + @Override + public long elapsed() { + // Micrometer Timer Sample does not provide API to get elapsed time + return 0; + } +} 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..c2b85d4ce1 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java @@ -0,0 +1,86 @@ +/* + * 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.*; +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().withDriverMetrics(new MicrometerMetricsProvider(meterRegistry)).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/metrics/MicrometerConnectionPoolMetricsListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java new file mode 100644 index 0000000000..7c711f6840 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java @@ -0,0 +1,23 @@ +/* + * 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; + +class MicrometerConnectionPoolMetricsListenerTest { + +} diff --git a/pom.xml b/pom.xml index 157fa4f0b4..f138a1e822 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,7 @@ 2.13.0 1.18.22 20.3.4 + 1.8.1 @@ -119,6 +120,11 @@ slf4j-api ${slf4j-api.version} + + io.micrometer + micrometer-core + ${micrometer.version} + From bd80f3895ed1c3ff4e76c0b9509a9f5a1361a0c9 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Wed, 19 Jan 2022 14:40:16 +0100 Subject: [PATCH 02/24] Bring it to life. --- .../main/java/org/neo4j/driver/Config.java | 6 +++ .../neo4j/driver/ConnectionPoolMetrics.java | 2 +- .../neo4j/driver/internal/DriverFactory.java | 2 +- .../MicrometerConnectionPoolMetrics.java | 51 ++++++++++++------- .../internal/metrics/MicrometerMetrics.java | 26 +++++----- .../metrics/MicrometerTimerListenerEvent.java | 1 + 6 files changed, 56 insertions(+), 32 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index 9f86f18d71..78cbd161c2 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -98,6 +98,7 @@ public class Config implements Serializable private final boolean isMetricsEnabled; private final int eventLoopThreads; private final String userAgent; + private final MetricsProvider metricsProvider; private Config( ConfigBuilder builder ) { @@ -122,6 +123,7 @@ private Config( ConfigBuilder builder ) this.eventLoopThreads = builder.eventLoopThreads; this.isMetricsEnabled = builder.isMetricsEnabled; + this.metricsProvider = builder.metricsProvider; } /** @@ -262,6 +264,8 @@ public boolean isMetricsEnabled() return isMetricsEnabled; } + public MetricsProvider metricsProvider() { return metricsProvider; } + /** * @return the user_agent configured for this driver */ @@ -292,6 +296,7 @@ public static class ConfigBuilder private boolean isMetricsEnabled = false; private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE; private int eventLoopThreads = 0; + private MetricsProvider metricsProvider; private ConfigBuilder() {} @@ -717,6 +722,7 @@ public ConfigBuilder withDriverMetrics() */ // TODO Figure out how a user configures a different metrics implementation public ConfigBuilder withDriverMetrics(MetricsProvider provider) { + this.metricsProvider = provider; this.isMetricsEnabled = true; 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..2ca7132283 100644 --- a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java @@ -59,7 +59,7 @@ public interface ConnectionPoolMetrics /** * A counter to record how many connections have been successfully created with this pool since the pool is 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 has ever been created by this pool. */ long created(); 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..d69913441d 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java @@ -118,7 +118,7 @@ protected static MetricsProvider createDriverMetrics( Config config, Clock clock { if( config.isMetricsEnabled() ) { - return new InternalMetricsProvider( clock, config.logging() ); + return config.metricsProvider(); } else { 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 index d9788664ec..f6101a3c72 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -37,13 +37,18 @@ public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsLis private final Counter closed; - // creating = created + failedToCreate private final AtomicInteger creating = new AtomicInteger(); private final Counter failedToCreate; + private final Counter created; // acquiring = acquired + timedOutToAcquire + failedToAcquireDueToOtherFailures (which we do not keep track) private final AtomicInteger acquiring = new AtomicInteger(); private final Counter timedOutToAcquire; + private final AtomicLong totalAcquisitionTime = new AtomicLong(); + private final AtomicLong totalConnectionTime = new AtomicLong(); + private final AtomicLong totalInUseTime = new AtomicLong(); + private final Counter acquired; + private final Counter totalInUse; private final String id; private final MeterRegistry registry; @@ -67,9 +72,15 @@ public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsLis Gauge.builder(PREFIX + ".creating", creating, AtomicInteger::get).tags(this.tags).register(this.registry); Gauge.builder(PREFIX + ".acquiring", acquiring, AtomicInteger::get).tags(this.tags).register(this.registry); + Gauge.builder(PREFIX + ".inUse", this::inUse).tags(this.tags).register(this.registry); + Gauge.builder(PREFIX + ".idle", this::idle).tags(this.tags).register(this.registry); + failedToCreate = Counter.builder(PREFIX + ".failed").tags(this.tags).register(this.registry); timedOutToAcquire = Counter.builder(PREFIX + ".acquisition.timeout").tags(this.tags).register(this.registry); closed = Counter.builder(PREFIX + ".closed").tags(this.tags).register(this.registry); + created = Counter.builder(PREFIX + ".created").tags(this.tags).register(this.registry); + acquired = Counter.builder(PREFIX + ".acquired").tags(this.tags).register(this.registry); + totalInUse = Counter.builder(PREFIX + ".inUse").tags(this.tags).register(this.registry); } @Override @@ -90,8 +101,10 @@ public void afterFailedToCreate() public void afterCreated( ListenerEvent connEvent ) { creating.decrementAndGet(); + created.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) connEvent).getSample(); - sample.stop(Timer.builder(PREFIX + ".creation").tags(this.tags).register(this.registry)); + long elapsed = sample.stop(Timer.builder(PREFIX + ".creation").tags(this.tags).register(this.registry)); + totalConnectionTime.addAndGet( elapsed ); } @Override @@ -116,10 +129,12 @@ public void afterAcquiringOrCreating() @Override public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) { + acquired.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) acquireEvent).getSample(); // We can't time failed acquisitions currently // Same for creation Timer and in-use Timer - sample.stop(Timer.builder(PREFIX + ".acquisition").tags(this.tags).register(this.registry)); + long elapsed = sample.stop(Timer.builder(PREFIX + ".acquisition").tags(this.tags).register(this.registry)); + totalAcquisitionTime.addAndGet(elapsed); } @Override @@ -138,8 +153,10 @@ public void acquired( ListenerEvent inUseEvent ) @Override public void released( ListenerEvent inUseEvent ) { + totalInUse.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) inUseEvent).getSample(); - sample.stop(Timer.builder(PREFIX + ".usage").tags(this.tags).register(registry)); + long elapsed = sample.stop(Timer.builder(PREFIX + ".usage").tags(this.tags).register(registry)); + totalInUseTime.addAndGet( elapsed ); } @Override @@ -150,66 +167,66 @@ public String id() { // no-ops below here @Override public int inUse() { - return 0; + return pool.inUseConnections(address); } @Override public int idle() { - return 0; + return pool.idleConnections(address); } @Override public int creating() { - return 0; + return creating.get(); } @Override public long created() { - return 0; + return ((Double) created.count()).longValue(); } @Override public long failedToCreate() { - return 0; + return ((Double) failedToCreate.count()).longValue(); } @Override public long closed() { - return 0; + return ((Double) closed.count()).longValue(); } @Override public int acquiring() { - return 0; + return acquiring.get(); } @Override public long acquired() { - return 0; + return ((Double) acquired.count()).longValue(); } @Override public long timedOutToAcquire() { - return 0; + return ((Double) timedOutToAcquire.count()).longValue(); } @Override public long totalAcquisitionTime() { - return 0; + return totalAcquisitionTime.get(); } @Override public long totalConnectionTime() { - return 0; + return totalConnectionTime.get(); } @Override public long totalInUseTime() { - return 0; + return totalInUseTime.get(); } @Override public long totalInUseCount() { - return 0; + return ((Double) totalInUse.count()).longValue(); } } 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 index f245f6467d..08cc63ffa6 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java @@ -32,7 +32,7 @@ public class MicrometerMetrics implements Metrics, MetricsListener { private final MeterRegistry meterRegistry; - private final Map connectionPoolMetrics; + private final Map connectionPoolMetrics; public MicrometerMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; @@ -46,52 +46,52 @@ public Collection connectionPoolMetrics() { @Override public void beforeCreating(String poolId, ListenerEvent creatingEvent) { - poolMetrics(poolId).beforeCreating(creatingEvent); + poolMetricsListener(poolId).beforeCreating(creatingEvent); } @Override public void afterCreated(String poolId, ListenerEvent creatingEvent) { - poolMetrics(poolId).afterCreated(creatingEvent); + poolMetricsListener(poolId).afterCreated(creatingEvent); } @Override public void afterFailedToCreate(String poolId) { - poolMetrics(poolId).afterFailedToCreate(); + poolMetricsListener(poolId).afterFailedToCreate(); } @Override public void afterClosed(String poolId) { - poolMetrics(poolId).afterClosed(); + poolMetricsListener(poolId).afterClosed(); } @Override public void beforeAcquiringOrCreating(String poolId, ListenerEvent acquireEvent) { - poolMetrics(poolId).beforeAcquiringOrCreating(acquireEvent); + poolMetricsListener(poolId).beforeAcquiringOrCreating(acquireEvent); } @Override public void afterAcquiringOrCreating(String poolId) { - poolMetrics(poolId).afterAcquiringOrCreating(); + poolMetricsListener(poolId).afterAcquiringOrCreating(); } @Override public void afterAcquiredOrCreated(String poolId, ListenerEvent acquireEvent) { - poolMetrics(poolId).afterAcquiredOrCreated(acquireEvent); + poolMetricsListener(poolId).afterAcquiredOrCreated(acquireEvent); } @Override public void afterTimedOutToAcquireOrCreate(String poolId) { - poolMetrics(poolId).afterTimedOutToAcquireOrCreate(); + poolMetricsListener(poolId).afterTimedOutToAcquireOrCreate(); } @Override public void afterConnectionCreated(String poolId, ListenerEvent inUseEvent) { - poolMetrics(poolId).acquired(inUseEvent); + poolMetricsListener(poolId).acquired(inUseEvent); } @Override public void afterConnectionReleased(String poolId, ListenerEvent inUseEvent) { - poolMetrics(poolId).released(inUseEvent); + poolMetricsListener(poolId).released(inUseEvent); } @Override @@ -110,9 +110,9 @@ public void removePoolMetrics(String poolId) { this.connectionPoolMetrics.remove(poolId); } - private ConnectionPoolMetricsListener poolMetrics( String poolId ) + private ConnectionPoolMetricsListener poolMetricsListener(String poolId ) { - InternalConnectionPoolMetrics poolMetrics = (InternalConnectionPoolMetrics) this.connectionPoolMetrics.get( poolId ); + ConnectionPoolMetricsListener poolMetrics = (ConnectionPoolMetricsListener) this.connectionPoolMetrics.get( poolId ); if ( poolMetrics == null ) { return DEV_NULL_POOL_METRICS_LISTENER; 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 index 75470f9f99..e6cf35bb0b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java @@ -42,6 +42,7 @@ public Timer.Sample getSample() { @Override public long elapsed() { // Micrometer Timer Sample does not provide API to get elapsed time + // and it is not needed right now return 0; } } From ce3af7eb4f36b4d53648e63492a4d2313606ab1b Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Tue, 25 Jan 2022 17:06:53 +0200 Subject: [PATCH 03/24] Update Micrometer metrics This update includes general improvements, refactorings and tests. --- .../main/java/org/neo4j/driver/Config.java | 33 +- .../neo4j/driver/ConnectionPoolMetrics.java | 5 +- .../neo4j/driver/internal/DriverFactory.java | 5 +- .../ConnectionPoolMetricsListener.java | 28 +- .../metrics/InternalAbstractMetrics.java | 14 +- .../InternalConnectionPoolMetrics.java | 24 +- .../internal/metrics/InternalMetrics.java | 14 +- .../internal/metrics/ListenerEvent.java | 11 +- .../internal/metrics/MetricsListener.java | 32 +- .../MicrometerConnectionPoolMetrics.java | 198 +++++++----- .../internal/metrics/MicrometerMetrics.java | 107 ++++--- .../metrics/MicrometerMetricsProvider.java | 21 +- .../metrics/MicrometerTimerListenerEvent.java | 23 +- .../metrics/TimeRecorderListenerEvent.java | 6 +- .../java/org/neo4j/driver/ConfigTest.java | 37 ++- .../neo4j/driver/integration/MetricsIT.java | 38 +-- .../driver/internal/DriverFactoryTest.java | 20 ++ ...eterConnectionPoolMetricsListenerTest.java | 23 -- .../MicrometerConnectionPoolMetricsTest.java | 284 ++++++++++++++++++ .../MicrometerMetricsProviderTest.java | 69 +++++ .../metrics/MicrometerMetricsTest.java | 248 +++++++++++++++ .../MicrometerTimerListenerEventTest.java | 53 ++++ 22 files changed, 1035 insertions(+), 258 deletions(-) delete mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index 78cbd161c2..d7d2db57a8 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -18,10 +18,13 @@ */ package org.neo4j.driver; +import io.micrometer.core.instrument.MeterRegistry; + import java.io.File; import java.io.Serializable; import java.net.InetAddress; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -30,11 +33,9 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil; -import org.neo4j.driver.internal.metrics.InternalMetricsProvider; -import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.retry.RetrySettings; -import org.neo4j.driver.internal.util.Clock; import org.neo4j.driver.net.ServerAddressResolver; +import org.neo4j.driver.util.Experimental; import org.neo4j.driver.util.Immutable; import static java.lang.String.format; @@ -98,7 +99,7 @@ public class Config implements Serializable private final boolean isMetricsEnabled; private final int eventLoopThreads; private final String userAgent; - private final MetricsProvider metricsProvider; + private final MeterRegistry meterRegistry; private Config( ConfigBuilder builder ) { @@ -123,7 +124,7 @@ private Config( ConfigBuilder builder ) this.eventLoopThreads = builder.eventLoopThreads; this.isMetricsEnabled = builder.isMetricsEnabled; - this.metricsProvider = builder.metricsProvider; + this.meterRegistry = builder.meterRegistry; } /** @@ -264,7 +265,10 @@ public boolean isMetricsEnabled() return isMetricsEnabled; } - public MetricsProvider metricsProvider() { return metricsProvider; } + public Optional meterRegistry() + { + return Optional.ofNullable( meterRegistry ); + } /** * @return the user_agent configured for this driver @@ -296,7 +300,7 @@ public static class ConfigBuilder private boolean isMetricsEnabled = false; private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE; private int eventLoopThreads = 0; - private MetricsProvider metricsProvider; + private MeterRegistry meterRegistry; private ConfigBuilder() {} @@ -712,17 +716,22 @@ public ConfigBuilder withResolver( ServerAddressResolver resolver ) */ public ConfigBuilder withDriverMetrics() { - return withDriverMetrics(new InternalMetricsProvider(Clock.SYSTEM, this.logging)); + this.isMetricsEnabled = true; + return this; } /** * Enable driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}. - * @param provider which implementation of metrics to use + *

+ * You must have Micrometer on classpath to use this option. + * + * @param meterRegistry meter registry to register metrics with * @return this builder. */ - // TODO Figure out how a user configures a different metrics implementation - public ConfigBuilder withDriverMetrics(MetricsProvider provider) { - this.metricsProvider = provider; + @Experimental + public ConfigBuilder withMicrometerDriverMetrics( MeterRegistry meterRegistry ) + { + this.meterRegistry = Objects.requireNonNull( meterRegistry, "meterRegistry" ); this.isMetricsEnabled = true; 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 2ca7132283..dd5eafc189 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(); 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 d69913441d..2609d27e7c 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java @@ -44,6 +44,7 @@ import org.neo4j.driver.internal.logging.NettyLogging; 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; @@ -118,7 +119,9 @@ protected static MetricsProvider createDriverMetrics( Config config, Clock clock { if( config.isMetricsEnabled() ) { - return config.metricsProvider(); + return config.meterRegistry() + .map( MicrometerMetricsProvider::new ) + .orElseGet( () -> new InternalMetricsProvider( Clock.SYSTEM, config.logging() ) ); } else { 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..c73d27b7c2 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 @@ -23,12 +23,12 @@ public 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,26 +66,28 @@ 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 ); + void released( ListenerEvent inUseEvent ); ConnectionPoolMetricsListener DEV_NULL_POOL_METRICS_LISTENER = new ConnectionPoolMetricsListener() { @Override - public void beforeCreating( ListenerEvent listenerEvent ) + public void beforeCreating( ListenerEvent listenerEvent ) { } @Override - public void afterCreated( ListenerEvent listenerEvent ) + public void afterCreated( ListenerEvent listenerEvent ) { } @@ -101,7 +105,7 @@ public void afterClosed() } @Override - public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) + public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) { } @@ -113,7 +117,7 @@ public void afterAcquiringOrCreating() } @Override - public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) + public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) { } @@ -125,13 +129,13 @@ public void afterTimedOutToAcquireOrCreate() } @Override - public void acquired( ListenerEvent inUseEvent ) + public void acquired( ListenerEvent inUseEvent ) { } @Override - public void released( ListenerEvent inUseEvent ) + 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 index 88eba87128..1c785d699e 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java @@ -32,13 +32,13 @@ public abstract class InternalAbstractMetrics implements Metrics, MetricsListene { @Override - public void beforeCreating( String poolId, ListenerEvent creatingEvent ) + public void beforeCreating( String poolId, ListenerEvent creatingEvent ) { } @Override - public void afterCreated( String poolId, ListenerEvent creatingEvent ) + public void afterCreated( String poolId, ListenerEvent creatingEvent ) { } @@ -56,7 +56,7 @@ public void afterClosed( String poolId ) } @Override - public void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent ) + public void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent ) { } @@ -68,7 +68,7 @@ public void afterAcquiringOrCreating( String poolId ) } @Override - public void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent ) + public void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent ) { } @@ -80,19 +80,19 @@ public void afterTimedOutToAcquireOrCreate( String poolId ) } @Override - public void afterConnectionCreated( String poolId, ListenerEvent inUseEvent ) + public void afterConnectionCreated( String poolId, ListenerEvent inUseEvent ) { } @Override - public void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ) + public void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ) { } @Override - public ListenerEvent createListenerEvent() + public ListenerEvent createListenerEvent() { return ListenerEvent.DEV_NULL_LISTENER_EVENT; } 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..35b332418b 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 @@ -63,7 +63,7 @@ public class InternalConnectionPoolMetrics implements ConnectionPoolMetrics, Con } @Override - public void beforeCreating( ListenerEvent connEvent ) + public void beforeCreating( ListenerEvent connEvent ) { creating.incrementAndGet(); connEvent.start(); @@ -77,13 +77,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 +93,7 @@ public void afterClosed() } @Override - public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) + public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) { acquireEvent.start(); acquiring.incrementAndGet(); @@ -106,12 +106,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 +121,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 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..b99b80356d 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 @@ -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 ); } 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..e9a3a350d2 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,9 +18,9 @@ */ package org.neo4j.driver.internal.metrics; -public interface ListenerEvent +public interface ListenerEvent { - ListenerEvent DEV_NULL_LISTENER_EVENT = new ListenerEvent() + ListenerEvent DEV_NULL_LISTENER_EVENT = new ListenerEvent() { @Override public void start() @@ -28,13 +28,14 @@ public void start() } @Override - public long elapsed() + public Long getSample() { - return 0; + return 0L; } }; 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..b42fc4f1d6 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 @@ -20,25 +20,27 @@ import java.util.concurrent.TimeUnit; +import org.neo4j.driver.Config; 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; 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 +56,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 +70,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,19 +85,21 @@ 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 inUseEvent a connection listener registered with a {@link NetworkConnection} when created. */ - 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 poolId the id of the pool where the netty channel lives. * @param inUseEvent a connection listener registered with a {@link NetworkConnection} when destroyed. */ - void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ); + void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ); - ListenerEvent createListenerEvent(); + ListenerEvent createListenerEvent(); void putPoolMetrics( String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool ); 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 index f6101a3c72..7cd04adb1d 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -18,48 +18,65 @@ */ package org.neo4j.driver.internal.metrics; -import io.micrometer.core.instrument.*; +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 org.neo4j.driver.ConnectionPoolMetrics; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.spi.ConnectionPool; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; +import static java.lang.String.format; public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsListener, ConnectionPoolMetrics { - private static final String PREFIX = "neo4j.driver.connections"; + 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 CREATED = PREFIX + ".created"; + 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 ACQUIRED = PREFIX + ".acquired"; + 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"; + public static final String RELEASED = PREFIX + ".released"; - // address and pool are not used. private final BoltServerAddress address; private final ConnectionPool pool; - private final Counter closed; + private final String id; private final AtomicInteger creating = new AtomicInteger(); - private final Counter failedToCreate; private final Counter created; - - // acquiring = acquired + timedOutToAcquire + failedToAcquireDueToOtherFailures (which we do not keep track) + private final Counter failedToCreate; + private final Counter closed; private final AtomicInteger acquiring = new AtomicInteger(); - private final Counter timedOutToAcquire; - private final AtomicLong totalAcquisitionTime = new AtomicLong(); - private final AtomicLong totalConnectionTime = new AtomicLong(); - private final AtomicLong totalInUseTime = new AtomicLong(); private final Counter acquired; - private final Counter totalInUse; - - private final String id; - private final MeterRegistry registry; - private final Iterable tags; + private final Counter timedOutToAcquire; + private final Timer totalAcquisitionTimer; + private final Timer totalConnectionTimer; + private final Timer totalInUseTimer; + private final Counter released; - MicrometerConnectionPoolMetrics(String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry ) + MicrometerConnectionPoolMetrics( String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry ) { - this(poolId, address, pool, registry, Tags.empty()); + this( poolId, address, pool, registry, Tags.empty() ); } - MicrometerConnectionPoolMetrics(String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry, Iterable tags ) { + MicrometerConnectionPoolMetrics( String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry, Iterable initialTags ) + { + Objects.requireNonNull( poolId ); Objects.requireNonNull( address ); Objects.requireNonNull( pool ); Objects.requireNonNull( registry ); @@ -67,24 +84,26 @@ public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsLis this.id = poolId; this.address = address; this.pool = pool; - this.registry = registry; - this.tags = Tags.concat(tags, "poolId", poolId); - - Gauge.builder(PREFIX + ".creating", creating, AtomicInteger::get).tags(this.tags).register(this.registry); - Gauge.builder(PREFIX + ".acquiring", acquiring, AtomicInteger::get).tags(this.tags).register(this.registry); - Gauge.builder(PREFIX + ".inUse", this::inUse).tags(this.tags).register(this.registry); - Gauge.builder(PREFIX + ".idle", this::idle).tags(this.tags).register(this.registry); - - failedToCreate = Counter.builder(PREFIX + ".failed").tags(this.tags).register(this.registry); - timedOutToAcquire = Counter.builder(PREFIX + ".acquisition.timeout").tags(this.tags).register(this.registry); - closed = Counter.builder(PREFIX + ".closed").tags(this.tags).register(this.registry); - created = Counter.builder(PREFIX + ".created").tags(this.tags).register(this.registry); - acquired = Counter.builder(PREFIX + ".acquired").tags(this.tags).register(this.registry); - totalInUse = Counter.builder(PREFIX + ".inUse").tags(this.tags).register(this.registry); + Iterable tags = Tags.concat( initialTags, + "address", String.format( "%s:%d", address.connectionHost(), 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 ); + created = Counter.builder( CREATED ).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 ); + acquired = Counter.builder( ACQUIRED ).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 ); + released = Counter.builder( RELEASED ).tags( tags ).register( registry ); } @Override - public void beforeCreating( ListenerEvent connEvent ) + public void beforeCreating( ListenerEvent connEvent ) { creating.incrementAndGet(); connEvent.start(); @@ -98,13 +117,12 @@ public void afterFailedToCreate() } @Override - public void afterCreated( ListenerEvent connEvent ) + public void afterCreated( ListenerEvent connEvent ) { creating.decrementAndGet(); created.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) connEvent).getSample(); - long elapsed = sample.stop(Timer.builder(PREFIX + ".creation").tags(this.tags).register(this.registry)); - totalConnectionTime.addAndGet( elapsed ); + sample.stop( totalConnectionTimer ); } @Override @@ -114,7 +132,7 @@ public void afterClosed() } @Override - public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) + public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) { acquireEvent.start(); acquiring.incrementAndGet(); @@ -127,106 +145,130 @@ public void afterAcquiringOrCreating() } @Override - public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) + public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) { acquired.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) acquireEvent).getSample(); - // We can't time failed acquisitions currently - // Same for creation Timer and in-use Timer - long elapsed = sample.stop(Timer.builder(PREFIX + ".acquisition").tags(this.tags).register(this.registry)); - totalAcquisitionTime.addAndGet(elapsed); + sample.stop( totalAcquisitionTimer ); } @Override public void afterTimedOutToAcquireOrCreate() { - // if we could access the ListenerEvent here, we could use the Timer with acquisition timeouts timedOutToAcquire.increment(); } @Override - public void acquired( ListenerEvent inUseEvent ) + public void acquired( ListenerEvent inUseEvent ) { inUseEvent.start(); } @Override - public void released( ListenerEvent inUseEvent ) + public void released( ListenerEvent inUseEvent ) { - totalInUse.increment(); + released.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) inUseEvent).getSample(); - long elapsed = sample.stop(Timer.builder(PREFIX + ".usage").tags(this.tags).register(registry)); - totalInUseTime.addAndGet( elapsed ); + sample.stop( totalInUseTimer ); } @Override - public String id() { + public String id() + { return this.id; } - // no-ops below here @Override - public int inUse() { - return pool.inUseConnections(address); + public int inUse() + { + return pool.inUseConnections( address ); } @Override - public int idle() { - return pool.idleConnections(address); + public int idle() + { + return pool.idleConnections( address ); } @Override - public int creating() { + public int creating() + { return creating.get(); } @Override - public long created() { - return ((Double) created.count()).longValue(); + public long created() + { + return toLong( created ); } @Override - public long failedToCreate() { - return ((Double) failedToCreate.count()).longValue(); + public long failedToCreate() + { + return toLong( failedToCreate ); } @Override - public long closed() { - return ((Double) closed.count()).longValue(); + public long closed() + { + return toLong( closed ); } @Override - public int acquiring() { + public int acquiring() + { return acquiring.get(); } @Override - public long acquired() { - return ((Double) acquired.count()).longValue(); + public long acquired() + { + return toLong( acquired ); + } + + @Override + public long timedOutToAcquire() + { + return toLong( timedOutToAcquire ); } @Override - public long timedOutToAcquire() { - return ((Double) timedOutToAcquire.count()).longValue(); + public long totalAcquisitionTime() + { + return (long) totalAcquisitionTimer.totalTime( TimeUnit.MILLISECONDS ); } @Override - public long totalAcquisitionTime() { - return totalAcquisitionTime.get(); + public long totalConnectionTime() + { + return (long) totalConnectionTimer.totalTime( TimeUnit.MILLISECONDS ); } @Override - public long totalConnectionTime() { - return totalConnectionTime.get(); + public long totalInUseTime() + { + return (long) totalInUseTimer.totalTime( TimeUnit.MILLISECONDS ); } @Override - public long totalInUseTime() { - return totalInUseTime.get(); + public long totalInUseCount() + { + return toLong( released ); } @Override - public long totalInUseCount() { - return ((Double) totalInUse.count()).longValue(); + 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 toLong( 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 index 08cc63ffa6..d5ed349ba3 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java @@ -19,98 +19,119 @@ package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; -import org.neo4j.driver.ConnectionPoolMetrics; -import org.neo4j.driver.Metrics; -import org.neo4j.driver.internal.BoltServerAddress; -import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class MicrometerMetrics implements Metrics, MetricsListener { +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 class MicrometerMetrics implements Metrics, MetricsListener +{ private final MeterRegistry meterRegistry; - private final Map connectionPoolMetrics; + private final Map connectionPoolMetrics; - public MicrometerMetrics(MeterRegistry meterRegistry) { + public MicrometerMetrics( MeterRegistry meterRegistry ) + { this.meterRegistry = meterRegistry; this.connectionPoolMetrics = new ConcurrentHashMap<>(); } @Override - public Collection connectionPoolMetrics() { - return Collections.unmodifiableCollection(this.connectionPoolMetrics.values()); + public Collection connectionPoolMetrics() + { + return Collections.unmodifiableCollection( this.connectionPoolMetrics.values() ); } @Override - public void beforeCreating(String poolId, ListenerEvent creatingEvent) { - poolMetricsListener(poolId).beforeCreating(creatingEvent); + public void beforeCreating( String poolId, ListenerEvent creatingEvent ) + { + poolMetricsListener( poolId ).beforeCreating( creatingEvent ); } @Override - public void afterCreated(String poolId, ListenerEvent creatingEvent) { - poolMetricsListener(poolId).afterCreated(creatingEvent); + public void afterCreated( String poolId, ListenerEvent creatingEvent ) + { + poolMetricsListener( poolId ).afterCreated( creatingEvent ); } @Override - public void afterFailedToCreate(String poolId) { - poolMetricsListener(poolId).afterFailedToCreate(); + public void afterFailedToCreate( String poolId ) + { + poolMetricsListener( poolId ).afterFailedToCreate(); } @Override - public void afterClosed(String poolId) { - poolMetricsListener(poolId).afterClosed(); + public void afterClosed( String poolId ) + { + poolMetricsListener( poolId ).afterClosed(); } @Override - public void beforeAcquiringOrCreating(String poolId, ListenerEvent acquireEvent) { - poolMetricsListener(poolId).beforeAcquiringOrCreating(acquireEvent); + public void beforeAcquiringOrCreating( String poolId, ListenerEvent acquireEvent ) + { + poolMetricsListener( poolId ).beforeAcquiringOrCreating( acquireEvent ); } @Override - public void afterAcquiringOrCreating(String poolId) { - poolMetricsListener(poolId).afterAcquiringOrCreating(); + public void afterAcquiringOrCreating( String poolId ) + { + poolMetricsListener( poolId ).afterAcquiringOrCreating(); } @Override - public void afterAcquiredOrCreated(String poolId, ListenerEvent acquireEvent) { - poolMetricsListener(poolId).afterAcquiredOrCreated(acquireEvent); + public void afterAcquiredOrCreated( String poolId, ListenerEvent acquireEvent ) + { + poolMetricsListener( poolId ).afterAcquiredOrCreated( acquireEvent ); } @Override - public void afterTimedOutToAcquireOrCreate(String poolId) { - poolMetricsListener(poolId).afterTimedOutToAcquireOrCreate(); + public void afterTimedOutToAcquireOrCreate( String poolId ) + { + poolMetricsListener( poolId ).afterTimedOutToAcquireOrCreate(); } @Override - public void afterConnectionCreated(String poolId, ListenerEvent inUseEvent) { - poolMetricsListener(poolId).acquired(inUseEvent); + public void afterConnectionCreated( String poolId, ListenerEvent inUseEvent ) + { + poolMetricsListener( poolId ).acquired( inUseEvent ); } @Override - public void afterConnectionReleased(String poolId, ListenerEvent inUseEvent) { - poolMetricsListener(poolId).released(inUseEvent); + public void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ) + { + poolMetricsListener( poolId ).released( inUseEvent ); } @Override - public ListenerEvent createListenerEvent() { - return new MicrometerTimerListenerEvent(this.meterRegistry); + public ListenerEvent createListenerEvent() + { + return new MicrometerTimerListenerEvent( this.meterRegistry ); } @Override - public void putPoolMetrics(String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool) { - this.connectionPoolMetrics.put(poolId, new MicrometerConnectionPoolMetrics(poolId, address, connectionPool, this.meterRegistry)); + public void putPoolMetrics( String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool ) + { + this.connectionPoolMetrics.put( poolId, new MicrometerConnectionPoolMetrics( poolId, address, connectionPool, this.meterRegistry ) ); + } + + // For testing purposes only + void putPoolMetrics( String poolId, ConnectionPoolMetrics poolMetrics ) + { + this.connectionPoolMetrics.put( poolId, poolMetrics ); } @Override - public void removePoolMetrics(String poolId) { - // TODO should we unregister metrics registered for this poolId? - this.connectionPoolMetrics.remove(poolId); + public void removePoolMetrics( String poolId ) + { + this.connectionPoolMetrics.remove( poolId ); } - private ConnectionPoolMetricsListener poolMetricsListener(String poolId ) + private ConnectionPoolMetricsListener poolMetricsListener( String poolId ) { ConnectionPoolMetricsListener poolMetrics = (ConnectionPoolMetricsListener) this.connectionPoolMetrics.get( poolId ); if ( poolMetrics == null ) @@ -123,12 +144,12 @@ private ConnectionPoolMetricsListener poolMetricsListener(String poolId ) ConnectionPoolMetricsListener DEV_NULL_POOL_METRICS_LISTENER = new ConnectionPoolMetricsListener() { @Override - public void beforeCreating( ListenerEvent listenerEvent ) + public void beforeCreating( ListenerEvent listenerEvent ) { } @Override - public void afterCreated( ListenerEvent listenerEvent ) + public void afterCreated( ListenerEvent listenerEvent ) { } @@ -143,7 +164,7 @@ public void afterClosed() } @Override - public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) + public void beforeAcquiringOrCreating( ListenerEvent acquireEvent ) { } @@ -153,7 +174,7 @@ public void afterAcquiringOrCreating() } @Override - public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) + public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) { } @@ -163,12 +184,12 @@ public void afterTimedOutToAcquireOrCreate() } @Override - public void acquired( ListenerEvent inUseEvent ) + public void acquired( ListenerEvent inUseEvent ) { } @Override - public void released( ListenerEvent inUseEvent ) + public void released( ListenerEvent inUseEvent ) { } }; 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 index eececa2c00..d05f96c7a5 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java @@ -19,30 +19,33 @@ package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; -import org.neo4j.driver.Metrics; -public class MicrometerMetricsProvider implements MetricsProvider { +import org.neo4j.driver.Metrics; - private final MeterRegistry meterRegistry; +public class MicrometerMetricsProvider implements MetricsProvider +{ private final MicrometerMetrics metrics; - public MicrometerMetricsProvider(MeterRegistry meterRegistry) { - this.meterRegistry = meterRegistry; - this.metrics = new MicrometerMetrics(this.meterRegistry); + public MicrometerMetricsProvider( MeterRegistry meterRegistry ) + { + this.metrics = new MicrometerMetrics( meterRegistry ); } @Override - public Metrics metrics() { + public Metrics metrics() + { return this.metrics; } @Override - public MetricsListener metricsListener() { + public MetricsListener metricsListener() + { return this.metrics; } @Override - public boolean isMetricsEnabled() { + public boolean isMetricsEnabled() + { return true; } } 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 index e6cf35bb0b..75118a095b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java @@ -21,28 +21,25 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; -public class MicrometerTimerListenerEvent implements ListenerEvent { - +public class MicrometerTimerListenerEvent implements ListenerEvent +{ private final MeterRegistry meterRegistry; private Timer.Sample sample; - public MicrometerTimerListenerEvent(MeterRegistry meterRegistry) { + public MicrometerTimerListenerEvent( MeterRegistry meterRegistry ) + { this.meterRegistry = meterRegistry; } @Override - public void start() { - this.sample = Timer.start(this.meterRegistry); - } - - public Timer.Sample getSample() { - return this.sample; + public void start() + { + this.sample = Timer.start( this.meterRegistry ); } @Override - public long elapsed() { - // Micrometer Timer Sample does not provide API to get elapsed time - // and it is not needed right now - return 0; + 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..5bf460df14 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 +public 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/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java index 98592ad0cb..69d87c2971 100644 --- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java +++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java @@ -18,6 +18,8 @@ */ package org.neo4j.driver; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -30,6 +32,7 @@ import java.io.Serializable; import java.lang.reflect.Field; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -362,6 +365,38 @@ void shouldErrorWithInvalidUserAgent() assertThrows( IllegalArgumentException.class, () -> Config.builder().withUserAgent( "" ).build() ); } + @Test + void shouldNotHaveMeterRegistryByDefault() + { + Config config = Config.builder().build(); + Optional meterRegistryOpt = config.meterRegistry(); + + assertFalse( meterRegistryOpt.isPresent() ); + assertFalse( config.isMetricsEnabled() ); + } + + @Test + void shouldNotAcceptNullMeterRegistry() + { + Config.ConfigBuilder builder = Config.builder(); + assertThrows( NullPointerException.class, () -> builder.withMicrometerDriverMetrics( null ) ); + } + + @Test + void shouldSetMeterRegistry() + { + MeterRegistry registry = new SimpleMeterRegistry(); + + Config config = Config.builder() + .withMicrometerDriverMetrics( registry ) + .build(); + Optional meterRegistryOpt = config.meterRegistry(); + + assertTrue( meterRegistryOpt.isPresent() ); + assertEquals( registry, meterRegistryOpt.get() ); + assertTrue( config.isMetricsEnabled() ); + } + @Nested class SerializationTest { @@ -370,7 +405,7 @@ class SerializationTest void shouldSerialize() throws Exception { Config config = Config.builder() - .withMaxConnectionPoolSize( 123 ) + .withMaxConnectionPoolSize( 123 ) .withConnectionTimeout( 6543L, TimeUnit.MILLISECONDS ) .withConnectionAcquisitionTimeout( 5432L, TimeUnit.MILLISECONDS ) .withConnectionLivenessCheckTimeout( 4321L, TimeUnit.MILLISECONDS ) diff --git a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java index c2b85d4ce1..94ab8cb9e9 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java @@ -25,8 +25,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.RegisterExtension; -import org.neo4j.driver.*; -import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; + +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.QueryRunner; +import org.neo4j.driver.Result; import org.neo4j.driver.util.DatabaseExtension; import org.neo4j.driver.util.ParallelizableIT; @@ -34,8 +38,8 @@ import static org.neo4j.driver.Values.parameters; @ParallelizableIT -class MetricsIT { - +class MetricsIT +{ @RegisterExtension static final DatabaseExtension neo4j = new DatabaseExtension(); @@ -45,7 +49,7 @@ class MetricsIT { @BeforeEach void createDriver() { - driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), Config.builder().withDriverMetrics(new MicrometerMetricsProvider(meterRegistry)).build() ); + driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), Config.builder().withMicrometerDriverMetrics( meterRegistry ).build() ); } @AfterEach @@ -59,28 +63,28 @@ 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()); + 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()); + assertEquals( 1, acquisitionTimer.count() ); + assertEquals( 1, creationTimer.count() ); + assertEquals( 1, usageTimer.count() ); } - private Result createNodesInNewSession(int nodesToCreate ) + private Result createNodesInNewSession( int nodesToCreate ) { return createNodes( nodesToCreate, driver.session() ); } - private Result createNodes(int nodesToCreate, QueryRunner queryRunner) + 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 ) ); + 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..d150e4bca0 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,8 @@ */ package org.neo4j.driver.internal; +import io.micrometer.core.instrument.MeterRegistry; +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 +27,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; @@ -41,6 +44,7 @@ import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer; 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; @@ -171,6 +175,22 @@ void shouldCreateDriverMetricsIfMonitoringEnabled() assertThat( provider instanceof InternalMetricsProvider, is( true ) ); } + @Test + void shouldCreateMicrometerDriverMetricsIfMonitoringEnabled() + { + // Given + MeterRegistry registry = new SimpleMeterRegistry(); + Config config = mock( Config.class ); + when( config.isMetricsEnabled() ).thenReturn( true ); + when( config.meterRegistry() ).thenReturn( Optional.of( registry ) ); + when( config.logging() ).thenReturn( Logging.none() ); + // When + MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM ); + // Then + assertThat( provider.isMetricsEnabled(), is( true ) ); + assertThat( provider instanceof MicrometerMetricsProvider, is( true ) ); + } + @ParameterizedTest @MethodSource( "testUris" ) void shouldCreateAppropriateDriverType( String uri ) diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java deleted file mode 100644 index 7c711f6840..0000000000 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsListenerTest.java +++ /dev/null @@ -1,23 +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; - -class MicrometerConnectionPoolMetricsListenerTest { - -} 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..b6bf0ff2fa --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java @@ -0,0 +1,284 @@ +/* + * 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 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; + + @BeforeEach + void beforeEach() + { + address = new BoltServerAddress( "host", "127.0.0.1", 7687 ); + pool = mock( ConnectionPool.class ); + registry = new SimpleMeterRegistry(); + metrics = new MicrometerConnectionPoolMetrics( ID, address, pool, 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 shouldDelegateToPoolOnInUse() + { + // GIVEN + int expected = 5; + given( pool.inUseConnections( address ) ).willReturn( expected ); + ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class ); + given( expectedMetrics.inUse() ).willReturn( expected ); + + // WHEN + int actual = metrics.inUse(); + + // THEN + assertEquals( expected, actual ); + then( pool ).should().inUseConnections( address ); + verifyMetrics( expectedMetrics, metrics ); + } + + @Test + void shouldDelegateToPoolOnIdle() + { + // GIVEN + int expected = 5; + given( pool.idleConnections( address ) ).willReturn( expected ); + ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class ); + given( expectedMetrics.idle() ).willReturn( expected ); + + // WHEN + int actual = metrics.idle(); + + // THEN + assertEquals( expected, actual ); + then( pool ).should().idleConnections( address ); + verifyMetrics( expectedMetrics, metrics ); + } + + 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.CREATED ).counter().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.ACQUIRED ).counter().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.RELEASED ).counter().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..0268dcb9ea --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java @@ -0,0 +1,69 @@ +/* + * 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 +{ + MicrometerMetricsProvider provider; + MeterRegistry registry; + + @BeforeEach + void beforeEach() + { + provider = new MicrometerMetricsProvider( registry ); + } + + @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 ); + } + + @Test + void shouldReportMetricsEnabled() + { + // GIVEN & WHEN + boolean metricsEnabled = provider.isMetricsEnabled(); + + // THEN + assertTrue( metricsEnabled ); + } +} 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..7b1c354de6 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java @@ -0,0 +1,248 @@ +/* + * 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 org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; + +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 ); + poolMetrics = mock( ConnectionPoolMetrics.class, Mockito.withSettings().extraInterfaces( ConnectionPoolMetricsListener.class ) ); + poolMetricsListener = (ConnectionPoolMetricsListener) poolMetrics; + } + + @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.putPoolMetrics( ID, BoltServerAddress.LOCAL_DEFAULT, mock( ConnectionPoolImpl.class ) ); + + // 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 ); + } +} From faf764ba0b4cf5352823299a39d385accd7b82bb Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Wed, 2 Feb 2022 17:40:04 +0100 Subject: [PATCH 04/24] Make MetricsAdapter a supported, public api. - Set scope of micrometer to provided - Rename MetricsProvider to MetricsAdapter (it does not provide metrics, the driver does. It adapts the drivers metrics to something external) - Make it a public interface - Remove dependencies to other internal interfaces and classes (such as BoltServerAddress and the pool itself via ServerAddress and intsuppliers) - Reduce visibility of internal classes as much as possible - Make sure that adapters are not serialized - Apply the clock to the internal adapter (an oversight from the previous iteration) --- bundle/pom.xml | 1 - driver/pom.xml | 1 - .../main/java/org/neo4j/driver/Config.java | 53 ++++---- .../main/java/org/neo4j/driver/Driver.java | 4 +- .../java/org/neo4j/driver/MetricsAdapter.java | 37 ++++++ .../neo4j/driver/internal/DriverFactory.java | 45 +++---- .../neo4j/driver/internal/InternalDriver.java | 13 +- .../internal/async/NetworkConnection.java | 4 +- .../async/pool/ConnectionPoolImpl.java | 13 +- .../internal/async/pool/NettyChannelPool.java | 2 +- .../async/pool/NettyChannelTracker.java | 17 +-- .../async/pool/NetworkConnectionFactory.java | 2 +- .../metrics/DevNullListenerEvent.java | 37 ++++++ .../metrics/DevNullMetricsAdapter.java | 44 +++++++ .../metrics/DevNullMetricsListener.java | 102 ++++++++++++++ .../metrics/DevNullPoolMetricsListener.java | 77 +++++++++++ .../metrics/InternalAbstractMetrics.java | 124 ------------------ .../InternalConnectionPoolMetrics.java | 27 ++-- .../internal/metrics/InternalMetrics.java | 17 ++- ...vider.java => InternalMetricsAdapter.java} | 12 +- .../internal/metrics/MetricsProvider.java | 57 -------- .../metrics/TimeRecorderListenerEvent.java | 3 +- .../driver/internal/spi/ConnectionPool.java | 5 +- .../ConnectionPoolMetricsListener.java | 65 +-------- .../{internal => }/metrics/ListenerEvent.java | 16 +-- .../metrics/MetricsListener.java | 13 +- .../MicrometerConnectionPoolMetrics.java | 31 +++-- .../metrics/MicrometerMetrics.java | 68 ++-------- .../MicrometerMetricsAdapter.java} | 16 +-- .../metrics/MicrometerTimerListenerEvent.java | 4 +- .../java/org/neo4j/driver/ConfigTest.java | 33 +++-- .../org/neo4j/driver/GraphDatabaseTest.java | 3 +- .../integration/ConnectionHandlingIT.java | 8 +- .../neo4j/driver/integration/MetricsIT.java | 4 +- .../internal/CustomSecurityPlanTest.java | 10 +- .../driver/internal/DriverFactoryTest.java | 39 +++--- .../driver/internal/InternalDriverTest.java | 16 +-- .../internal/async/NetworkConnectionTest.java | 4 +- .../async/pool/ConnectionPoolImplIT.java | 4 +- .../async/pool/ConnectionPoolImplTest.java | 4 +- .../async/pool/NettyChannelPoolIT.java | 4 +- .../async/pool/NettyChannelTrackerTest.java | 8 +- .../async/pool/TestConnectionPool.java | 4 +- .../RoutingTableAndConnectionPoolTest.java | 6 +- .../util/FailingConnectionDriverFactory.java | 11 +- .../util/io/ChannelTrackingDriverFactory.java | 6 +- .../MicrometerConnectionPoolMetricsTest.java | 76 ++++++----- .../MicrometerMetricsAdapterTest.java} | 18 +-- .../metrics/MicrometerMetricsTest.java | 5 +- .../MicrometerTimerListenerEventTest.java | 2 +- .../requests/GetConnectionPoolMetrics.java | 19 ++- 51 files changed, 611 insertions(+), 583 deletions(-) create mode 100644 driver/src/main/java/org/neo4j/driver/MetricsAdapter.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java delete mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/InternalAbstractMetrics.java rename driver/src/main/java/org/neo4j/driver/internal/metrics/{InternalMetricsProvider.java => InternalMetricsAdapter.java} (83%) delete mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/ConnectionPoolMetricsListener.java (65%) rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/ListenerEvent.java (71%) rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/MetricsListener.java (86%) rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/MicrometerConnectionPoolMetrics.java (87%) rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/MicrometerMetrics.java (71%) rename driver/src/main/java/org/neo4j/driver/{internal/metrics/MicrometerMetricsProvider.java => metrics/MicrometerMetricsAdapter.java} (76%) rename driver/src/main/java/org/neo4j/driver/{internal => }/metrics/MicrometerTimerListenerEvent.java (90%) rename driver/src/test/java/org/neo4j/driver/{internal => }/metrics/MicrometerConnectionPoolMetricsTest.java (86%) rename driver/src/test/java/org/neo4j/driver/{internal/metrics/MicrometerMetricsProviderTest.java => metrics/MicrometerMetricsAdapterTest.java} (78%) rename driver/src/test/java/org/neo4j/driver/{internal => }/metrics/MicrometerMetricsTest.java (96%) rename driver/src/test/java/org/neo4j/driver/{internal => }/metrics/MicrometerTimerListenerEventTest.java (97%) diff --git a/bundle/pom.xml b/bundle/pom.xml index 90f06abfaa..bf8600fbee 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -40,7 +40,6 @@ io.micrometer micrometer-core - true org.graalvm.nativeimage diff --git a/driver/pom.xml b/driver/pom.xml index c0ac6cbec1..1b87c2971b 100644 --- a/driver/pom.xml +++ b/driver/pom.xml @@ -40,7 +40,6 @@ io.micrometer micrometer-core - true org.slf4j diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index 43900c1425..b60cd370b1 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -18,8 +18,6 @@ */ package org.neo4j.driver; -import io.micrometer.core.instrument.MeterRegistry; - import java.io.File; import java.io.Serializable; import java.net.InetAddress; @@ -34,6 +32,8 @@ import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil; import org.neo4j.driver.internal.retry.RetrySettings; +import org.neo4j.driver.internal.metrics.DevNullMetricsAdapter; +import org.neo4j.driver.metrics.MicrometerMetricsAdapter; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.Experimental; import org.neo4j.driver.util.Immutable; @@ -99,7 +99,7 @@ public class Config implements Serializable private final boolean isMetricsEnabled; private final int eventLoopThreads; private final String userAgent; - private final MeterRegistry meterRegistry; + private final transient MetricsAdapter metricsAdapter; private Config( ConfigBuilder builder ) { @@ -124,7 +124,7 @@ private Config( ConfigBuilder builder ) this.eventLoopThreads = builder.eventLoopThreads; this.isMetricsEnabled = builder.isMetricsEnabled; - this.meterRegistry = builder.meterRegistry; + this.metricsAdapter = builder.metricsAdapter; } /** @@ -265,9 +265,9 @@ public boolean isMetricsEnabled() return isMetricsEnabled; } - public Optional meterRegistry() + public Optional metricsAdapter() { - return Optional.ofNullable( meterRegistry ); + return Optional.ofNullable( metricsAdapter ); } /** @@ -297,10 +297,10 @@ public static class ConfigBuilder private int connectionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis( 30 ); private RetrySettings retrySettings = RetrySettings.DEFAULT; private ServerAddressResolver resolver; + private MetricsAdapter metricsAdapter; private boolean isMetricsEnabled = false; private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE; private int eventLoopThreads = 0; - private MeterRegistry meterRegistry; private ConfigBuilder() {} @@ -717,34 +717,43 @@ public ConfigBuilder withResolver( ServerAddressResolver resolver ) */ public ConfigBuilder withDriverMetrics() { - this.isMetricsEnabled = true; - return this; + return withMetricsEnabled( true ); } /** - * Enable driver metrics backed by Micrometer instrumentation. The metrics can be obtained afterwards via Micrometer means and {@link - * Driver#metrics()}. - *

- * You must have Micrometer on classpath to use this option. - * - * @param meterRegistry meter registry to register metrics with. + * Disable driver metrics. When disabled, driver metrics cannot be accessed via {@link Driver#metrics()}. * @return this builder. */ - @Experimental - public ConfigBuilder withMicrometerDriverMetrics( MeterRegistry meterRegistry ) + public ConfigBuilder withoutDriverMetrics() + { + return withMetricsEnabled( false ); + } + + private ConfigBuilder withMetricsEnabled( boolean enabled ) { - this.meterRegistry = Objects.requireNonNull( meterRegistry, "meterRegistry" ); - this.isMetricsEnabled = true; + this.isMetricsEnabled = enabled; + this.metricsAdapter = null; return this; } /** - * Disable driver metrics. When disabled, driver metrics cannot be accessed via {@link Driver#metrics()}. + * Enable driver metrics backed by a different metrics provider. + *

+ * We offer an implementation based on Micrometer. + * The metrics can be obtained afterwards via Micrometer means and {@link Driver#metrics()}. + * You must have Micrometer on classpath to use the provided {@link MicrometerMetricsAdapter}. + *

+ * This configuration setting is not serialiable. If metrics had been enabled in a configuration + * that was serialized inbetween usage, it will default to the internal adapter. + * + * @param metricsAdapter the metrics provider to use. Use {@literal null} to disable metrics again. * @return this builder. */ - public ConfigBuilder withoutDriverMetrics() + @Experimental + public ConfigBuilder withMetricsAdapter( MetricsAdapter metricsAdapter ) { - this.isMetricsEnabled = false; + this.metricsAdapter = Objects.requireNonNull( metricsAdapter, "metricsAdapter" ); + this.isMetricsEnabled = this.metricsAdapter != DevNullMetricsAdapter.INSTANCE; return this; } 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..55c2439d49 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java @@ -0,0 +1,37 @@ +/* + * 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; + +import org.neo4j.driver.metrics.MetricsListener; + +/** + * An adapter that can collect driver metrics via a {@link MetricsListener} and publishes them via a {@link Metrics} instance. + */ +public interface MetricsAdapter +{ + /** + * @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(); +} 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 2609d27e7c..8d14e8ceec 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,9 +43,8 @@ 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.InternalMetricsProvider; -import org.neo4j.driver.internal.metrics.MetricsProvider; -import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; +import org.neo4j.driver.internal.metrics.DevNullMetricsAdapter; +import org.neo4j.driver.internal.metrics.InternalMetricsAdapter; import org.neo4j.driver.internal.retry.ExponentialBackoffRetryLogic; import org.neo4j.driver.internal.retry.RetryLogic; import org.neo4j.driver.internal.retry.RetrySettings; @@ -57,7 +57,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 @@ -95,15 +94,15 @@ 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() ); - ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, + MetricsAdapter metricsAdapter = getOrCreateMetricsProvider( config, createClock() ); + ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, newRoutingSettings.routingContext() ); - return createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsProvider, config ); + return createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsAdapter, config ); } protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { Clock clock = createClock(); ConnectionSettings settings = new ConnectionSettings( authToken, config.userAgent(), config.connectionTimeoutMillis() ); @@ -112,20 +111,18 @@ protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan config.connectionAcquisitionTimeoutMillis(), config.maxConnectionLifetimeMillis(), config.idleTimeBeforeConnectionTest() ); - return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsProvider.metricsListener(), config.logging(), clock, ownsEventLoopGroup ); + return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsAdapter.metricsListener(), config.logging(), clock, ownsEventLoopGroup ); } - protected static MetricsProvider createDriverMetrics( Config config, Clock clock ) + protected static MetricsAdapter getOrCreateMetricsProvider( Config config, Clock clock ) { - if( config.isMetricsEnabled() ) + if ( config.isMetricsEnabled() ) { - return config.meterRegistry() - .map( MicrometerMetricsProvider::new ) - .orElseGet( () -> new InternalMetricsProvider( Clock.SYSTEM, config.logging() ) ); + return config.metricsAdapter().orElseGet( () -> new InternalMetricsAdapter( clock, config.logging() ) ); } else { - return METRICS_DISABLED_PROVIDER; + return DevNullMetricsAdapter.INSTANCE; } } @@ -137,7 +134,7 @@ protected ChannelConnector createConnector( ConnectionSettings settings, Securit private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, - MetricsProvider metricsProvider, Config config ) + MetricsAdapter metricsAdapter, Config config ) { try { @@ -145,12 +142,12 @@ private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltSer if ( isRoutingScheme( scheme ) ) { - return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsProvider, config ); + return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsAdapter, config ); } else { assertNoRoutingContext( uri, routingSettings ); - return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metricsProvider, config ); + return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metricsAdapter, config ); } } catch ( Throwable driverError ) @@ -167,11 +164,11 @@ private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltSer * This method is protected only for testing */ protected InternalDriver createDirectDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, RetryLogic retryLogic, - MetricsProvider metricsProvider, Config config ) + MetricsAdapter metricsAdapter, Config config ) { ConnectionProvider connectionProvider = new DirectConnectionProvider( address, connectionPool ); SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config ); - InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsProvider, config ); + InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsAdapter, config ); Logger log = config.logging().getLog( getClass() ); log.info( "Direct driver instance %s created for server address %s", driver.hashCode(), address ); return driver; @@ -183,12 +180,12 @@ protected InternalDriver createDirectDriver( SecurityPlan securityPlan, BoltServ * This method is protected only for testing */ protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, - EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsProvider metricsProvider, Config config ) + EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsAdapter metricsAdapter, Config config ) { ConnectionProvider connectionProvider = createLoadBalancer( address, connectionPool, eventExecutorGroup, config, routingSettings ); SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config ); - InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsProvider, config ); + InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsAdapter, config ); Logger log = config.logging().getLog( getClass() ); log.info( "Routing driver instance %s created for server address %s", driver.hashCode(), address ); return driver; @@ -199,9 +196,9 @@ protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltSer *

* This method is protected only for testing */ - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) { - return new InternalDriver( securityPlan, sessionFactory, metricsProvider, config.logging() ); + return new InternalDriver( securityPlan, sessionFactory, metricsAdapter, config.logging() ); } /** 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..d3bd6c1a17 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.MetricsAdapter; 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.DevNullMetricsAdapter; import org.neo4j.driver.internal.reactive.InternalRxSession; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.types.InternalTypeSystem; @@ -47,13 +48,13 @@ public class InternalDriver implements Driver private final Logger log; private AtomicBoolean closed = new AtomicBoolean( false ); - private final MetricsProvider metricsProvider; + private final MetricsAdapter metricsAdapter; - InternalDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Logging logging ) + InternalDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Logging logging ) { this.securityPlan = securityPlan; this.sessionFactory = sessionFactory; - this.metricsProvider = metricsProvider; + this.metricsAdapter = metricsAdapter; this.log = logging.getLog( getClass() ); } @@ -96,13 +97,13 @@ public AsyncSession asyncSession( SessionConfig sessionConfig ) @Override public Metrics metrics() { - return metricsProvider.metrics(); + return metricsAdapter.metrics(); } @Override public boolean isMetricsEnabled() { - return metricsProvider.isMetricsEnabled(); + return metricsAdapter != DevNullMetricsAdapter.INSTANCE; } @Override diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java index c8916aaf32..5bd5689a2b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java @@ -38,8 +38,8 @@ import org.neo4j.driver.internal.messaging.BoltProtocol; import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.messaging.request.ResetMessage; -import org.neo4j.driver.internal.metrics.ListenerEvent; -import org.neo4j.driver.internal.metrics.MetricsListener; +import org.neo4j.driver.metrics.ListenerEvent; +import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.internal.util.Clock; 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..a8e2277ccb 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 @@ -41,12 +41,13 @@ import org.neo4j.driver.exceptions.ServiceUnavailableException; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.internal.metrics.ListenerEvent; -import org.neo4j.driver.internal.metrics.MetricsListener; +import org.neo4j.driver.metrics.ListenerEvent; +import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; 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/NettyChannelPool.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java index 8abdb5b30b..756e471a2c 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java @@ -31,7 +31,7 @@ import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.internal.metrics.ListenerEvent; +import org.neo4j.driver.metrics.ListenerEvent; import static java.util.Objects.requireNonNull; import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setPoolId; 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..3997a60ec3 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 @@ -35,8 +35,9 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.BoltServerAddress; 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.metrics.ListenerEvent; +import org.neo4j.driver.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/async/pool/NetworkConnectionFactory.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java index 1a3404e950..960132b6ff 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java @@ -22,7 +22,7 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.async.NetworkConnection; -import org.neo4j.driver.internal.metrics.MetricsListener; +import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.util.Clock; 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..7f9553851a --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java @@ -0,0 +1,37 @@ +/* + * 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.ListenerEvent; + +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/DevNullMetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java new file mode 100644 index 0000000000..15746a77d5 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java @@ -0,0 +1,44 @@ +/* + * 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.MetricsAdapter; +import org.neo4j.driver.metrics.MetricsListener; +import org.neo4j.driver.exceptions.ClientException; + +public enum DevNullMetricsAdapter implements MetricsAdapter +{ + INSTANCE; + + @Override + public Metrics metrics() + { + // To outside users, we forbid 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 DevNullMetricsListener.INSTANCE; + } +} 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..b40398dcfe --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java @@ -0,0 +1,102 @@ +/* + * 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.metrics.ListenerEvent; +import org.neo4j.driver.metrics.MetricsListener; +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 not available while driver metrics is not enabled."; + } +} 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..943c6dc39f --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java @@ -0,0 +1,77 @@ +/* + * 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.ListenerEvent; +import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; + +public 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 1c785d699e..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 35b332418b..f7e16d72c4 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,20 @@ 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.metrics.ListenerEvent; +import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; +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,14 +55,16 @@ 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 @@ -144,13 +149,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 @@ -231,7 +236,7 @@ public String toString() } // This method is for purposes testing only - public BoltServerAddress getAddress() + 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 b99b80356d..e378b49957 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,22 @@ 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.metrics.ListenerEvent; 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.metrics.MetricsListener; import org.neo4j.driver.internal.util.Clock; +import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; +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 +52,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 @@ -144,7 +147,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/InternalMetricsAdapter.java similarity index 83% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsAdapter.java index b807f055c8..39f21c0086 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsAdapter.java @@ -19,14 +19,16 @@ package org.neo4j.driver.internal.metrics; import org.neo4j.driver.Logging; +import org.neo4j.driver.MetricsAdapter; +import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.util.Clock; import org.neo4j.driver.Metrics; -public class InternalMetricsProvider implements MetricsProvider +public final class InternalMetricsAdapter implements MetricsAdapter { private final InternalMetrics metrics; - public InternalMetricsProvider( Clock clock, Logging logging ) + public InternalMetricsAdapter( Clock clock, Logging logging ) { this.metrics = new InternalMetrics( clock, logging ); } @@ -42,10 +44,4 @@ public MetricsListener metricsListener() { return metrics; } - - @Override - public boolean isMetricsEnabled() - { - return true; - } } 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 deleted file mode 100644 index 8d476fa381..0000000000 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java +++ /dev/null @@ -1,57 +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 org.neo4j.driver.Metrics; -import org.neo4j.driver.exceptions.ClientException; - -import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS; - -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; - } - }; - - Metrics metrics(); - - MetricsListener metricsListener(); - - boolean isMetricsEnabled(); -} 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 5bf460df14..94d748db54 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 @@ -18,9 +18,10 @@ */ package org.neo4j.driver.internal.metrics; +import org.neo4j.driver.metrics.ListenerEvent; import org.neo4j.driver.internal.util.Clock; -public class TimeRecorderListenerEvent implements ListenerEvent +final class TimeRecorderListenerEvent implements ListenerEvent { private final Clock clock; private long 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/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java b/driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java similarity index 65% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java rename to driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java index c73d27b7c2..6e65f4555b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; public interface ConnectionPoolMetricsListener { @@ -77,68 +77,5 @@ public interface ConnectionPoolMetricsListener * @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 ) - { - - } - }; } diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java b/driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java similarity index 71% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java rename to driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java index e9a3a350d2..85c98ce3c6 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java @@ -16,24 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; public interface ListenerEvent { - ListenerEvent DEV_NULL_LISTENER_EVENT = new ListenerEvent() - { - @Override - public void start() - { - } - - @Override - public Long getSample() - { - return 0L; - } - }; - void start(); T getSample(); diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java b/driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java similarity index 86% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java rename to driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java index b42fc4f1d6..26450d27e4 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java @@ -16,14 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import java.util.concurrent.TimeUnit; +import java.util.function.IntSupplier; import org.neo4j.driver.Config; -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.net.ServerAddress; public interface MetricsListener { @@ -87,7 +86,7 @@ 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 inUseEvent a connection listener event fired from the newly created connection. */ void afterConnectionCreated( String poolId, ListenerEvent inUseEvent ); @@ -95,13 +94,13 @@ public interface MetricsListener * 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 inUseEvent a connection listener event fired from the connection being released. */ void afterConnectionReleased( String poolId, ListenerEvent inUseEvent ); 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/MicrometerConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java similarity index 87% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java rename to driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java index 7cd04adb1d..8ca77d26ea 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.Gauge; @@ -28,14 +28,15 @@ 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.internal.spi.ConnectionPool; +import org.neo4j.driver.net.ServerAddress; import static java.lang.String.format; -public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsListener, ConnectionPoolMetrics +final class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsListener, ConnectionPoolMetrics { public static final String PREFIX = "neo4j.driver.connections"; public static final String IN_USE = PREFIX + ".in.use"; @@ -52,8 +53,8 @@ public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsLis public static final String USAGE = PREFIX + ".usage"; public static final String RELEASED = PREFIX + ".released"; - private final BoltServerAddress address; - private final ConnectionPool pool; + private final IntSupplier inUseSupplier; + private final IntSupplier idleSupplier; private final String id; @@ -69,23 +70,25 @@ public class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsLis private final Timer totalInUseTimer; private final Counter released; - MicrometerConnectionPoolMetrics( String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry ) + MicrometerConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier, MeterRegistry registry ) { - this( poolId, address, pool, registry, Tags.empty() ); + this( poolId, address, inUseSupplier, idleSupplier, registry, Tags.empty() ); } - MicrometerConnectionPoolMetrics( String poolId, BoltServerAddress address, ConnectionPool pool, MeterRegistry registry, Iterable initialTags ) + MicrometerConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier, MeterRegistry registry, Iterable initialTags ) { Objects.requireNonNull( poolId ); Objects.requireNonNull( address ); - Objects.requireNonNull( pool ); + Objects.requireNonNull( inUseSupplier ); + Objects.requireNonNull( idleSupplier ); Objects.requireNonNull( registry ); this.id = poolId; - this.address = address; - this.pool = pool; + 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", address.connectionHost(), address.port() ) ); + "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 ); @@ -181,13 +184,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 diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java similarity index 71% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java rename to driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java index d5ed349ba3..8c625fe308 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; @@ -24,13 +24,14 @@ 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.internal.BoltServerAddress; -import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; +import org.neo4j.driver.internal.metrics.DevNullPoolMetricsListener; +import org.neo4j.driver.net.ServerAddress; -public class MicrometerMetrics implements Metrics, MetricsListener +final class MicrometerMetrics implements Metrics, MetricsListener { private final MeterRegistry meterRegistry; private final Map connectionPoolMetrics; @@ -114,9 +115,9 @@ public ListenerEvent createListenerEvent() } @Override - public void putPoolMetrics( String poolId, BoltServerAddress address, ConnectionPoolImpl connectionPool ) + public void registerPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier ) { - this.connectionPoolMetrics.put( poolId, new MicrometerConnectionPoolMetrics( poolId, address, connectionPool, this.meterRegistry ) ); + this.connectionPoolMetrics.put( poolId, new MicrometerConnectionPoolMetrics( poolId, address, inUseSupplier, idleSupplier, this.meterRegistry ) ); } // For testing purposes only @@ -136,61 +137,8 @@ private ConnectionPoolMetricsListener poolMetricsListener( String poolId ) ConnectionPoolMetricsListener poolMetrics = (ConnectionPoolMetricsListener) this.connectionPoolMetrics.get( poolId ); if ( poolMetrics == null ) { - return DEV_NULL_POOL_METRICS_LISTENER; + return DevNullPoolMetricsListener.INSTANCE; } return poolMetrics; } - - 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 ) - { - } - }; } diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java similarity index 76% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java rename to driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java index d05f96c7a5..87e9f616c7 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java @@ -16,17 +16,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; import org.neo4j.driver.Metrics; +import org.neo4j.driver.MetricsAdapter; -public class MicrometerMetricsProvider implements MetricsProvider +/** + * An adapter to bridge between the driver metrics and a Micrometer {@link MeterRegistry meter registry}. + */ +public final class MicrometerMetricsAdapter implements MetricsAdapter { private final MicrometerMetrics metrics; - public MicrometerMetricsProvider( MeterRegistry meterRegistry ) + public MicrometerMetricsAdapter( MeterRegistry meterRegistry ) { this.metrics = new MicrometerMetrics( meterRegistry ); } @@ -42,10 +46,4 @@ public MetricsListener metricsListener() { return this.metrics; } - - @Override - public boolean isMetricsEnabled() - { - return true; - } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java similarity index 90% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java rename to driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java index 75118a095b..9227c9002f 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; -public class MicrometerTimerListenerEvent implements ListenerEvent +final class MicrometerTimerListenerEvent implements ListenerEvent { private final MeterRegistry meterRegistry; private Timer.Sample sample; diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java index 69d87c2971..2c71fdc1c0 100644 --- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java +++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java @@ -18,8 +18,6 @@ */ package org.neo4j.driver; -import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -369,7 +367,7 @@ void shouldErrorWithInvalidUserAgent() void shouldNotHaveMeterRegistryByDefault() { Config config = Config.builder().build(); - Optional meterRegistryOpt = config.meterRegistry(); + Optional meterRegistryOpt = config.metricsAdapter(); assertFalse( meterRegistryOpt.isPresent() ); assertFalse( config.isMetricsEnabled() ); @@ -379,21 +377,21 @@ void shouldNotHaveMeterRegistryByDefault() void shouldNotAcceptNullMeterRegistry() { Config.ConfigBuilder builder = Config.builder(); - assertThrows( NullPointerException.class, () -> builder.withMicrometerDriverMetrics( null ) ); + assertThrows( NullPointerException.class, () -> builder.withMetricsAdapter( null ) ); } @Test - void shouldSetMeterRegistry() + void shouldSetMetricsAdapter() { - MeterRegistry registry = new SimpleMeterRegistry(); + MetricsAdapter adapter = mock(MetricsAdapter.class); Config config = Config.builder() - .withMicrometerDriverMetrics( registry ) + .withMetricsAdapter( adapter ) .build(); - Optional meterRegistryOpt = config.meterRegistry(); + Optional meterRegistryOpt = config.metricsAdapter(); assertTrue( meterRegistryOpt.isPresent() ); - assertEquals( registry, meterRegistryOpt.get() ); + assertEquals( adapter, meterRegistryOpt.get() ); assertTrue( config.isMetricsEnabled() ); } @@ -472,6 +470,23 @@ void shouldSerializeSerializableLogging() throws IOException, ClassNotFoundExcep } ); } + // No point in trying to make the adapter implementations serializable + @Test + void shouldNotTryToSerializeMetricsAdapter() throws IOException, ClassNotFoundException + { + Config config = Config.builder() + .withMetricsAdapter( mock(MetricsAdapter.class) ) + .build(); + + assertTrue( config.metricsAdapter().isPresent() ); + assertTrue( config.isMetricsEnabled() ); + + Config verify = TestUtil.serializeAndReadBack( config, Config.class ); + + assertFalse( verify.metricsAdapter().isPresent() ); + assertTrue( verify.isMetricsEnabled() ); + } + @ParameterizedTest @ValueSource( classes = {DevNullLogging.class, JULogging.class, ConsoleLogging.class, Slf4jLogging.class} ) void officialLoggingProvidersShouldBeSerializable( Class loggingClass ) diff --git a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java index 8c6a928730..b4b7db32db 100644 --- a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java +++ b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java @@ -33,7 +33,6 @@ import org.neo4j.driver.internal.DriverFactory; import org.neo4j.driver.internal.InternalDriver; import org.neo4j.driver.internal.cluster.RoutingSettings; -import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.retry.RetryLogic; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.spi.ConnectionPool; @@ -221,7 +220,7 @@ private MockSupplyingDriverFactory( List drivers ) @Override protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, - MetricsProvider metricsProvider, Config config ) + MetricsAdapter metricsAdapter, Config config ) { return driverIterator.next(); } 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..b0a06894c1 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java @@ -53,7 +53,8 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; 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.MetricsAdapter; +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; @@ -474,7 +474,7 @@ private static class DriverFactoryWithConnectionPool extends DriverFactory @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider ignored, Config config, boolean ownsEventLoopGroup, + MetricsAdapter ignored, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { ConnectionSettings connectionSettings = new ConnectionSettings( authToken, "test", 1000 ); @@ -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 index 94ab8cb9e9..01d8636e43 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java @@ -31,6 +31,7 @@ import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.QueryRunner; import org.neo4j.driver.Result; +import org.neo4j.driver.metrics.MicrometerMetricsAdapter; import org.neo4j.driver.util.DatabaseExtension; import org.neo4j.driver.util.ParallelizableIT; @@ -49,7 +50,8 @@ class MetricsIT @BeforeEach void createDriver() { - driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), Config.builder().withMicrometerDriverMetrics( meterRegistry ).build() ); + driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), + Config.builder().withMetricsAdapter( new MicrometerMetricsAdapter( meterRegistry ) ).build() ); } @AfterEach diff --git a/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java b/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java index b470953687..3a031670ec 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java @@ -30,7 +30,7 @@ import org.neo4j.driver.Config; 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.MetricsAdapter; import org.neo4j.driver.internal.retry.RetrySettings; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.spi.ConnectionPool; @@ -67,19 +67,19 @@ private static class SecurityPlanCapturingDriverFactory extends DriverFactory List capturedSecurityPlans = new ArrayList<>(); @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) { capturedSecurityPlans.add( securityPlan ); - return super.createDriver( securityPlan, sessionFactory, metricsProvider, config ); + return super.createDriver( securityPlan, sessionFactory, metricsAdapter, config ); } @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { capturedSecurityPlans.add( securityPlan ); - return super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, routingContext ); + return super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, routingContext ); } } } 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 d150e4bca0..c565d09281 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java @@ -18,7 +18,6 @@ */ package org.neo4j.driver.internal; -import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.netty.bootstrap.Bootstrap; import io.netty.util.concurrent.EventExecutorGroup; @@ -42,9 +41,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.InternalMetricsProvider; -import org.neo4j.driver.internal.metrics.MetricsProvider; -import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; +import org.neo4j.driver.internal.metrics.DevNullMetricsAdapter; +import org.neo4j.driver.internal.metrics.InternalMetricsAdapter; +import org.neo4j.driver.MetricsAdapter; +import org.neo4j.driver.metrics.MicrometerMetricsAdapter; import org.neo4j.driver.internal.retry.RetryLogic; import org.neo4j.driver.internal.retry.RetrySettings; import org.neo4j.driver.internal.security.SecurityPlan; @@ -55,6 +55,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; @@ -68,7 +69,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; @@ -156,9 +156,9 @@ void shouldNotCreateDriverMetrics() Config config = mock( Config.class ); when( config.isMetricsEnabled() ).thenReturn( false ); // When - MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM ); + MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider, is( METRICS_DISABLED_PROVIDER ) ); + assertThat( provider, is(equalTo( DevNullMetricsAdapter.INSTANCE ) ) ); } @Test @@ -169,26 +169,23 @@ void shouldCreateDriverMetricsIfMonitoringEnabled() when( config.isMetricsEnabled() ).thenReturn( true ); when( config.logging() ).thenReturn( Logging.none() ); // When - MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM ); + MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider.isMetricsEnabled(), is( true ) ); - assertThat( provider instanceof InternalMetricsProvider, is( true ) ); + assertThat( provider instanceof InternalMetricsAdapter, is( true ) ); } @Test void shouldCreateMicrometerDriverMetricsIfMonitoringEnabled() { // Given - MeterRegistry registry = new SimpleMeterRegistry(); Config config = mock( Config.class ); when( config.isMetricsEnabled() ).thenReturn( true ); - when( config.meterRegistry() ).thenReturn( Optional.of( registry ) ); + when( config.metricsAdapter() ).thenReturn( Optional.of( new MicrometerMetricsAdapter( new SimpleMeterRegistry() ) ) ); when( config.logging() ).thenReturn( Logging.none() ); // When - MetricsProvider provider = DriverFactory.createDriverMetrics( config, Clock.SYSTEM ); + MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider.isMetricsEnabled(), is( true ) ); - assertThat( provider instanceof MicrometerMetricsProvider, is( true ) ); + assertThat( provider instanceof MicrometerMetricsAdapter, is( true ) ); } @ParameterizedTest @@ -242,21 +239,21 @@ private static class ThrowingDriverFactory extends DriverFactory } @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) { throw new UnsupportedOperationException( "Can't create direct driver" ); } @Override protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, - EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsProvider metricsProvider, Config config ) + EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsAdapter metricsAdapter, Config config ) { throw new UnsupportedOperationException( "Can't create routing driver" ); } @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPool; @@ -268,7 +265,7 @@ private static class SessionFactoryCapturingDriverFactory extends DriverFactory SessionFactory capturedSessionFactory; @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) { InternalDriver driver = mock( InternalDriver.class ); when( driver.verifyConnectivityAsync() ).thenReturn( completedWithNull() ); @@ -293,7 +290,7 @@ protected SessionFactory createSessionFactory( ConnectionProvider connectionProv @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPoolMock(); } @@ -316,7 +313,7 @@ protected Bootstrap createBootstrap( int ignored ) @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPoolMock(); } 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..372fc3e2b4 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.MetricsAdapter; 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.metrics.DevNullMetricsAdapter; 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; @@ -107,7 +107,7 @@ void shouldThrowClientExceptionIfMetricsNotEnabled() throws Throwable } @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, DevNullMetricsAdapter.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 ); - return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, metricsProvider, DEV_NULL_LOGGING ); + MetricsAdapter metricsAdapter = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); + return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, metricsAdapter, 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 d1794dd84f..fbe80f8f4d 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; @@ -62,7 +63,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; @@ -630,7 +630,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 676dfc532f..8a93c67c16 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/async/pool/TestConnectionPool.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java index d317231aa0..0d4203e2e0 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java @@ -30,8 +30,8 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.internal.metrics.ListenerEvent; -import org.neo4j.driver.internal.metrics.MetricsListener; +import org.neo4j.driver.metrics.ListenerEvent; +import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.util.Clock; 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..24c653d013 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.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/util/FailingConnectionDriverFactory.java b/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java index 2aaa4c9bf5..5bdf7575c5 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.MetricsAdapter; 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 { @@ -44,10 +45,10 @@ public class FailingConnectionDriverFactory extends DriverFactory @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { - ConnectionPool pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, + ConnectionPool pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, routingContext ); return new ConnectionPoolWithFailingConnections( pool, nextRunFailure ); } @@ -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..d0cb897a1e 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,12 +25,12 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import org.neo4j.driver.MetricsAdapter; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.ConnectionSettings; import org.neo4j.driver.internal.async.connection.BootstrapFactory; import org.neo4j.driver.internal.async.connection.ChannelConnector; import org.neo4j.driver.internal.cluster.RoutingContext; -import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.spi.ConnectionPool; import org.neo4j.driver.internal.util.Clock; @@ -75,9 +75,9 @@ protected final ChannelConnector createConnector( ConnectionSettings settings, S @Override protected final ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { - pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, routingContext ); + pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, routingContext ); return pool; } diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java similarity index 86% rename from driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java rename to driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java index b6bf0ff2fa..79a78be7e9 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java +++ b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; @@ -25,6 +25,8 @@ 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; @@ -43,6 +45,10 @@ class MicrometerConnectionPoolMetricsTest 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() @@ -50,7 +56,7 @@ void beforeEach() address = new BoltServerAddress( "host", "127.0.0.1", 7687 ); pool = mock( ConnectionPool.class ); registry = new SimpleMeterRegistry(); - metrics = new MicrometerConnectionPoolMetrics( ID, address, pool, registry ); + metrics = new MicrometerConnectionPoolMetrics( ID, address, inUseSupplier, idleSupplier, registry ); } @Test @@ -214,39 +220,49 @@ void shouldIncrementReleasedAndStopTimerOnReleased() } @Test - void shouldDelegateToPoolOnInUse() + void shouldUseInUseSupplier() { - // GIVEN - int expected = 5; - given( pool.inUseConnections( address ) ).willReturn( expected ); - ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class ); - given( expectedMetrics.inUse() ).willReturn( expected ); - - // WHEN - int actual = metrics.inUse(); - - // THEN - assertEquals( expected, actual ); - then( pool ).should().inUseConnections( address ); - verifyMetrics( expectedMetrics, metrics ); + 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 shouldDelegateToPoolOnIdle() + void shouldUseIdleSupplier() { - // GIVEN - int expected = 5; - given( pool.idleConnections( address ) ).willReturn( expected ); - ConnectionPoolMetrics expectedMetrics = mock( ConnectionPoolMetrics.class ); - given( expectedMetrics.idle() ).willReturn( expected ); - - // WHEN - int actual = metrics.idle(); - - // THEN - assertEquals( expected, actual ); - then( pool ).should().idleConnections( address ); - verifyMetrics( expectedMetrics, metrics ); + 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 ) diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java similarity index 78% rename from driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java rename to driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java index 0268dcb9ea..8352d6cf72 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java +++ b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; @@ -26,15 +26,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -class MicrometerMetricsProviderTest +class MicrometerMetricsAdapterTest { - MicrometerMetricsProvider provider; + MicrometerMetricsAdapter provider; MeterRegistry registry; @BeforeEach void beforeEach() { - provider = new MicrometerMetricsProvider( registry ); + provider = new MicrometerMetricsAdapter( registry ); } @Test @@ -56,14 +56,4 @@ void shouldReturnMicrometerMetricsOnMetricsListener() // THEN assertTrue( listener instanceof MicrometerMetrics ); } - - @Test - void shouldReportMetricsEnabled() - { - // GIVEN & WHEN - boolean metricsEnabled = provider.isMetricsEnabled(); - - // THEN - assertTrue( metricsEnabled ); - } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java similarity index 96% rename from driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java rename to driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java index 7b1c354de6..8d44daf154 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java +++ b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; @@ -28,7 +28,6 @@ import org.neo4j.driver.ConnectionPoolMetrics; import org.neo4j.driver.internal.BoltServerAddress; -import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -226,7 +225,7 @@ void shouldPutPoolMetrics() int size = metrics.connectionPoolMetrics().size(); // WHEN - metrics.putPoolMetrics( ID, BoltServerAddress.LOCAL_DEFAULT, mock( ConnectionPoolImpl.class ) ); + metrics.registerPoolMetrics( ID, BoltServerAddress.LOCAL_DEFAULT, () -> 23, () -> 42 ); // 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/metrics/MicrometerTimerListenerEventTest.java similarity index 97% rename from driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java rename to driver/src/test/java/org/neo4j/driver/metrics/MicrometerTimerListenerEventTest.java index 4513ae532b..f4031e5f53 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java +++ b/driver/src/test/java/org/neo4j/driver/metrics/MicrometerTimerListenerEventTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.internal.metrics; +package org.neo4j.driver.metrics; import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java index bc69c22ea2..fe150a329d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java @@ -26,12 +26,14 @@ import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import reactor.core.publisher.Mono; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import org.neo4j.driver.Metrics; import org.neo4j.driver.internal.BoltServerAddress; -import org.neo4j.driver.internal.metrics.InternalConnectionPoolMetrics; +import org.neo4j.driver.net.ServerAddress; @Getter @Setter @@ -63,11 +65,20 @@ private ConnectionPoolMetrics getConnectionPoolMetrics( TestkitState testkitStat Metrics metrics = driverHolder.getDriver().metrics(); org.neo4j.driver.ConnectionPoolMetrics poolMetrics = metrics.connectionPoolMetrics().stream() - .map( InternalConnectionPoolMetrics.class::cast ) .filter( pm -> { - BoltServerAddress address = new BoltServerAddress( data.getAddress() ); - BoltServerAddress poolAddress = pm.getAddress(); + // Brute forcing the access via reflections avoid having the InternalConnectionPoolMetrics a public class + ServerAddress poolAddress; + try + { + Method m = pm.getClass().getDeclaredMethod("getAddress"); + poolAddress = (ServerAddress) m.invoke( pm ); + } + catch ( NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) + { + return false; + } + ServerAddress address = new BoltServerAddress( data.getAddress() ); return address.host().equals( poolAddress.host() ) && address.port() == poolAddress.port(); } ) .findFirst() From f56e4bc40bceef3a6052618d8f8a2d003e280f29 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Wed, 2 Feb 2022 18:18:26 +0100 Subject: [PATCH 05/24] Saving a file before commiting seems to be relevant. --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ef0d0fa810..1c8348c807 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,4 @@ - 4.0.0 @@ -124,6 +124,8 @@ io.micrometer micrometer-core ${micrometer.version} + provided + true From 6957633b6947b3ae954f6105e480feea3a8caddc Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Thu, 3 Feb 2022 08:50:36 +0100 Subject: [PATCH 06/24] Not messing up the file while saven even more so. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c8348c807..c16b29e0ed 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,4 @@ -d 4.0.0 From afc433f4e230889f77e56ae568b6034b74b7ea75 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Thu, 3 Feb 2022 11:27:45 +0100 Subject: [PATCH 07/24] Make interfaces internal again, provide an enum to select the provider, use global registry by default. This change keeps the existing serialization feature of config correct. It will work for everyone just using micrometer as is with the global registry. if there is a need to select the registriy, we can work on that later. --- .../main/java/org/neo4j/driver/Config.java | 34 ++++++------ .../java/org/neo4j/driver/MetricsAdapter.java | 20 ++++--- .../neo4j/driver/internal/DriverFactory.java | 52 +++++++++++-------- .../neo4j/driver/internal/InternalDriver.java | 14 ++--- .../internal/async/NetworkConnection.java | 4 +- .../async/pool/ConnectionPoolImpl.java | 4 +- .../internal/async/pool/NettyChannelPool.java | 2 +- .../async/pool/NettyChannelTracker.java | 4 +- .../async/pool/NetworkConnectionFactory.java | 2 +- .../ConnectionPoolMetricsListener.java | 4 +- .../metrics/DevNullListenerEvent.java | 2 - .../metrics/DevNullMetricsListener.java | 2 - ...apter.java => DevNullMetricsProvider.java} | 4 +- .../metrics/DevNullPoolMetricsListener.java | 5 +- .../InternalConnectionPoolMetrics.java | 2 - .../internal/metrics/InternalMetrics.java | 3 -- ...pter.java => InternalMetricsProvider.java} | 6 +-- .../{ => internal}/metrics/ListenerEvent.java | 2 +- .../metrics/MetricsListener.java | 2 +- .../internal/metrics/MetricsProvider.java | 38 ++++++++++++++ .../MicrometerConnectionPoolMetrics.java | 2 +- .../metrics/MicrometerMetrics.java | 3 +- .../metrics/MicrometerMetricsProvider.java} | 17 ++++-- .../metrics/MicrometerTimerListenerEvent.java | 2 +- .../metrics/TimeRecorderListenerEvent.java | 1 - .../java/org/neo4j/driver/ConfigTest.java | 34 +++--------- .../org/neo4j/driver/GraphDatabaseTest.java | 3 +- .../integration/ConnectionHandlingIT.java | 4 +- .../neo4j/driver/integration/MetricsIT.java | 5 +- .../internal/CustomSecurityPlanTest.java | 10 ++-- .../driver/internal/DriverFactoryTest.java | 35 +++++++------ .../driver/internal/InternalDriverTest.java | 10 ++-- .../async/pool/TestConnectionPool.java | 4 +- .../RoutingTableAndConnectionPoolTest.java | 2 +- .../MicrometerConnectionPoolMetricsTest.java | 2 +- .../MicrometerMetricsProviderTest.java} | 9 ++-- .../metrics/MicrometerMetricsTest.java | 6 +-- .../MicrometerTimerListenerEventTest.java | 2 +- .../util/FailingConnectionDriverFactory.java | 6 +-- .../util/io/ChannelTrackingDriverFactory.java | 6 +-- 40 files changed, 198 insertions(+), 171 deletions(-) rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/ConnectionPoolMetricsListener.java (96%) rename driver/src/main/java/org/neo4j/driver/internal/metrics/{DevNullMetricsAdapter.java => DevNullMetricsProvider.java} (89%) rename driver/src/main/java/org/neo4j/driver/internal/metrics/{InternalMetricsAdapter.java => InternalMetricsProvider.java} (83%) rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/ListenerEvent.java (94%) rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/MetricsListener.java (98%) create mode 100644 driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/MicrometerConnectionPoolMetrics.java (99%) rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/MicrometerMetrics.java (97%) rename driver/src/main/java/org/neo4j/driver/{metrics/MicrometerMetricsAdapter.java => internal/metrics/MicrometerMetricsProvider.java} (71%) rename driver/src/main/java/org/neo4j/driver/{ => internal}/metrics/MicrometerTimerListenerEvent.java (96%) rename driver/src/test/java/org/neo4j/driver/{ => internal}/metrics/MicrometerConnectionPoolMetricsTest.java (99%) rename driver/src/test/java/org/neo4j/driver/{metrics/MicrometerMetricsAdapterTest.java => internal/metrics/MicrometerMetricsProviderTest.java} (87%) rename driver/src/test/java/org/neo4j/driver/{ => internal}/metrics/MicrometerMetricsTest.java (96%) rename driver/src/test/java/org/neo4j/driver/{ => internal}/metrics/MicrometerTimerListenerEventTest.java (97%) diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index b60cd370b1..25abebf7b0 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -31,9 +31,9 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil; +import org.neo4j.driver.internal.metrics.MetricsProvider; +import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; import org.neo4j.driver.internal.retry.RetrySettings; -import org.neo4j.driver.internal.metrics.DevNullMetricsAdapter; -import org.neo4j.driver.metrics.MicrometerMetricsAdapter; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.Experimental; import org.neo4j.driver.util.Immutable; @@ -96,10 +96,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 transient MetricsAdapter metricsAdapter; + private final MetricsAdapter metricsAdapter; private Config( ConfigBuilder builder ) { @@ -123,7 +122,6 @@ private Config( ConfigBuilder builder ) this.fetchSize = builder.fetchSize; this.eventLoopThreads = builder.eventLoopThreads; - this.isMetricsEnabled = builder.isMetricsEnabled; this.metricsAdapter = builder.metricsAdapter; } @@ -262,12 +260,12 @@ public int eventLoopThreads() */ public boolean isMetricsEnabled() { - return isMetricsEnabled; + return this.metricsAdapter != MetricsAdapter.DEV_NULL; } - public Optional metricsAdapter() + public MetricsAdapter metricsAdapter() { - return Optional.ofNullable( metricsAdapter ); + return this.metricsAdapter; } /** @@ -297,8 +295,7 @@ public static class ConfigBuilder private int connectionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis( 30 ); private RetrySettings retrySettings = RetrySettings.DEFAULT; private ServerAddressResolver resolver; - private MetricsAdapter metricsAdapter; - private boolean isMetricsEnabled = false; + private MetricsAdapter metricsAdapter = MetricsAdapter.DEV_NULL; private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE; private int eventLoopThreads = 0; @@ -731,8 +728,14 @@ public ConfigBuilder withoutDriverMetrics() private ConfigBuilder withMetricsEnabled( boolean enabled ) { - this.isMetricsEnabled = enabled; - this.metricsAdapter = null; + if ( !enabled ) + { + this.metricsAdapter = MetricsAdapter.DEV_NULL; + } + else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.DEV_NULL ) + { + this.metricsAdapter = MetricsAdapter.DEFAULT; + } return this; } @@ -741,19 +744,16 @@ private ConfigBuilder withMetricsEnabled( boolean enabled ) *

* We offer an implementation based on Micrometer. * The metrics can be obtained afterwards via Micrometer means and {@link Driver#metrics()}. - * You must have Micrometer on classpath to use the provided {@link MicrometerMetricsAdapter}. + * You must have Micrometer on classpath to use the provided {@link MicrometerMetricsProvider}. *

- * This configuration setting is not serialiable. If metrics had been enabled in a configuration - * that was serialized inbetween usage, it will default to the internal adapter. * - * @param metricsAdapter the metrics provider to use. Use {@literal null} to disable metrics again. + * @param metricsAdapter the metrics adapter to use. Use {@link MetricsAdapter#DEV_NULL} to disable metrics again. * @return this builder. */ @Experimental public ConfigBuilder withMetricsAdapter( MetricsAdapter metricsAdapter ) { this.metricsAdapter = Objects.requireNonNull( metricsAdapter, "metricsAdapter" ); - this.isMetricsEnabled = this.metricsAdapter != DevNullMetricsAdapter.INSTANCE; return this; } diff --git a/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java index 55c2439d49..f6d80c7833 100644 --- a/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java +++ b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java @@ -18,20 +18,24 @@ */ package org.neo4j.driver; -import org.neo4j.driver.metrics.MetricsListener; - /** - * An adapter that can collect driver metrics via a {@link MetricsListener} and publishes them via a {@link Metrics} instance. + * Defines which metrics consumer to use: Should metrics be consumed and exposed via the drivers default consumer or + * provided with one of the external facades. */ -public interface MetricsAdapter +public enum MetricsAdapter { /** - * @return The actual metrics type to use + * Disables metrics. + */ + DEV_NULL, + + /** + * Consumes and publishes metrics via the driver itself. */ - Metrics metrics(); + DEFAULT, /** - * @return A listener that will be notified on certain events so that it can collect metrics about them. + * Consumes and publishes metrics via Micrometer. Make sure you put Micrometer on the classpath before using this option. */ - MetricsListener metricsListener(); + 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 8d14e8ceec..63035a0f8e 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java @@ -43,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.DevNullMetricsAdapter; -import org.neo4j.driver.internal.metrics.InternalMetricsAdapter; +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; @@ -94,15 +96,15 @@ public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings r EventExecutorGroup eventExecutorGroup = bootstrap.config().group(); RetryLogic retryLogic = createRetryLogic( retrySettings, eventExecutorGroup, config.logging() ); - MetricsAdapter metricsAdapter = getOrCreateMetricsProvider( config, createClock() ); - ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, + MetricsProvider metricsProvider = getOrCreateMetricsProvider( config, createClock() ); + ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, newRoutingSettings.routingContext() ); - return createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsAdapter, config ); + return createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsProvider, config ); } protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { Clock clock = createClock(); ConnectionSettings settings = new ConnectionSettings( authToken, config.userAgent(), config.connectionTimeoutMillis() ); @@ -111,19 +113,27 @@ protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan config.connectionAcquisitionTimeoutMillis(), config.maxConnectionLifetimeMillis(), config.idleTimeBeforeConnectionTest() ); - return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsAdapter.metricsListener(), config.logging(), clock, ownsEventLoopGroup ); + return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsProvider.metricsListener(), config.logging(), clock, ownsEventLoopGroup ); } - protected static MetricsAdapter getOrCreateMetricsProvider( 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 config.metricsAdapter().orElseGet( () -> new InternalMetricsAdapter( clock, config.logging() ) ); + metricsAdapter = config.isMetricsEnabled() ? MetricsAdapter.DEFAULT : MetricsAdapter.DEV_NULL; } - else + switch ( metricsAdapter ) { - return DevNullMetricsAdapter.INSTANCE; + 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, @@ -134,7 +144,7 @@ protected ChannelConnector createConnector( ConnectionSettings settings, Securit private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, - MetricsAdapter metricsAdapter, Config config ) + MetricsProvider metricsProvider, Config config ) { try { @@ -142,12 +152,12 @@ private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltSer if ( isRoutingScheme( scheme ) ) { - return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsAdapter, config ); + return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsProvider, config ); } else { assertNoRoutingContext( uri, routingSettings ); - return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metricsAdapter, config ); + return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metricsProvider, config ); } } catch ( Throwable driverError ) @@ -164,11 +174,11 @@ private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltSer * This method is protected only for testing */ protected InternalDriver createDirectDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, RetryLogic retryLogic, - MetricsAdapter metricsAdapter, Config config ) + MetricsProvider metricsProvider, Config config ) { ConnectionProvider connectionProvider = new DirectConnectionProvider( address, connectionPool ); SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config ); - InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsAdapter, config ); + InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsProvider, config ); Logger log = config.logging().getLog( getClass() ); log.info( "Direct driver instance %s created for server address %s", driver.hashCode(), address ); return driver; @@ -180,12 +190,12 @@ protected InternalDriver createDirectDriver( SecurityPlan securityPlan, BoltServ * This method is protected only for testing */ protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, - EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsAdapter metricsAdapter, Config config ) + EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsProvider metricsProvider, Config config ) { ConnectionProvider connectionProvider = createLoadBalancer( address, connectionPool, eventExecutorGroup, config, routingSettings ); SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config ); - InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsAdapter, config ); + InternalDriver driver = createDriver( securityPlan, sessionFactory, metricsProvider, config ); Logger log = config.logging().getLog( getClass() ); log.info( "Routing driver instance %s created for server address %s", driver.hashCode(), address ); return driver; @@ -196,9 +206,9 @@ protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltSer *

* This method is protected only for testing */ - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) { - return new InternalDriver( securityPlan, sessionFactory, metricsAdapter, config.logging() ); + return new InternalDriver( securityPlan, sessionFactory, metricsProvider, config.logging() ); } /** 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 d3bd6c1a17..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,13 +25,13 @@ import org.neo4j.driver.Logger; import org.neo4j.driver.Logging; import org.neo4j.driver.Metrics; -import org.neo4j.driver.MetricsAdapter; +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.DevNullMetricsAdapter; +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; @@ -48,13 +48,13 @@ public class InternalDriver implements Driver private final Logger log; private AtomicBoolean closed = new AtomicBoolean( false ); - private final MetricsAdapter metricsAdapter; + private final MetricsProvider metricsProvider; - InternalDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Logging logging ) + InternalDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Logging logging ) { this.securityPlan = securityPlan; this.sessionFactory = sessionFactory; - this.metricsAdapter = metricsAdapter; + this.metricsProvider = metricsProvider; this.log = logging.getLog( getClass() ); } @@ -97,13 +97,13 @@ public AsyncSession asyncSession( SessionConfig sessionConfig ) @Override public Metrics metrics() { - return metricsAdapter.metrics(); + return metricsProvider.metrics(); } @Override public boolean isMetricsEnabled() { - return metricsAdapter != DevNullMetricsAdapter.INSTANCE; + return metricsProvider != DevNullMetricsProvider.INSTANCE; } @Override diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java index 5bd5689a2b..c8916aaf32 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkConnection.java @@ -38,8 +38,8 @@ import org.neo4j.driver.internal.messaging.BoltProtocol; import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.messaging.request.ResetMessage; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.MetricsListener; +import org.neo4j.driver.internal.metrics.ListenerEvent; +import org.neo4j.driver.internal.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.internal.util.Clock; 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 a8e2277ccb..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 @@ -41,8 +41,8 @@ import org.neo4j.driver.exceptions.ServiceUnavailableException; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.MetricsListener; +import org.neo4j.driver.internal.metrics.ListenerEvent; +import org.neo4j.driver.internal.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ConnectionPool; import org.neo4j.driver.internal.util.Clock; diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java index 756e471a2c..8abdb5b30b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NettyChannelPool.java @@ -31,7 +31,7 @@ import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.metrics.ListenerEvent; +import org.neo4j.driver.internal.metrics.ListenerEvent; import static java.util.Objects.requireNonNull; import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setPoolId; 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 3997a60ec3..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 @@ -35,8 +35,8 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.messaging.BoltProtocol; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.MetricsListener; +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; diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java index 960132b6ff..1a3404e950 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/NetworkConnectionFactory.java @@ -22,7 +22,7 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.async.NetworkConnection; -import org.neo4j.driver.metrics.MetricsListener; +import org.neo4j.driver.internal.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.util.Clock; diff --git a/driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java similarity index 96% rename from driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java index 6e65f4555b..3ca86713f6 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/ConnectionPoolMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/ConnectionPoolMetricsListener.java @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; -public interface ConnectionPoolMetricsListener +interface ConnectionPoolMetricsListener { /** * Invoked before a connection is creating. 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 index 7f9553851a..6c17eab971 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullListenerEvent.java @@ -18,8 +18,6 @@ */ package org.neo4j.driver.internal.metrics; -import org.neo4j.driver.metrics.ListenerEvent; - enum DevNullListenerEvent implements ListenerEvent { INSTANCE; 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 index b40398dcfe..6b15b3c557 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java @@ -20,8 +20,6 @@ import java.util.function.IntSupplier; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.net.ServerAddress; public enum DevNullMetricsListener implements MetricsListener diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java similarity index 89% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java index 15746a77d5..2da015c98c 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsAdapter.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java @@ -19,11 +19,9 @@ package org.neo4j.driver.internal.metrics; import org.neo4j.driver.Metrics; -import org.neo4j.driver.MetricsAdapter; -import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.exceptions.ClientException; -public enum DevNullMetricsAdapter implements MetricsAdapter +public enum DevNullMetricsProvider implements MetricsProvider { 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 index 943c6dc39f..3d4dcc74e6 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullPoolMetricsListener.java @@ -18,10 +18,7 @@ */ package org.neo4j.driver.internal.metrics; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; - -public enum DevNullPoolMetricsListener implements ConnectionPoolMetricsListener +enum DevNullPoolMetricsListener implements ConnectionPoolMetricsListener { INSTANCE; 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 f7e16d72c4..7b4807a017 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 @@ -24,8 +24,6 @@ import java.util.function.IntSupplier; import org.neo4j.driver.ConnectionPoolMetrics; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; import org.neo4j.driver.net.ServerAddress; import static java.lang.String.format; 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 e378b49957..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 @@ -25,13 +25,10 @@ import java.util.function.IntSupplier; import org.neo4j.driver.ConnectionPoolMetrics; -import org.neo4j.driver.metrics.ListenerEvent; import org.neo4j.driver.Logger; import org.neo4j.driver.Logging; import org.neo4j.driver.Metrics; -import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.util.Clock; -import org.neo4j.driver.metrics.ConnectionPoolMetricsListener; import org.neo4j.driver.net.ServerAddress; import static java.lang.String.format; diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java similarity index 83% rename from driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsAdapter.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java index 39f21c0086..0980dbf218 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsAdapter.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/InternalMetricsProvider.java @@ -19,16 +19,14 @@ package org.neo4j.driver.internal.metrics; import org.neo4j.driver.Logging; -import org.neo4j.driver.MetricsAdapter; -import org.neo4j.driver.metrics.MetricsListener; import org.neo4j.driver.internal.util.Clock; import org.neo4j.driver.Metrics; -public final class InternalMetricsAdapter implements MetricsAdapter +public final class InternalMetricsProvider implements MetricsProvider { private final InternalMetrics metrics; - public InternalMetricsAdapter( Clock clock, Logging logging ) + public InternalMetricsProvider( Clock clock, Logging logging ) { this.metrics = new InternalMetrics( clock, logging ); } diff --git a/driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java similarity index 94% rename from driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java index 85c98ce3c6..543ee0e723 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/ListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/ListenerEvent.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; public interface ListenerEvent { diff --git a/driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java similarity index 98% rename from driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java index 26450d27e4..48e5710b2a 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/MetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import java.util.concurrent.TimeUnit; import java.util.function.IntSupplier; 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 new file mode 100644 index 0000000000..854ddbd382 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsProvider.java @@ -0,0 +1,38 @@ +/* + * 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.internal.metrics.MetricsListener; + +/** + * An adapter that can collect driver metrics via a {@link MetricsListener} and publishes them via a {@link Metrics} instance. + */ +public interface MetricsProvider +{ + /** + * @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(); +} diff --git a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java similarity index 99% rename from driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java index 8ca77d26ea..be34a34ca2 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.Gauge; diff --git a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java similarity index 97% rename from driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java index 8c625fe308..f3b4eaf134 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetrics.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; @@ -28,7 +28,6 @@ import org.neo4j.driver.ConnectionPoolMetrics; import org.neo4j.driver.Metrics; -import org.neo4j.driver.internal.metrics.DevNullPoolMetricsListener; import org.neo4j.driver.net.ServerAddress; final class MicrometerMetrics implements Metrics, MetricsListener diff --git a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java similarity index 71% rename from driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java index 87e9f616c7..961443bd69 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerMetricsAdapter.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java @@ -16,21 +16,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; import org.neo4j.driver.Metrics; -import org.neo4j.driver.MetricsAdapter; /** * An adapter to bridge between the driver metrics and a Micrometer {@link MeterRegistry meter registry}. */ -public final class MicrometerMetricsAdapter implements MetricsAdapter +public final class MicrometerMetricsProvider implements MetricsProvider { private final MicrometerMetrics metrics; - public MicrometerMetricsAdapter( MeterRegistry meterRegistry ) + 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 ); } diff --git a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java similarity index 96% rename from driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java rename to driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java index 9227c9002f..9258666783 100644 --- a/driver/src/main/java/org/neo4j/driver/metrics/MicrometerTimerListenerEvent.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEvent.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; 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 94d748db54..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 @@ -18,7 +18,6 @@ */ package org.neo4j.driver.internal.metrics; -import org.neo4j.driver.metrics.ListenerEvent; import org.neo4j.driver.internal.util.Clock; final class TimeRecorderListenerEvent implements ListenerEvent diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java index 2c71fdc1c0..84ce2488b8 100644 --- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java +++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java @@ -30,7 +30,6 @@ import java.io.Serializable; import java.lang.reflect.Field; import java.util.List; -import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -38,6 +37,7 @@ import org.neo4j.driver.internal.logging.DevNullLogging; import org.neo4j.driver.internal.logging.JULogging; import org.neo4j.driver.internal.logging.Slf4jLogging; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.TestUtil; @@ -367,9 +367,9 @@ void shouldErrorWithInvalidUserAgent() void shouldNotHaveMeterRegistryByDefault() { Config config = Config.builder().build(); - Optional meterRegistryOpt = config.metricsAdapter(); + MetricsAdapter metricsAdapter = config.metricsAdapter(); - assertFalse( meterRegistryOpt.isPresent() ); + assertEquals( MetricsAdapter.DEV_NULL, metricsAdapter ); assertFalse( config.isMetricsEnabled() ); } @@ -383,15 +383,12 @@ void shouldNotAcceptNullMeterRegistry() @Test void shouldSetMetricsAdapter() { - MetricsAdapter adapter = mock(MetricsAdapter.class); - Config config = Config.builder() - .withMetricsAdapter( adapter ) + .withMetricsAdapter( MetricsAdapter.DEFAULT ) .build(); - Optional meterRegistryOpt = config.metricsAdapter(); + MetricsAdapter metricsAdapter = config.metricsAdapter(); - assertTrue( meterRegistryOpt.isPresent() ); - assertEquals( adapter, meterRegistryOpt.get() ); + assertEquals( MetricsAdapter.DEFAULT, metricsAdapter ); assertTrue( config.isMetricsEnabled() ); } @@ -417,6 +414,7 @@ void shouldSerialize() throws Exception .withDriverMetrics() .withRoutingTablePurgeDelay( 50000, TimeUnit.MILLISECONDS ) .withLeakedSessionsLogging() + .withMetricsAdapter( MetricsAdapter.MICROMETER ) .build(); Config verify = TestUtil.serializeAndReadBack( config, Config.class ); @@ -439,6 +437,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() ); } @@ -470,23 +469,6 @@ void shouldSerializeSerializableLogging() throws IOException, ClassNotFoundExcep } ); } - // No point in trying to make the adapter implementations serializable - @Test - void shouldNotTryToSerializeMetricsAdapter() throws IOException, ClassNotFoundException - { - Config config = Config.builder() - .withMetricsAdapter( mock(MetricsAdapter.class) ) - .build(); - - assertTrue( config.metricsAdapter().isPresent() ); - assertTrue( config.isMetricsEnabled() ); - - Config verify = TestUtil.serializeAndReadBack( config, Config.class ); - - assertFalse( verify.metricsAdapter().isPresent() ); - assertTrue( verify.isMetricsEnabled() ); - } - @ParameterizedTest @ValueSource( classes = {DevNullLogging.class, JULogging.class, ConsoleLogging.class, Slf4jLogging.class} ) void officialLoggingProvidersShouldBeSerializable( Class loggingClass ) diff --git a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java index b4b7db32db..8c6a928730 100644 --- a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java +++ b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java @@ -33,6 +33,7 @@ import org.neo4j.driver.internal.DriverFactory; import org.neo4j.driver.internal.InternalDriver; import org.neo4j.driver.internal.cluster.RoutingSettings; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.retry.RetryLogic; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.spi.ConnectionPool; @@ -220,7 +221,7 @@ private MockSupplyingDriverFactory( List drivers ) @Override protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, - MetricsAdapter metricsAdapter, Config config ) + MetricsProvider metricsProvider, Config config ) { return driverIterator.next(); } 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 b0a06894c1..551910430b 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/ConnectionHandlingIT.java @@ -53,7 +53,7 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; import org.neo4j.driver.internal.cluster.RoutingContext; import org.neo4j.driver.internal.cluster.RoutingSettings; -import org.neo4j.driver.MetricsAdapter; +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; @@ -474,7 +474,7 @@ private static class DriverFactoryWithConnectionPool extends DriverFactory @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter ignored, Config config, boolean ownsEventLoopGroup, + MetricsProvider ignored, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { ConnectionSettings connectionSettings = new ConnectionSettings( authToken, "test", 1000 ); diff --git a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java index 01d8636e43..4c777a90ef 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/MetricsIT.java @@ -29,9 +29,10 @@ 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.metrics.MicrometerMetricsAdapter; +import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; import org.neo4j.driver.util.DatabaseExtension; import org.neo4j.driver.util.ParallelizableIT; @@ -51,7 +52,7 @@ class MetricsIT void createDriver() { driver = GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), - Config.builder().withMetricsAdapter( new MicrometerMetricsAdapter( meterRegistry ) ).build() ); + Config.builder().withMetricsAdapter( MetricsAdapter.MICROMETER ).build() ); } @AfterEach diff --git a/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java b/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java index 3a031670ec..b470953687 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/CustomSecurityPlanTest.java @@ -30,7 +30,7 @@ import org.neo4j.driver.Config; import org.neo4j.driver.internal.cluster.RoutingContext; import org.neo4j.driver.internal.cluster.RoutingSettings; -import org.neo4j.driver.MetricsAdapter; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.retry.RetrySettings; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.spi.ConnectionPool; @@ -67,19 +67,19 @@ private static class SecurityPlanCapturingDriverFactory extends DriverFactory List capturedSecurityPlans = new ArrayList<>(); @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) { capturedSecurityPlans.add( securityPlan ); - return super.createDriver( securityPlan, sessionFactory, metricsAdapter, config ); + return super.createDriver( securityPlan, sessionFactory, metricsProvider, config ); } @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { capturedSecurityPlans.add( securityPlan ); - return super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, routingContext ); + return super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, routingContext ); } } } 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 c565d09281..9f4c77c002 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java @@ -34,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; @@ -41,10 +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.DevNullMetricsAdapter; -import org.neo4j.driver.internal.metrics.InternalMetricsAdapter; -import org.neo4j.driver.MetricsAdapter; -import org.neo4j.driver.metrics.MicrometerMetricsAdapter; +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; @@ -156,9 +157,9 @@ void shouldNotCreateDriverMetrics() Config config = mock( Config.class ); when( config.isMetricsEnabled() ).thenReturn( false ); // When - MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); + MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider, is(equalTo( DevNullMetricsAdapter.INSTANCE ) ) ); + assertThat( provider, is(equalTo( DevNullMetricsProvider.INSTANCE ) ) ); } @Test @@ -169,9 +170,9 @@ void shouldCreateDriverMetricsIfMonitoringEnabled() when( config.isMetricsEnabled() ).thenReturn( true ); when( config.logging() ).thenReturn( Logging.none() ); // When - MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); + MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider instanceof InternalMetricsAdapter, is( true ) ); + assertThat( provider instanceof InternalMetricsProvider, is( true ) ); } @Test @@ -180,12 +181,12 @@ void shouldCreateMicrometerDriverMetricsIfMonitoringEnabled() // Given Config config = mock( Config.class ); when( config.isMetricsEnabled() ).thenReturn( true ); - when( config.metricsAdapter() ).thenReturn( Optional.of( new MicrometerMetricsAdapter( new SimpleMeterRegistry() ) ) ); + when( config.metricsAdapter() ).thenReturn( MetricsAdapter.MICROMETER ); when( config.logging() ).thenReturn( Logging.none() ); // When - MetricsAdapter provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); + MetricsProvider provider = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); // Then - assertThat( provider instanceof MicrometerMetricsAdapter, is( true ) ); + assertThat( provider instanceof MicrometerMetricsProvider, is( true ) ); } @ParameterizedTest @@ -239,21 +240,21 @@ private static class ThrowingDriverFactory extends DriverFactory } @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) { throw new UnsupportedOperationException( "Can't create direct driver" ); } @Override protected InternalDriver createRoutingDriver( SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool, - EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsAdapter metricsAdapter, Config config ) + EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsProvider metricsProvider, Config config ) { throw new UnsupportedOperationException( "Can't create routing driver" ); } @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPool; @@ -265,7 +266,7 @@ private static class SessionFactoryCapturingDriverFactory extends DriverFactory SessionFactory capturedSessionFactory; @Override - protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsAdapter metricsAdapter, Config config ) + protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) { InternalDriver driver = mock( InternalDriver.class ); when( driver.verifyConnectivityAsync() ).thenReturn( completedWithNull() ); @@ -290,7 +291,7 @@ protected SessionFactory createSessionFactory( ConnectionProvider connectionProv @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPoolMock(); } @@ -313,7 +314,7 @@ protected Bootstrap createBootstrap( int ignored ) @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { return connectionPoolMock(); } 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 372fc3e2b4..eb839f3c32 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java @@ -24,10 +24,10 @@ import org.neo4j.driver.Config; import org.neo4j.driver.Metrics; -import org.neo4j.driver.MetricsAdapter; +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.DevNullMetricsAdapter; import org.neo4j.driver.internal.security.SecurityPlanImpl; import org.neo4j.driver.internal.util.Clock; @@ -121,7 +121,7 @@ void shouldReturnMetricsIfMetricsEnabled() private static InternalDriver newDriver( SessionFactory sessionFactory ) { - return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, DevNullMetricsAdapter.INSTANCE, 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(); } - MetricsAdapter metricsAdapter = DriverFactory.getOrCreateMetricsProvider( config, Clock.SYSTEM ); - return new InternalDriver( SecurityPlanImpl.insecure(), sessionFactory, metricsAdapter, DEV_NULL_LOGGING ); + 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/pool/TestConnectionPool.java b/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java index 0d4203e2e0..d317231aa0 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/pool/TestConnectionPool.java @@ -30,8 +30,8 @@ import org.neo4j.driver.Logging; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.connection.ChannelConnector; -import org.neo4j.driver.metrics.ListenerEvent; -import org.neo4j.driver.metrics.MetricsListener; +import org.neo4j.driver.internal.metrics.ListenerEvent; +import org.neo4j.driver.internal.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.util.Clock; 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 24c653d013..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,7 +42,7 @@ import org.neo4j.driver.Bookmark; import org.neo4j.driver.Logging; -import org.neo4j.driver.metrics.MetricsListener; +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; diff --git a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java similarity index 99% rename from driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java rename to driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java index 79a78be7e9..31c1fe72c9 100644 --- a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerConnectionPoolMetricsTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; diff --git a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java similarity index 87% rename from driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java rename to driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java index 8352d6cf72..9d4a8bd694 100644 --- a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsAdapterTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProviderTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; @@ -26,15 +26,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -class MicrometerMetricsAdapterTest +class MicrometerMetricsProviderTest { - MicrometerMetricsAdapter provider; - MeterRegistry registry; + MetricsProvider provider; @BeforeEach void beforeEach() { - provider = new MicrometerMetricsAdapter( registry ); + provider = MicrometerMetricsProvider.forGlobalRegistry(); } @Test diff --git a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java similarity index 96% rename from driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java rename to driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java index 8d44daf154..f4dae3fe02 100644 --- a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerMetricsTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerMetricsTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; @@ -48,8 +48,8 @@ void beforeEach() { registry = new SimpleMeterRegistry(); metrics = new MicrometerMetrics( registry ); - poolMetrics = mock( ConnectionPoolMetrics.class, Mockito.withSettings().extraInterfaces( ConnectionPoolMetricsListener.class ) ); - poolMetricsListener = (ConnectionPoolMetricsListener) poolMetrics; + poolMetricsListener = mock( ConnectionPoolMetricsListener.class, Mockito.withSettings().extraInterfaces( ConnectionPoolMetrics.class ) ); + poolMetrics = (ConnectionPoolMetrics) poolMetricsListener; } @Test diff --git a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerTimerListenerEventTest.java b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java similarity index 97% rename from driver/src/test/java/org/neo4j/driver/metrics/MicrometerTimerListenerEventTest.java rename to driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java index f4031e5f53..4513ae532b 100644 --- a/driver/src/test/java/org/neo4j/driver/metrics/MicrometerTimerListenerEventTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerTimerListenerEventTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.neo4j.driver.metrics; +package org.neo4j.driver.internal.metrics; import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; 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 5bdf7575c5..73a19ba46f 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,7 +27,7 @@ import org.neo4j.driver.AuthToken; import org.neo4j.driver.Config; -import org.neo4j.driver.MetricsAdapter; +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; @@ -45,10 +45,10 @@ public class FailingConnectionDriverFactory extends DriverFactory @Override protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { - ConnectionPool pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, + ConnectionPool pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, routingContext ); return new ConnectionPoolWithFailingConnections( pool, nextRunFailure ); } 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 d0cb897a1e..7ef0d2586c 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,7 +25,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import org.neo4j.driver.MetricsAdapter; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.ConnectionSettings; import org.neo4j.driver.internal.async.connection.BootstrapFactory; @@ -75,9 +75,9 @@ protected final ChannelConnector createConnector( ConnectionSettings settings, S @Override protected final ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, - MetricsAdapter metricsAdapter, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) + MetricsProvider metricsProvider, Config config, boolean ownsEventLoopGroup, RoutingContext routingContext ) { - pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsAdapter, config, ownsEventLoopGroup, routingContext ); + pool = super.createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup, routingContext ); return pool; } From f2ca0dffbe6ad4ddf88e0d32ed44c3b097df97f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 17:52:04 +0200 Subject: [PATCH 08/24] Move micrometer-core optional tag to dependency declaration --- bundle/pom.xml | 9 +++++---- driver/pom.xml | 1 + pom.xml | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bundle/pom.xml b/bundle/pom.xml index bf8600fbee..5a32e82e7e 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -33,13 +33,14 @@ - org.slf4j - slf4j-api + io.micrometer + micrometer-core true - io.micrometer - micrometer-core + org.slf4j + slf4j-api + true org.graalvm.nativeimage diff --git a/driver/pom.xml b/driver/pom.xml index 1b87c2971b..c0ac6cbec1 100644 --- a/driver/pom.xml +++ b/driver/pom.xml @@ -40,6 +40,7 @@ io.micrometer micrometer-core + true org.slf4j diff --git a/pom.xml b/pom.xml index c16b29e0ed..dcde71325a 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,6 @@ micrometer-core ${micrometer.version} provided - true From fec69a25c226fa6d0a472d48909ccd15c7221855 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:14:02 +0200 Subject: [PATCH 09/24] Update Config javadoc and remove imports of internal metrics classes --- driver/src/main/java/org/neo4j/driver/Config.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index 25abebf7b0..2e0093c12d 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -22,7 +22,6 @@ import java.io.Serializable; import java.net.InetAddress; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -31,8 +30,6 @@ import org.neo4j.driver.internal.async.pool.PoolSettings; import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil; -import org.neo4j.driver.internal.metrics.MetricsProvider; -import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider; import org.neo4j.driver.internal.retry.RetrySettings; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.Experimental; @@ -740,14 +737,13 @@ else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.D } /** - * Enable driver metrics backed by a different metrics provider. + * Enable driver metrics with chosen {@link MetricsAdapter}. *

- * We offer an implementation based on Micrometer. - * The metrics can be obtained afterwards via Micrometer means and {@link Driver#metrics()}. - * You must have Micrometer on classpath to use the provided {@link MicrometerMetricsProvider}. + * We offer an 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 again. + * @param metricsAdapter the metrics adapter to use. Use {@link MetricsAdapter#DEV_NULL} to disable metrics. * @return this builder. */ @Experimental From 70bab1d3eaefdd1e0ae8f34067be6231d3d33676 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:30:38 +0200 Subject: [PATCH 10/24] Update withMetricsEnabled(boolean) implementation --- driver/src/main/java/org/neo4j/driver/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index 2e0093c12d..e5ed81ac44 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -727,11 +727,11 @@ private ConfigBuilder withMetricsEnabled( boolean enabled ) { if ( !enabled ) { - this.metricsAdapter = MetricsAdapter.DEV_NULL; + withMetricsAdapter( MetricsAdapter.DEV_NULL ); } else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.DEV_NULL ) { - this.metricsAdapter = MetricsAdapter.DEFAULT; + withMetricsAdapter( MetricsAdapter.DEFAULT ); } return this; } From 0e0e61ec15920f33b98c557ca0ea83ed83d46102 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:35:29 +0200 Subject: [PATCH 11/24] Enable ConfigBuilder.withMetricsAdapter documentation --- driver/src/main/java/org/neo4j/driver/Config.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index e5ed81ac44..c2728a849e 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -737,10 +737,10 @@ else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.D } /** - * Enable driver metrics with chosen {@link MetricsAdapter}. + * Enable driver metrics with given {@link MetricsAdapter}. *

- * We offer an 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. + * {@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. From 2167eeb504244147c700edd5289ddf9b72aedf2f Mon Sep 17 00:00:00 2001 From: injectives <11927660+injectives@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:37:38 +0200 Subject: [PATCH 12/24] Update driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java Co-authored-by: Gerrit Meier --- .../src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java index dd5eafc189..79f766aabd 100644 --- a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java @@ -60,7 +60,7 @@ public interface ConnectionPoolMetrics /** * A counter to record how many connections have been successfully created with this pool since the pool is created. * This number increases every time when a connection is successfully created. - * @return The amount of connections has ever been created by this pool. + * @return The amount of connections that has ever been created by this pool. */ long created(); From 0c8fe232d00b9dc77b95999b7db2b4e37fcd6677 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:39:47 +0200 Subject: [PATCH 13/24] Update ConnectionPoolMetrics documentation --- .../src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java index 79f766aabd..3c9c55115a 100644 --- a/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java @@ -58,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 that has ever been created by this pool. + * @return The amount of connections that have ever been created by this pool. */ long created(); From 479f14fe891856b3904c6ac3dcc67c302b60ab5b Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:44:28 +0200 Subject: [PATCH 14/24] Update MetricsAdapter documentation --- driver/src/main/java/org/neo4j/driver/MetricsAdapter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java index f6d80c7833..e78e93ba0a 100644 --- a/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java +++ b/driver/src/main/java/org/neo4j/driver/MetricsAdapter.java @@ -19,8 +19,7 @@ package org.neo4j.driver; /** - * Defines which metrics consumer to use: Should metrics be consumed and exposed via the drivers default consumer or - * provided with one of the external facades. + * 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 { @@ -35,7 +34,7 @@ public enum MetricsAdapter DEFAULT, /** - * Consumes and publishes metrics via Micrometer. Make sure you put Micrometer on the classpath before using this option. + * Consumes and publishes metrics via Micrometer. Ensure that Micrometer is on classpath when using this option. */ MICROMETER } From d942e0deb9a5f26a6dda13fe2258723aea80980d Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Thu, 3 Feb 2022 18:56:17 +0200 Subject: [PATCH 15/24] Update formatting in ConfigTest --- .../java/org/neo4j/driver/ConfigTest.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java index 84ce2488b8..c6b2da7644 100644 --- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java +++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java @@ -37,7 +37,6 @@ import org.neo4j.driver.internal.logging.DevNullLogging; import org.neo4j.driver.internal.logging.JULogging; import org.neo4j.driver.internal.logging.Slf4jLogging; -import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.util.TestUtil; @@ -395,31 +394,29 @@ void shouldSetMetricsAdapter() @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() - .withMetricsAdapter( MetricsAdapter.MICROMETER ) - .build(); + .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() ); @@ -445,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 ); From acf04add09b5131b0bb2142592438f5746b1a6d0 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 7 Feb 2022 18:24:34 +0200 Subject: [PATCH 16/24] Update wording --- .../neo4j/driver/internal/metrics/DevNullMetricsListener.java | 2 +- .../neo4j/driver/internal/metrics/DevNullMetricsProvider.java | 2 +- .../org/neo4j/driver/internal/metrics/MetricsProvider.java | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) 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 index 6b15b3c557..5894e703a1 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java @@ -95,6 +95,6 @@ public void removePoolMetrics( String poolId ) @Override public String toString() { - return "Driver metrics not available while driver metrics is not enabled."; + return "Driver metrics are not available when 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 index 2da015c98c..3cf250cb4d 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsProvider.java @@ -30,7 +30,7 @@ public Metrics metrics() { // To outside users, we forbid 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." ); + "Driver metrics are not enabled. You need to enable driver metrics in driver configuration in order to access them." ); } @Override 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 854ddbd382..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,10 +19,9 @@ package org.neo4j.driver.internal.metrics; import org.neo4j.driver.Metrics; -import org.neo4j.driver.internal.metrics.MetricsListener; /** - * An adapter that can collect driver metrics via a {@link MetricsListener} and publishes them via a {@link Metrics} instance. + * An adapter that collects driver metrics via {@link MetricsListener} and publishes them via {@link Metrics} instance. */ public interface MetricsProvider { From 674f5cccef78c1acdf1e95158c87cd1cae106ed2 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 7 Feb 2022 19:47:43 +0200 Subject: [PATCH 17/24] Updated wording --- .../driver/internal/metrics/MicrometerMetricsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 961443bd69..3b766a6bfd 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerMetricsProvider.java @@ -23,7 +23,7 @@ import org.neo4j.driver.Metrics; /** - * An adapter to bridge between the driver metrics and a Micrometer {@link MeterRegistry meter registry}. + * An adapter to bridge between driver metrics and Micrometer {@link MeterRegistry meter registry}. */ public final class MicrometerMetricsProvider implements MetricsProvider { From 575682c57d84625719ed54d6ae3e5b43025ac88a Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 7 Feb 2022 23:20:04 +0200 Subject: [PATCH 18/24] Formatting --- .../internal/util/io/ChannelTrackingDriverFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 7ef0d2586c..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,18 +25,18 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import org.neo4j.driver.internal.metrics.MetricsProvider; +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; import org.neo4j.driver.internal.async.connection.ChannelConnector; import org.neo4j.driver.internal.cluster.RoutingContext; +import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.security.SecurityPlan; 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 { From 921ac636b8c558cd1553c28a82eb33a924a5b7ef Mon Sep 17 00:00:00 2001 From: injectives <11927660+injectives@users.noreply.github.com> Date: Mon, 7 Feb 2022 23:22:40 +0200 Subject: [PATCH 19/24] Update driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java Co-authored-by: Gerrit Meier --- .../neo4j/driver/internal/metrics/DevNullMetricsListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 5894e703a1..4915906800 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/DevNullMetricsListener.java @@ -95,6 +95,6 @@ public void removePoolMetrics( String poolId ) @Override public String toString() { - return "Driver metrics are not available when they are not enabled."; + return "Driver metrics are not available if they are not enabled."; } } From 85cbcd0767c60efd12f7b14b1e0dfb97e78df724 Mon Sep 17 00:00:00 2001 From: injectives <11927660+injectives@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:10:56 +0200 Subject: [PATCH 20/24] Update driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java Co-authored-by: Gerrit Meier --- .../internal/metrics/MicrometerConnectionPoolMetrics.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index be34a34ca2..25e244eb73 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -270,7 +270,7 @@ public String toString() totalAcquisitionTime(), totalConnectionTime(), totalInUseTime(), totalInUseCount() ); } - private long toLong( Counter counter ) + private long count( Counter counter ) { return (long) counter.count(); } From a0d1d95eca57ed8b734501d14ce17089efb6c257 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 28 Feb 2022 22:20:32 +0000 Subject: [PATCH 21/24] Fix compilation error --- .../metrics/MicrometerConnectionPoolMetrics.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 index 25e244eb73..3ef69b3fb2 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -202,19 +202,19 @@ public int creating() @Override public long created() { - return toLong( created ); + return count( created ); } @Override public long failedToCreate() { - return toLong( failedToCreate ); + return count( failedToCreate ); } @Override public long closed() { - return toLong( closed ); + return count( closed ); } @Override @@ -226,13 +226,13 @@ public int acquiring() @Override public long acquired() { - return toLong( acquired ); + return count( acquired ); } @Override public long timedOutToAcquire() { - return toLong( timedOutToAcquire ); + return count( timedOutToAcquire ); } @Override @@ -256,7 +256,7 @@ public long totalInUseTime() @Override public long totalInUseCount() { - return toLong( released ); + return count( released ); } @Override From c692db15bd51fab117063a2e272ac055e099c379 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 28 Feb 2022 22:29:34 +0000 Subject: [PATCH 22/24] Update failing test --- .../test/java/org/neo4j/driver/internal/InternalDriverTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 eb839f3c32..4893526544 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java @@ -103,7 +103,7 @@ 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 From 520aab6df0bd512d9160f122430258b286bfd7ab Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 28 Feb 2022 22:49:19 +0000 Subject: [PATCH 23/24] Fix GetConnectionPoolMetrics access --- .../driver/internal/metrics/InternalConnectionPoolMetrics.java | 2 +- .../backend/messages/requests/GetConnectionPoolMetrics.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 7b4807a017..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 @@ -233,7 +233,7 @@ public String toString() totalAcquisitionTime(), totalConnectionTime(), totalInUseTime(), totalInUseCount() ); } - // This method is for purposes testing only + // This method is for testing purposes only public ServerAddress getAddress() { return address; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java index fe150a329d..63cc06e252 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetConnectionPoolMetrics.java @@ -72,6 +72,7 @@ private ConnectionPoolMetrics getConnectionPoolMetrics( TestkitState testkitStat try { Method m = pm.getClass().getDeclaredMethod("getAddress"); + m.setAccessible( true ); poolAddress = (ServerAddress) m.invoke( pm ); } catch ( NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) From acad532ad857095c69885ebd096cda654257a7a5 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Mon, 7 Mar 2022 23:34:21 +0000 Subject: [PATCH 24/24] Delete redundant counters based on review feedback --- .../MicrometerConnectionPoolMetrics.java | 18 +++--------------- .../MicrometerConnectionPoolMetricsTest.java | 6 +++--- 2 files changed, 6 insertions(+), 18 deletions(-) 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 index 3ef69b3fb2..0e53c15f3b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetrics.java @@ -42,16 +42,13 @@ final class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsList 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 CREATED = PREFIX + ".created"; 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 ACQUIRED = PREFIX + ".acquired"; 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"; - public static final String RELEASED = PREFIX + ".released"; private final IntSupplier inUseSupplier; private final IntSupplier idleSupplier; @@ -59,16 +56,13 @@ final class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsList private final String id; private final AtomicInteger creating = new AtomicInteger(); - private final Counter created; private final Counter failedToCreate; private final Counter closed; private final AtomicInteger acquiring = new AtomicInteger(); - private final Counter acquired; private final Counter timedOutToAcquire; private final Timer totalAcquisitionTimer; private final Timer totalConnectionTimer; private final Timer totalInUseTimer; - private final Counter released; MicrometerConnectionPoolMetrics( String poolId, ServerAddress address, IntSupplier inUseSupplier, IntSupplier idleSupplier, MeterRegistry registry ) { @@ -93,16 +87,13 @@ final class MicrometerConnectionPoolMetrics implements ConnectionPoolMetricsList 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 ); - created = Counter.builder( CREATED ).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 ); - acquired = Counter.builder( ACQUIRED ).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 ); - released = Counter.builder( RELEASED ).tags( tags ).register( registry ); } @Override @@ -123,7 +114,6 @@ public void afterFailedToCreate() public void afterCreated( ListenerEvent connEvent ) { creating.decrementAndGet(); - created.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) connEvent).getSample(); sample.stop( totalConnectionTimer ); } @@ -150,7 +140,6 @@ public void afterAcquiringOrCreating() @Override public void afterAcquiredOrCreated( ListenerEvent acquireEvent ) { - acquired.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) acquireEvent).getSample(); sample.stop( totalAcquisitionTimer ); } @@ -170,7 +159,6 @@ public void acquired( ListenerEvent inUseEvent ) @Override public void released( ListenerEvent inUseEvent ) { - released.increment(); Timer.Sample sample = ((MicrometerTimerListenerEvent) inUseEvent).getSample(); sample.stop( totalInUseTimer ); } @@ -202,7 +190,7 @@ public int creating() @Override public long created() { - return count( created ); + return totalConnectionTimer.count(); } @Override @@ -226,7 +214,7 @@ public int acquiring() @Override public long acquired() { - return count( acquired ); + return totalAcquisitionTimer.count(); } @Override @@ -256,7 +244,7 @@ public long totalInUseTime() @Override public long totalInUseCount() { - return count( released ); + return totalInUseTimer.count(); } @Override 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 index 31c1fe72c9..ea9891b3c0 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/metrics/MicrometerConnectionPoolMetricsTest.java @@ -275,7 +275,7 @@ void verifyMetrics( ConnectionPoolMetrics expected, ConnectionPoolMetrics actual 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.CREATED ).counter().count() ); + 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() ); @@ -283,7 +283,7 @@ void verifyMetrics( ConnectionPoolMetrics expected, ConnectionPoolMetrics actual 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.ACQUIRED ).counter().count() ); + 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() ); @@ -295,6 +295,6 @@ void verifyMetrics( ConnectionPoolMetrics expected, ConnectionPoolMetrics actual 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.RELEASED ).counter().count() ); + assertEquals( expected.totalInUseCount(), registry.get( MicrometerConnectionPoolMetrics.USAGE ).timer().count() ); } }