Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Micrometer metrics #1137

Merged
merged 28 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e2a4e73
[WIP] Micrometer metrics instrumentation
shakuzen Dec 14, 2021
bd80f38
Bring it to life.
meistermeier Jan 19, 2022
ce3af7e
Update Micrometer metrics
injectives Jan 25, 2022
ec5dbf3
Merge branch '5.0' into micrometer-metrics
injectives Jan 28, 2022
faf764b
Make MetricsAdapter a supported, public api.
michael-simons Feb 2, 2022
f56e4bc
Saving a file before commiting seems to be relevant.
michael-simons Feb 2, 2022
6957633
Not messing up the file while saven even more so.
michael-simons Feb 3, 2022
afc433f
Make interfaces internal again, provide an enum to select the provide…
michael-simons Feb 3, 2022
f2ca0df
Move micrometer-core optional tag to dependency declaration
injectives Feb 3, 2022
fec69a2
Update Config javadoc and remove imports of internal metrics classes
injectives Feb 3, 2022
70bab1d
Update withMetricsEnabled(boolean) implementation
injectives Feb 3, 2022
0e0e61e
Enable ConfigBuilder.withMetricsAdapter documentation
injectives Feb 3, 2022
2167eeb
Update driver/src/main/java/org/neo4j/driver/ConnectionPoolMetrics.java
injectives Feb 3, 2022
0c8fe23
Update ConnectionPoolMetrics documentation
injectives Feb 3, 2022
479f14f
Update MetricsAdapter documentation
injectives Feb 3, 2022
d942e0d
Update formatting in ConfigTest
injectives Feb 3, 2022
acf04ad
Update wording
injectives Feb 7, 2022
674f5cc
Updated wording
injectives Feb 7, 2022
575682c
Formatting
injectives Feb 7, 2022
921ac63
Update driver/src/main/java/org/neo4j/driver/internal/metrics/DevNull…
injectives Feb 7, 2022
85cbcd0
Update driver/src/main/java/org/neo4j/driver/internal/metrics/Microme…
injectives Feb 8, 2022
40db7b6
Merge branch '5.0' into micrometer-metrics
injectives Feb 22, 2022
6ff57ac
Merge branch '5.0' into micrometer-metrics
injectives Feb 28, 2022
a0d1d95
Fix compilation error
injectives Feb 28, 2022
c692db1
Update failing test
injectives Feb 28, 2022
520aab6
Fix GetConnectionPoolMetrics access
injectives Feb 28, 2022
acad532
Delete redundant counters based on review feedback
injectives Mar 7, 2022
6ece62a
Merge branch '5.0' into micrometer-metrics
injectives Mar 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
</dependency>

<!-- Optional and / or provided dependencies, as they are not transitive to the original driver they must be declared again. -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions driver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
</dependency>

<!-- Optional and / or provided dependencies -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
51 changes: 43 additions & 8 deletions driver/src/main/java/org/neo4j/driver/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil;
import org.neo4j.driver.internal.retry.RetrySettings;
import org.neo4j.driver.net.ServerAddressResolver;
import org.neo4j.driver.util.Experimental;
import org.neo4j.driver.util.Immutable;

import static java.lang.String.format;
Expand Down Expand Up @@ -92,9 +93,9 @@ public class Config implements Serializable
private final RetrySettings retrySettings;
private final ServerAddressResolver resolver;

private final boolean isMetricsEnabled;
private final int eventLoopThreads;
private final String userAgent;
private final MetricsAdapter metricsAdapter;

private Config( ConfigBuilder builder )
{
Expand All @@ -118,7 +119,7 @@ private Config( ConfigBuilder builder )
this.fetchSize = builder.fetchSize;

this.eventLoopThreads = builder.eventLoopThreads;
this.isMetricsEnabled = builder.isMetricsEnabled;
this.metricsAdapter = builder.metricsAdapter;
}

/**
Expand Down Expand Up @@ -256,7 +257,12 @@ public int eventLoopThreads()
*/
public boolean isMetricsEnabled()
{
return isMetricsEnabled;
return this.metricsAdapter != MetricsAdapter.DEV_NULL;
}

public MetricsAdapter metricsAdapter()
{
return this.metricsAdapter;
}

/**
Expand Down Expand Up @@ -286,7 +292,7 @@ public static class ConfigBuilder
private int connectionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis( 30 );
private RetrySettings retrySettings = RetrySettings.DEFAULT;
private ServerAddressResolver resolver;
private boolean isMetricsEnabled = false;
private MetricsAdapter metricsAdapter = MetricsAdapter.DEV_NULL;
private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE;
private int eventLoopThreads = 0;

Expand Down Expand Up @@ -699,13 +705,13 @@ public ConfigBuilder withResolver( ServerAddressResolver resolver )
}

/**
* Enable driver metrics. The metrics can be obtained afterwards via {@link Driver#metrics()}.
* Enable driver metrics backed by internal basic implementation. The metrics can be obtained afterwards via {@link Driver#metrics()}.
*
* @return this builder.
*/
public ConfigBuilder withDriverMetrics()
{
this.isMetricsEnabled = true;
return this;
return withMetricsEnabled( true );
}

/**
Expand All @@ -714,7 +720,36 @@ public ConfigBuilder withDriverMetrics()
*/
public ConfigBuilder withoutDriverMetrics()
{
this.isMetricsEnabled = false;
return withMetricsEnabled( false );
}

private ConfigBuilder withMetricsEnabled( boolean enabled )
{
if ( !enabled )
{
withMetricsAdapter( MetricsAdapter.DEV_NULL );
}
else if ( this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.DEV_NULL )
{
withMetricsAdapter( MetricsAdapter.DEFAULT );
}
return this;
}

/**
* Enable driver metrics with given {@link MetricsAdapter}.
* <p>
* {@link MetricsAdapter#MICROMETER} enables implementation based on <a href="https://micrometer.io">Micrometer</a>. The metrics can be obtained
* afterwards via Micrometer means and {@link Driver#metrics()}. Micrometer must be on classpath when using this option.
* <p>
*
* @param metricsAdapter the metrics adapter to use. Use {@link MetricsAdapter#DEV_NULL} to disable metrics.
* @return this builder.
*/
@Experimental
public ConfigBuilder withMetricsAdapter( MetricsAdapter metricsAdapter )
{
this.metricsAdapter = Objects.requireNonNull( metricsAdapter, "metricsAdapter" );
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -57,9 +58,9 @@ public interface ConnectionPoolMetrics
int creating();

/**
* A counter to record how many connections have been successfully created with this pool since the pool is created.
* A counter to record how many connections have been successfully created with this pool since the pool was created.
* This number increases every time when a connection is successfully created.
* @return The amount of connections have ever been created by this pool.
* @return The amount of connections that have ever been created by this pool.
*/
long created();

Expand Down
4 changes: 1 addition & 3 deletions driver/src/main/java/org/neo4j/driver/Driver.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,17 @@ 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();

/**
* Returns true if the driver metrics reporting is enabled via {@link Config.ConfigBuilder#withDriverMetrics()}, otherwise false.
*
* @return true if the metrics reporting is enabled.
*/
@Experimental
boolean isMetricsEnabled();

/**
Expand Down
40 changes: 40 additions & 0 deletions driver/src/main/java/org/neo4j/driver/MetricsAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.neo4j.driver;

/**
* Defines which metrics consumer to use: Should metrics be consumed and exposed via driver's default consumer or provided with one of the external facades.
*/
public enum MetricsAdapter
{
/**
* Disables metrics.
*/
DEV_NULL,

/**
* Consumes and publishes metrics via the driver itself.
*/
DEFAULT,

/**
* Consumes and publishes metrics via Micrometer. Ensure that Micrometer is on classpath when using this option.
*/
MICROMETER
}
24 changes: 17 additions & 7 deletions driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,8 +43,10 @@
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer;
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancingStrategy;
import org.neo4j.driver.internal.logging.NettyLogging;
import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
import org.neo4j.driver.internal.metrics.InternalMetricsProvider;
import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.internal.metrics.MicrometerMetricsProvider;
import org.neo4j.driver.internal.retry.ExponentialBackoffRetryLogic;
import org.neo4j.driver.internal.retry.RetryLogic;
import org.neo4j.driver.internal.retry.RetrySettings;
Expand All @@ -56,7 +59,6 @@

import static org.neo4j.driver.internal.Scheme.isRoutingScheme;
import static org.neo4j.driver.internal.cluster.IdentityResolver.IDENTITY_RESOLVER;
import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER;
import static org.neo4j.driver.internal.util.ErrorUtil.addSuppressed;

public class DriverFactory
Expand Down Expand Up @@ -94,7 +96,7 @@ public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings r
EventExecutorGroup eventExecutorGroup = bootstrap.config().group();
RetryLogic retryLogic = createRetryLogic( retrySettings, eventExecutorGroup, config.logging() );

MetricsProvider metricsProvider = createDriverMetrics( config, createClock() );
MetricsProvider metricsProvider = getOrCreateMetricsProvider( config, createClock() );
ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config,
ownsEventLoopGroup, newRoutingSettings.routingContext() );

Expand All @@ -114,16 +116,24 @@ protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan
return new ConnectionPoolImpl( connector, bootstrap, poolSettings, metricsProvider.metricsListener(), config.logging(), clock, ownsEventLoopGroup );
}

protected static MetricsProvider createDriverMetrics( Config config, Clock clock )
protected static MetricsProvider getOrCreateMetricsProvider( Config config, Clock clock )
{
if( config.isMetricsEnabled() )
MetricsAdapter metricsAdapter = config.metricsAdapter();
// This can actually only happen when someone mocks the config
if ( metricsAdapter == null )
{
return new InternalMetricsProvider( clock, config.logging() );
metricsAdapter = config.isMetricsEnabled() ? MetricsAdapter.DEFAULT : MetricsAdapter.DEV_NULL;
}
else
switch ( metricsAdapter )
{
return METRICS_DISABLED_PROVIDER;
case DEV_NULL:
return DevNullMetricsProvider.INSTANCE;
case DEFAULT:
return new InternalMetricsProvider( clock, config.logging() );
case MICROMETER:
return MicrometerMetricsProvider.forGlobalRegistry();
}
throw new IllegalStateException( "Unknown or unsupported MetricsAdapter: " + metricsAdapter );
}

protected ChannelConnector createConnector( ConnectionSettings settings, SecurityPlan securityPlan,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
import org.neo4j.driver.Metrics;
import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.async.AsyncSession;
import org.neo4j.driver.internal.async.InternalAsyncSession;
import org.neo4j.driver.internal.async.NetworkSession;
import org.neo4j.driver.internal.metrics.MetricsProvider;
import org.neo4j.driver.internal.metrics.DevNullMetricsProvider;
import org.neo4j.driver.internal.reactive.InternalRxSession;
import org.neo4j.driver.internal.security.SecurityPlan;
import org.neo4j.driver.internal.types.InternalTypeSystem;
Expand Down Expand Up @@ -102,7 +103,7 @@ public Metrics metrics()
@Override
public boolean isMetricsEnabled()
{
return metricsProvider.isMetricsEnabled();
return metricsProvider != DevNullMetricsProvider.INSTANCE;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.neo4j.driver.internal.spi.ConnectionPool;
import org.neo4j.driver.internal.util.Clock;
import org.neo4j.driver.internal.util.Futures;
import org.neo4j.driver.net.ServerAddress;

import static java.lang.String.format;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setAuthorizationStateListener;
Expand Down Expand Up @@ -159,13 +160,13 @@ public void retainAll( Set<BoltServerAddress> 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 );
}
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.metrics.ListenerEvent;
import org.neo4j.driver.internal.metrics.MetricsListener;
import org.neo4j.driver.net.ServerAddress;

import static org.neo4j.driver.internal.async.connection.ChannelAttributes.poolId;
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.serverAddress;
Expand All @@ -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<BoltServerAddress,Integer> addressToInUseChannelCount = new HashMap<>();
private final Map<BoltServerAddress,Integer> addressToIdleChannelCount = new HashMap<>();
private final Map<ServerAddress,Integer> addressToInUseChannelCount = new HashMap<>();
private final Map<ServerAddress,Integer> addressToIdleChannelCount = new HashMap<>();
private final Logger log;
private final MetricsListener metricsListener;
private final ChannelFutureListener closeListener = future -> channelClosed( future.channel() );
Expand Down Expand Up @@ -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 ) );
}
Expand Down Expand Up @@ -213,9 +214,9 @@ private void decrementIdle( Channel channel )
addressToIdleChannelCount.put( address, count - 1 );
}

private void increment( Channel channel, Map<BoltServerAddress,Integer> countMap )
private void increment( Channel channel, Map<ServerAddress,Integer> countMap )
{
BoltServerAddress address = serverAddress( channel );
ServerAddress address = serverAddress( channel );
Integer count = countMap.computeIfAbsent( address, k -> 0 );
countMap.put( address, count + 1 );
}
Expand Down
Loading