2121import java .time .Duration ;
2222import java .util .List ;
2323import java .util .Locale ;
24+ import java .util .ServiceLoader ;
2425import java .util .concurrent .TimeUnit ;
2526
27+ import io .micrometer .observation .ObservationRegistry ;
2628import org .jspecify .annotations .Nullable ;
29+ import org .neo4j .bolt .connection .BoltConnectionProviderFactory ;
2730import org .neo4j .driver .AuthToken ;
2831import org .neo4j .driver .AuthTokenManager ;
2932import org .neo4j .driver .AuthTokens ;
3235import org .neo4j .driver .Driver ;
3336import org .neo4j .driver .GraphDatabase ;
3437import org .neo4j .driver .internal .Scheme ;
38+ import org .neo4j .driver .observation .micrometer .MicrometerObservationProvider ;
3539
3640import org .springframework .beans .factory .ObjectProvider ;
3741import org .springframework .boot .autoconfigure .AutoConfiguration ;
6367@ EnableConfigurationProperties (Neo4jProperties .class )
6468public final class Neo4jAutoConfiguration {
6569
70+ private static final boolean HAS_DRIVER_METRICS ;
71+
72+ static {
73+ boolean metricsObservationProviderFound = true ;
74+ try {
75+ Class .forName ("org.neo4j.driver.observation.micrometer.MicrometerObservationProvider" , false ,
76+ Neo4jAutoConfiguration .class .getClassLoader ());
77+ }
78+ catch (ClassNotFoundException ex ) {
79+ metricsObservationProviderFound = false ;
80+ }
81+ HAS_DRIVER_METRICS = metricsObservationProviderFound ;
82+ }
83+
6684 @ Bean
6785 @ ConditionalOnMissingBean (Neo4jConnectionDetails .class )
6886 PropertiesNeo4jConnectionDetails neo4jConnectionDetails (Neo4jProperties properties ,
@@ -73,10 +91,11 @@ PropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properti
7391 @ Bean
7492 @ ConditionalOnMissingBean
7593 Driver neo4jDriver (Neo4jProperties properties , Environment environment , Neo4jConnectionDetails connectionDetails ,
76- ObjectProvider <ConfigBuilderCustomizer > configBuilderCustomizers ) {
94+ ObjectProvider <ConfigBuilderCustomizer > configBuilderCustomizers ,
95+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
7796
7897 Config config = mapDriverConfig (properties , connectionDetails ,
79- configBuilderCustomizers .orderedStream ().toList ());
98+ configBuilderCustomizers .orderedStream ().toList (), observationRegistryProvider );
8099 AuthTokenManager authTokenManager = connectionDetails .getAuthTokenManager ();
81100 if (authTokenManager != null ) {
82101 return GraphDatabase .driver (connectionDetails .getUri (), authTokenManager , config );
@@ -86,29 +105,29 @@ Driver neo4jDriver(Neo4jProperties properties, Environment environment, Neo4jCon
86105 }
87106
88107 Config mapDriverConfig (Neo4jProperties properties , Neo4jConnectionDetails connectionDetails ,
89- List <ConfigBuilderCustomizer > customizers ) {
108+ List <ConfigBuilderCustomizer > customizers ,
109+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
90110 Config .ConfigBuilder builder = Config .builder ();
91- configurePoolSettings (builder , properties .getPool ());
111+ configurePoolSettings (builder , properties .getPool (), observationRegistryProvider );
92112 URI uri = connectionDetails .getUri ();
93113 String scheme = (uri != null ) ? uri .getScheme () : "bolt" ;
94114 configureDriverSettings (builder , properties , isSimpleScheme (scheme ));
95- builder .withLogging (new Neo4jSpringJclLogging ());
96115 customizers .forEach ((customizer ) -> customizer .customize (builder ));
97116 return builder .build ();
98117 }
99118
100119 private boolean isSimpleScheme (String scheme ) {
101120 String lowerCaseScheme = scheme .toLowerCase (Locale .ENGLISH );
102- try {
103- Scheme .validateScheme (lowerCaseScheme );
104- }
105- catch (IllegalArgumentException ex ) {
121+ if (!ServiceLoader .load (BoltConnectionProviderFactory .class )
122+ .stream ()
123+ .anyMatch ((p ) -> p .get ().supports (lowerCaseScheme ))) {
106124 throw new IllegalArgumentException (String .format ("'%s' is not a supported scheme." , scheme ));
107125 }
108- return lowerCaseScheme . equals ( "bolt" ) || lowerCaseScheme . equals ( "neo4j" );
126+ return ! Scheme . isSecurityScheme ( lowerCaseScheme );
109127 }
110128
111- private void configurePoolSettings (Config .ConfigBuilder builder , Pool pool ) {
129+ private void configurePoolSettings (Config .ConfigBuilder builder , Pool pool ,
130+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
112131 if (pool .isLogLeakedSessions ()) {
113132 builder .withLeakedSessionsLogging ();
114133 }
@@ -120,12 +139,11 @@ private void configurePoolSettings(Config.ConfigBuilder builder, Pool pool) {
120139 builder .withMaxConnectionLifetime (pool .getMaxConnectionLifetime ().toMillis (), TimeUnit .MILLISECONDS );
121140 builder .withConnectionAcquisitionTimeout (pool .getConnectionAcquisitionTimeout ().toMillis (),
122141 TimeUnit .MILLISECONDS );
123- if (pool .isMetricsEnabled ()) {
124- builder .withDriverMetrics ();
125- }
126- else {
127- builder .withoutDriverMetrics ();
128- }
142+ observationRegistryProvider .ifAvailable ((orp ) -> {
143+ if (pool .isMetricsEnabled () && HAS_DRIVER_METRICS ) {
144+ builder .withObservationProvider (MicrometerObservationProvider .builder (orp ).build ());
145+ }
146+ });
129147 }
130148
131149 private void configureDriverSettings (Config .ConfigBuilder builder , Neo4jProperties properties ,
0 commit comments