Skip to content

Commit 98d8e69

Browse files
authored
fix(bigquery-jdbc): configure logging early to capture URL parsing warnings and errors (#13323)
1 parent 1695d0f commit 98d8e69

3 files changed

Lines changed: 124 additions & 21 deletions

File tree

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -127,35 +127,46 @@ public Connection connect(String url, Properties info) throws SQLException {
127127
LOG.finest("++enter++");
128128
try {
129129
if (acceptsURL(url)) {
130-
// strip 'jdbc:' from the URL, add any extra properties
131130
String connectionUri =
132131
BigQueryJdbcUrlUtility.appendPropertiesToURL(url.substring(5), this.toString(), info);
132+
Level logLevel;
133+
String logPath;
134+
try {
135+
// LogLevel
136+
String logLevelStr =
137+
BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation(
138+
connectionUri, BigQueryJdbcUrlUtility.LOG_LEVEL_PROPERTY_NAME);
139+
if (logLevelStr == null) {
140+
logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR);
141+
}
142+
logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr);
143+
144+
// LogPath
145+
logPath =
146+
BigQueryJdbcUrlUtility.parseUriPropertyWithoutValidation(
147+
connectionUri, BigQueryJdbcUrlUtility.LOG_PATH_PROPERTY_NAME);
148+
if (logPath == null) {
149+
logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR);
150+
}
151+
if (logPath == null) {
152+
logPath = BigQueryJdbcUrlUtility.DEFAULT_LOG_PATH;
153+
}
154+
155+
BigQueryJdbcRootLogger.setLevel(logLevel, logPath);
156+
} catch (RuntimeException e) {
157+
LOG.log(Level.SEVERE, "Failed to parse connection URL properties", e);
158+
throw new BigQueryJdbcException("Failed to parse connection URL properties", e);
159+
}
160+
161+
// Logging starts from here.
133162
DataSource ds;
134163
try {
135164
ds = DataSource.fromUrl(connectionUri);
136165
} catch (BigQueryJdbcRuntimeException e) {
166+
LOG.log(Level.SEVERE, "Failed to parse connection URL", e);
137167
throw new BigQueryJdbcException("Failed to parse connection URL", e);
138168
}
139169

140-
// LogLevel
141-
String logLevelStr = ds.getLogLevel();
142-
if (logLevelStr == null) {
143-
logLevelStr = System.getenv(BigQueryJdbcUrlUtility.LOG_LEVEL_ENV_VAR);
144-
}
145-
Level logLevel = BigQueryJdbcUrlUtility.parseLogLevel(logLevelStr);
146-
147-
// LogPath
148-
String logPath = ds.getLogPath();
149-
if (logPath == null) {
150-
logPath = System.getenv(BigQueryJdbcUrlUtility.LOG_PATH_ENV_VAR);
151-
}
152-
if (logPath == null) {
153-
logPath = BigQueryJdbcUrlUtility.DEFAULT_LOG_PATH;
154-
}
155-
156-
BigQueryJdbcRootLogger.setLevel(logLevel, logPath);
157-
158-
// Logging starts from here.
159170
BigQueryConnection connection = new BigQueryConnection(connectionUri, ds);
160171
LOG.info(
161172
"Driver info : { {Database Product Name : %s}, "

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,37 @@ static String parseUriProperty(String uri, String property) {
662662
return map.get(property);
663663
}
664664

665+
/**
666+
* Parses a URI property from the given URI without validating any other properties.
667+
*
668+
* @param uri The URI to parse.
669+
* @param property The name of the property to parse.
670+
* @return The String value of the property, or null if the property is not found.
671+
*/
672+
static String parseUriPropertyWithoutValidation(String uri, String property) {
673+
if (uri == null) {
674+
return null;
675+
}
676+
int start = 0;
677+
int len = uri.length();
678+
while (start < len) {
679+
int nextSemi = uri.indexOf(';', start);
680+
int end = (nextSemi == -1) ? len : nextSemi;
681+
682+
int eqIndex = uri.indexOf('=', start);
683+
if (eqIndex > start && eqIndex < end) {
684+
String key = uri.substring(start, eqIndex).trim();
685+
if (key.equalsIgnoreCase(property)) {
686+
String value = uri.substring(eqIndex + 1, end);
687+
return CharEscapers.decodeUriPath(value.replace("+", "%2B"));
688+
}
689+
}
690+
691+
start = end + 1;
692+
}
693+
return null;
694+
}
695+
665696
/**
666697
* Parses the URL into a map of key-value pairs, validating that all keys are known properties.
667698
*

java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDriverTest.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
import java.sql.DriverPropertyInfo;
2222
import java.sql.SQLException;
2323
import java.util.Properties;
24+
import java.util.logging.Level;
2425
import java.util.logging.Logger;
26+
import org.junit.jupiter.api.Assertions;
2527
import org.junit.jupiter.api.BeforeEach;
2628
import org.junit.jupiter.api.Test;
2729

28-
public class BigQueryDriverTest {
30+
public class BigQueryDriverTest extends BigQueryJdbcLoggingBaseTest {
2931

3032
static BigQueryDriver bigQueryDriver;
3133

@@ -104,4 +106,63 @@ public void testConnectWithInvalidUrlChainsNoException() throws SQLException {
104106
new Properties());
105107
assertThat(connection.isClosed()).isFalse();
106108
}
109+
110+
@Test
111+
public void testUnknownPropertyWarningIsLogged() throws SQLException {
112+
Connection connection =
113+
bigQueryDriver.connect(
114+
"jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;"
115+
+ "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;"
116+
+ "MyUnknownSetting=Value",
117+
new Properties());
118+
assertThat(connection.isClosed()).isFalse();
119+
120+
boolean foundWarning =
121+
capturedLogs.stream()
122+
.anyMatch(
123+
r ->
124+
r.getLevel() == Level.WARNING
125+
&& r.getMessage()
126+
.contains("Wrong value or unknown setting: MYUNKNOWNSETTING"));
127+
assertThat(foundWarning).isTrue();
128+
}
129+
130+
@Test
131+
public void testMalformedUrlExceptionIsLogged() {
132+
Assertions.assertThrows(
133+
SQLException.class,
134+
() ->
135+
bigQueryDriver.connect(
136+
"jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;"
137+
+ "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=3;"
138+
+ "MalformedPropertyWithoutEquals",
139+
new Properties()));
140+
141+
boolean foundSevere =
142+
capturedLogs.stream()
143+
.anyMatch(
144+
r ->
145+
r.getLevel() == Level.SEVERE
146+
&& r.getMessage().contains("Failed to parse connection URL"));
147+
assertThat(foundSevere).isTrue();
148+
}
149+
150+
@Test
151+
public void testInvalidLogLevelExceptionIsLogged() {
152+
Assertions.assertThrows(
153+
SQLException.class,
154+
() ->
155+
bigQueryDriver.connect(
156+
"jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;"
157+
+ "OAuthType=2;OAuthAccessToken=redactedToken;ProjectId=t;LogLevel=invalidInt;",
158+
new Properties()));
159+
160+
boolean foundSevere =
161+
capturedLogs.stream()
162+
.anyMatch(
163+
r ->
164+
r.getLevel() == Level.SEVERE
165+
&& r.getMessage().contains("Failed to parse connection URL properties"));
166+
assertThat(foundSevere).isTrue();
167+
}
107168
}

0 commit comments

Comments
 (0)