@@ -172,6 +172,8 @@ public String[] getValidValues() {
172
172
private static final RpcPriority DEFAULT_RPC_PRIORITY = null ;
173
173
private static final boolean DEFAULT_RETURN_COMMIT_STATS = false ;
174
174
private static final boolean DEFAULT_LENIENT = false ;
175
+ private static final boolean DEFAULT_TRACK_SESSION_LEAKS = true ;
176
+ private static final boolean DEFAULT_TRACK_CONNECTION_LEAKS = true ;
175
177
176
178
private static final String PLAIN_TEXT_PROTOCOL = "http:" ;
177
179
private static final String HOST_PROTOCOL = "https:" ;
@@ -218,6 +220,10 @@ public String[] getValidValues() {
218
220
private static final String DIALECT_PROPERTY_NAME = "dialect" ;
219
221
/** Name of the 'databaseRole' connection property. */
220
222
public static final String DATABASE_ROLE_PROPERTY_NAME = "databaseRole" ;
223
+ /** Name of the 'trackStackTraceOfSessionCheckout' connection property. */
224
+ public static final String TRACK_SESSION_LEAKS_PROPERTY_NAME = "trackSessionLeaks" ;
225
+ /** Name of the 'trackStackTraceOfConnectionCreation' connection property. */
226
+ public static final String TRACK_CONNECTION_LEAKS_PROPERTY_NAME = "trackConnectionLeaks" ;
221
227
/** All valid connection properties. */
222
228
public static final Set <ConnectionProperty > VALID_PROPERTIES =
223
229
Collections .unmodifiableSet (
@@ -287,7 +293,25 @@ public String[] getValidValues() {
287
293
DIALECT_PROPERTY_NAME , "Sets the dialect to use for this connection." ),
288
294
ConnectionProperty .createStringProperty (
289
295
DATABASE_ROLE_PROPERTY_NAME ,
290
- "Sets the database role to use for this connection. The default is privileges assigned to IAM role" ))));
296
+ "Sets the database role to use for this connection. The default is privileges assigned to IAM role" ),
297
+ ConnectionProperty .createBooleanProperty (
298
+ TRACK_SESSION_LEAKS_PROPERTY_NAME ,
299
+ "Capture the call stack of the thread that checked out a session of the session pool. This will "
300
+ + "pre-create a LeakedSessionException already when a session is checked out. This can be disabled, "
301
+ + "for example if a monitoring system logs the pre-created exception. "
302
+ + "If disabled, the LeakedSessionException will only be created when an "
303
+ + "actual session leak is detected. The stack trace of the exception will "
304
+ + "in that case not contain the call stack of when the session was checked out." ,
305
+ DEFAULT_TRACK_SESSION_LEAKS ),
306
+ ConnectionProperty .createBooleanProperty (
307
+ TRACK_CONNECTION_LEAKS_PROPERTY_NAME ,
308
+ "Capture the call stack of the thread that created a connection. This will "
309
+ + "pre-create a LeakedConnectionException already when a connection is created. "
310
+ + "This can be disabled, for example if a monitoring system logs the pre-created exception. "
311
+ + "If disabled, the LeakedConnectionException will only be created when an "
312
+ + "actual connection leak is detected. The stack trace of the exception will "
313
+ + "in that case not contain the call stack of when the connection was created." ,
314
+ DEFAULT_TRACK_CONNECTION_LEAKS ))));
291
315
292
316
private static final Set <ConnectionProperty > INTERNAL_PROPERTIES =
293
317
Collections .unmodifiableSet (
@@ -544,6 +568,8 @@ public static Builder newBuilder() {
544
568
private final boolean returnCommitStats ;
545
569
private final boolean autoConfigEmulator ;
546
570
private final RpcPriority rpcPriority ;
571
+ private final boolean trackSessionLeaks ;
572
+ private final boolean trackConnectionLeaks ;
547
573
548
574
private final boolean autocommit ;
549
575
private final boolean readOnly ;
@@ -588,6 +614,8 @@ private ConnectionOptions(Builder builder) {
588
614
this .usePlainText = this .autoConfigEmulator || parseUsePlainText (this .uri );
589
615
this .host = determineHost (matcher , autoConfigEmulator , usePlainText );
590
616
this .rpcPriority = parseRPCPriority (this .uri );
617
+ this .trackSessionLeaks = parseTrackSessionLeaks (this .uri );
618
+ this .trackConnectionLeaks = parseTrackConnectionLeaks (this .uri );
591
619
592
620
this .instanceId = matcher .group (Builder .INSTANCE_GROUP );
593
621
this .databaseName = matcher .group (Builder .DATABASE_GROUP );
@@ -641,11 +669,12 @@ private ConnectionOptions(Builder builder) {
641
669
Collections .unmodifiableList (builder .statementExecutionInterceptors );
642
670
this .configurator = builder .configurator ;
643
671
644
- if (this .minSessions != null || this .maxSessions != null ) {
672
+ if (this .minSessions != null || this .maxSessions != null || ! this . trackSessionLeaks ) {
645
673
SessionPoolOptions .Builder sessionPoolOptionsBuilder =
646
674
builder .sessionPoolOptions == null
647
675
? SessionPoolOptions .newBuilder ()
648
676
: builder .sessionPoolOptions .toBuilder ();
677
+ sessionPoolOptionsBuilder .setTrackStackTraceOfSessionCheckout (this .trackSessionLeaks );
649
678
sessionPoolOptionsBuilder .setAutoDetectDialect (true );
650
679
if (this .minSessions != null ) {
651
680
sessionPoolOptionsBuilder .setMinSessions (this .minSessions );
@@ -838,6 +867,18 @@ static boolean parseLenient(String uri) {
838
867
return value != null ? Boolean .parseBoolean (value ) : DEFAULT_LENIENT ;
839
868
}
840
869
870
+ @ VisibleForTesting
871
+ static boolean parseTrackSessionLeaks (String uri ) {
872
+ String value = parseUriProperty (uri , TRACK_SESSION_LEAKS_PROPERTY_NAME );
873
+ return value != null ? Boolean .parseBoolean (value ) : DEFAULT_TRACK_SESSION_LEAKS ;
874
+ }
875
+
876
+ @ VisibleForTesting
877
+ static boolean parseTrackConnectionLeaks (String uri ) {
878
+ String value = parseUriProperty (uri , TRACK_CONNECTION_LEAKS_PROPERTY_NAME );
879
+ return value != null ? Boolean .parseBoolean (value ) : DEFAULT_TRACK_CONNECTION_LEAKS ;
880
+ }
881
+
841
882
@ VisibleForTesting
842
883
static RpcPriority parseRPCPriority (String uri ) {
843
884
String value = parseUriProperty (uri , RPC_PRIORITY_NAME );
@@ -1078,6 +1119,10 @@ RpcPriority getRPCPriority() {
1078
1119
return rpcPriority ;
1079
1120
}
1080
1121
1122
+ boolean isTrackConnectionLeaks () {
1123
+ return this .trackConnectionLeaks ;
1124
+ }
1125
+
1081
1126
/** Interceptors that should be executed after each statement */
1082
1127
List <StatementExecutionInterceptor > getStatementExecutionInterceptors () {
1083
1128
return statementExecutionInterceptors ;
0 commit comments