21
21
import java .time .Duration ;
22
22
import java .util .List ;
23
23
import java .util .Locale ;
24
+ import java .util .ServiceLoader ;
24
25
import java .util .concurrent .TimeUnit ;
25
26
27
+ import io .micrometer .observation .ObservationRegistry ;
26
28
import org .jspecify .annotations .Nullable ;
29
+ import org .neo4j .bolt .connection .BoltConnectionProviderFactory ;
27
30
import org .neo4j .driver .AuthToken ;
28
31
import org .neo4j .driver .AuthTokenManager ;
29
32
import org .neo4j .driver .AuthTokens ;
32
35
import org .neo4j .driver .Driver ;
33
36
import org .neo4j .driver .GraphDatabase ;
34
37
import org .neo4j .driver .internal .Scheme ;
38
+ import org .neo4j .driver .observation .micrometer .MicrometerObservationProvider ;
35
39
36
40
import org .springframework .beans .factory .ObjectProvider ;
37
41
import org .springframework .boot .autoconfigure .AutoConfiguration ;
63
67
@ EnableConfigurationProperties (Neo4jProperties .class )
64
68
public final class Neo4jAutoConfiguration {
65
69
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
+
66
84
@ Bean
67
85
@ ConditionalOnMissingBean (Neo4jConnectionDetails .class )
68
86
PropertiesNeo4jConnectionDetails neo4jConnectionDetails (Neo4jProperties properties ,
@@ -73,10 +91,11 @@ PropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properti
73
91
@ Bean
74
92
@ ConditionalOnMissingBean
75
93
Driver neo4jDriver (Neo4jProperties properties , Environment environment , Neo4jConnectionDetails connectionDetails ,
76
- ObjectProvider <ConfigBuilderCustomizer > configBuilderCustomizers ) {
94
+ ObjectProvider <ConfigBuilderCustomizer > configBuilderCustomizers ,
95
+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
77
96
78
97
Config config = mapDriverConfig (properties , connectionDetails ,
79
- configBuilderCustomizers .orderedStream ().toList ());
98
+ configBuilderCustomizers .orderedStream ().toList (), observationRegistryProvider );
80
99
AuthTokenManager authTokenManager = connectionDetails .getAuthTokenManager ();
81
100
if (authTokenManager != null ) {
82
101
return GraphDatabase .driver (connectionDetails .getUri (), authTokenManager , config );
@@ -86,29 +105,29 @@ Driver neo4jDriver(Neo4jProperties properties, Environment environment, Neo4jCon
86
105
}
87
106
88
107
Config mapDriverConfig (Neo4jProperties properties , Neo4jConnectionDetails connectionDetails ,
89
- List <ConfigBuilderCustomizer > customizers ) {
108
+ List <ConfigBuilderCustomizer > customizers ,
109
+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
90
110
Config .ConfigBuilder builder = Config .builder ();
91
- configurePoolSettings (builder , properties .getPool ());
111
+ configurePoolSettings (builder , properties .getPool (), observationRegistryProvider );
92
112
URI uri = connectionDetails .getUri ();
93
113
String scheme = (uri != null ) ? uri .getScheme () : "bolt" ;
94
114
configureDriverSettings (builder , properties , isSimpleScheme (scheme ));
95
- builder .withLogging (new Neo4jSpringJclLogging ());
96
115
customizers .forEach ((customizer ) -> customizer .customize (builder ));
97
116
return builder .build ();
98
117
}
99
118
100
119
private boolean isSimpleScheme (String scheme ) {
101
120
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 ))) {
106
124
throw new IllegalArgumentException (String .format ("'%s' is not a supported scheme." , scheme ));
107
125
}
108
- return lowerCaseScheme . equals ( "bolt" ) || lowerCaseScheme . equals ( "neo4j" );
126
+ return ! Scheme . isSecurityScheme ( lowerCaseScheme );
109
127
}
110
128
111
- private void configurePoolSettings (Config .ConfigBuilder builder , Pool pool ) {
129
+ private void configurePoolSettings (Config .ConfigBuilder builder , Pool pool ,
130
+ ObjectProvider <ObservationRegistry > observationRegistryProvider ) {
112
131
if (pool .isLogLeakedSessions ()) {
113
132
builder .withLeakedSessionsLogging ();
114
133
}
@@ -120,12 +139,11 @@ private void configurePoolSettings(Config.ConfigBuilder builder, Pool pool) {
120
139
builder .withMaxConnectionLifetime (pool .getMaxConnectionLifetime ().toMillis (), TimeUnit .MILLISECONDS );
121
140
builder .withConnectionAcquisitionTimeout (pool .getConnectionAcquisitionTimeout ().toMillis (),
122
141
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
+ });
129
147
}
130
148
131
149
private void configureDriverSettings (Config .ConfigBuilder builder , Neo4jProperties properties ,
0 commit comments