Skip to content

Commit 9dac49e

Browse files
committed
chore: set Hibernate user-agent automatically
Use the call stack the first time that a JDBC connection is being created to determine whether the connection should use the sp-jdbc or sp-hib user-agent token.
1 parent 091612b commit 9dac49e

File tree

1 file changed

+32
-1
lines changed

1 file changed

+32
-1
lines changed

src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.cloud.spanner.connection.ConnectionPropertiesHelper;
2727
import com.google.cloud.spanner.connection.ConnectionProperty;
2828
import com.google.common.annotations.VisibleForTesting;
29+
import com.google.common.base.Suppliers;
2930
import com.google.rpc.Code;
3031
import io.opentelemetry.api.OpenTelemetry;
3132
import java.sql.Connection;
@@ -222,7 +223,9 @@ public Connection connect(String url, Properties info) throws SQLException {
222223
Matcher matcherExternalHost = EXTERNAL_HOST_URL_PATTERN.matcher(url);
223224
if (matcher.matches() || matcherExternalHost.matches()) {
224225
// strip 'jdbc:' from the URL, add any extra properties and pass on to the generic
225-
// Connection API
226+
// Connection API. Also set the user-agent if we detect that the connection
227+
// comes from known framework like Hibernate, and there is no other user-agent set.
228+
maybeAddUserAgent(info);
226229
String connectionUri = appendPropertiesToUrl(url.substring(5), info);
227230
ConnectionOptions options = buildConnectionOptions(connectionUri, info);
228231
JdbcConnection connection = new JdbcConnection(url, options);
@@ -259,6 +262,34 @@ private ConnectionOptions buildConnectionOptions(String connectionUrl, Propertie
259262
return builder.build();
260263
}
261264

265+
static void maybeAddUserAgent(Properties properties) {
266+
if (properties.containsKey("userAgent")) {
267+
return;
268+
}
269+
if (isHibernate()) {
270+
properties.setProperty("userAgent", "sp-hib");
271+
}
272+
}
273+
274+
static boolean isHibernate() {
275+
// Cache the result as the check is relatively expensive, and we also don't want to create
276+
// multiple different Spanner instances just to get the correct user-agent in every case.
277+
return Suppliers.memoize(
278+
() -> {
279+
try {
280+
StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
281+
for (StackTraceElement element : callStack) {
282+
if (element.getClassName().contains(".hibernate.")) {
283+
return true;
284+
}
285+
}
286+
} catch (Throwable ignore) {
287+
}
288+
return false;
289+
})
290+
.get();
291+
}
292+
262293
private String appendPropertiesToUrl(String url, Properties info) {
263294
StringBuilder res = new StringBuilder(url);
264295
for (Entry<Object, Object> entry : info.entrySet()) {

0 commit comments

Comments
 (0)