Skip to content

Commit ce4969b

Browse files
authored
fix(bqjdbc): enhance logging with caller inference and explicit exception tracking (#12903)
b/505727302 - BigQueryJdbcCustomLogger.java: - Implemented stack trace analysis to route exact execution locations via Logger.logp(). - Introduced Throwable interception overloads for SEVERE and WARNING tiers to print full stack traces when exceptions are thrown. - Catch Block Instrumentation: Added explicit Logs configurations to log exceptions: - BigQueryConnection.java - BigQueryBaseArray.java - BigQueryBaseStruct.java - BigQueryParameterHandler.java - BigQueryDaemonPollingTask.java - BigQueryJdbcProxyUtility.java - BigQueryJdbcCustomLoggerTest.java: Tests for changes made. Note: More catch block instrumentation to follow in future PRs.
1 parent 3ea90ef commit ce4969b

10 files changed

Lines changed: 193 additions & 8 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
drivers/**
22
target-it/**
3-
*logs/**
3+
*logs*/**

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,27 @@ public final int getBaseType() {
7171

7272
@Override
7373
public final Object getArray(Map<String, Class<?>> map) throws SQLException {
74+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
7475
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
7576
}
7677

7778
@Override
7879
public final Object getArray(long index, int count, Map<String, Class<?>> map)
7980
throws SQLException {
81+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
8082
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
8183
}
8284

8385
@Override
8486
public final ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
87+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
8588
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
8689
}
8790

8891
@Override
8992
public final ResultSet getResultSet(long index, int count, Map<String, Class<?>> map)
9093
throws SQLException {
94+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
9195
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
9296
}
9397

@@ -106,6 +110,7 @@ protected Object getArrayInternal(int fromIndex, int toIndexExclusive) {
106110
protected void ensureValid() throws IllegalStateException {
107111
LOG.finest("++enter++");
108112
if (!this.valid) {
113+
LOG.severe(INVALID_ARRAY);
109114
throw new IllegalStateException(INVALID_ARRAY);
110115
}
111116
}
@@ -127,6 +132,8 @@ protected Tuple<Integer, Integer> createRange(long index, int count, int size)
127132
// jdbc array follows 1 based array indexing
128133
long normalisedFromIndex = index - 1;
129134
if (normalisedFromIndex + count > size) {
135+
LOG.severe(
136+
"The array index is out of range: %d, number of elements: %d.", index + count, size);
130137
throw new IllegalArgumentException(
131138
String.format(
132139
"The array index is out of range: %d, number of elements: %d.", index + count, size));
@@ -166,6 +173,7 @@ public String toString() {
166173
}
167174
return Arrays.deepToString(array);
168175
} catch (SQLException e) {
176+
LOG.warning("Error converting array to string");
169177
return "[Error converting array to string: " + e.getMessage() + "]";
170178
}
171179
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ abstract class BigQueryBaseStruct implements java.sql.Struct {
4242

4343
@Override
4444
public final String getSQLTypeName() throws SQLException {
45+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
4546
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
4647
}
4748

4849
@Override
4950
public final Object[] getAttributes(Map<String, Class<?>> map) throws SQLException {
51+
LOG.severe(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
5052
throw new BigQueryJdbcSqlFeatureNotSupportedException(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED);
5153
}
5254

@@ -91,6 +93,7 @@ public String toString() {
9193
sb.append("}");
9294
return sb.toString();
9395
} catch (SQLException e) {
96+
LOG.severe(e, "Error converting struct to string");
9497
return "{ \"error\": \"Error converting struct to string: " + e.getMessage() + "\" }";
9598
}
9699
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ BigQueryReadClient getBigQueryReadClient() {
297297
this.bigQueryReadClient = getBigQueryReadClientConnection();
298298
}
299299
} catch (IOException e) {
300+
LOG.severe(e, "Failed to initialize BigQueryReadClient");
300301
throw new BigQueryJdbcRuntimeException(e);
301302
}
302303
return this.bigQueryReadClient;
@@ -308,6 +309,7 @@ BigQueryWriteClient getBigQueryWriteClient() {
308309
this.bigQueryWriteClient = getBigQueryWriteClientConnection();
309310
}
310311
} catch (IOException e) {
312+
LOG.severe(e, "Failed to initialize BigQueryWriteClient");
311313
throw new BigQueryJdbcRuntimeException(e);
312314
}
313315
return this.bigQueryWriteClient;
@@ -536,6 +538,7 @@ private void beginTransaction() {
536538
}
537539
this.transactionStarted = true;
538540
} catch (InterruptedException ex) {
541+
LOG.severe(ex, "Failed to begin transaction");
539542
throw new BigQueryJdbcRuntimeException(ex);
540543
}
541544
}
@@ -773,6 +776,7 @@ public void rollback() throws SQLException {
773776
beginTransaction();
774777
}
775778
} catch (InterruptedException | BigQueryException ex) {
779+
LOG.severe(ex, "Failed to rollback transaction");
776780
throw new BigQueryJdbcException(ex);
777781
}
778782
}
@@ -848,8 +852,10 @@ public void close() throws SQLException {
848852
}
849853
this.openStatements.clear();
850854
} catch (ConcurrentModificationException ex) {
855+
LOG.severe(ex, "Concurrent modification during close");
851856
throw new BigQueryJdbcException(ex);
852857
} catch (InterruptedException e) {
858+
LOG.severe(e, "Interrupted during close");
853859
throw new BigQueryJdbcRuntimeException(e);
854860
}
855861
this.isClosed = true;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,11 @@ else if (referenceQueueJsonRs != null) {
113113
reference.clear();
114114
}
115115
} else {
116+
LOG.severe("Null Reference Queue");
116117
throw new BigQueryJdbcRuntimeException("Null Reference Queue");
117118
}
118119
} catch (InterruptedException ex) {
120+
LOG.severe(ex, "Interrupted in GC daemon task");
119121
throw new BigQueryJdbcRuntimeException(ex);
120122
}
121123
}

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

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package com.google.cloud.bigquery.jdbc;
1818

19+
import java.util.function.Supplier;
20+
import java.util.logging.Level;
21+
import java.util.logging.LogRecord;
1922
import java.util.logging.Logger;
2023

2124
class BigQueryJdbcCustomLogger extends Logger {
@@ -30,31 +33,80 @@ protected BigQueryJdbcCustomLogger(String name, String resourceBundleName) {
3033
this.setParent(BigQueryJdbcRootLogger.getRootLogger());
3134
}
3235

36+
private void logWithCaller(Level level, Supplier<String> msgSupplier) {
37+
logWithCaller(level, null, msgSupplier);
38+
}
39+
40+
private void logWithCaller(Level level, Throwable thrown, Supplier<String> msgSupplier) {
41+
if (!isLoggable(level)) {
42+
return;
43+
}
44+
45+
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
46+
String sourceClass = "unknown";
47+
String sourceMethod = "unknown";
48+
49+
for (StackTraceElement element : stackTrace) {
50+
String className = element.getClassName();
51+
if (!className.equals(BigQueryJdbcCustomLogger.class.getName())) {
52+
sourceClass = className;
53+
sourceMethod = element.getMethodName();
54+
break;
55+
}
56+
}
57+
58+
if (thrown == null) {
59+
logp(level, sourceClass, sourceMethod, msgSupplier);
60+
} else {
61+
LogRecord record = new LogRecord(level, msgSupplier.get());
62+
record.setSourceClassName(sourceClass);
63+
record.setSourceMethodName(sourceMethod);
64+
record.setThrown(thrown);
65+
log(record);
66+
}
67+
}
68+
3369
void finest(String format, Object... args) {
34-
this.finest(() -> String.format(format, args));
70+
logWithCaller(Level.FINEST, () -> String.format(format, args));
3571
}
3672

3773
void finer(String format, Object... args) {
38-
this.finer(() -> String.format(format, args));
74+
logWithCaller(Level.FINER, () -> String.format(format, args));
3975
}
4076

4177
void fine(String format, Object... args) {
42-
this.fine(() -> String.format(format, args));
78+
logWithCaller(Level.FINE, () -> String.format(format, args));
4379
}
4480

4581
void config(String format, Object... args) {
46-
this.config(() -> String.format(format, args));
82+
logWithCaller(Level.CONFIG, () -> String.format(format, args));
4783
}
4884

4985
void info(String format, Object... args) {
50-
this.info(() -> String.format(format, args));
86+
logWithCaller(Level.INFO, () -> String.format(format, args));
5187
}
5288

5389
void warning(String format, Object... args) {
54-
this.warning(() -> String.format(format, args));
90+
logWithCaller(Level.WARNING, () -> String.format(format, args));
91+
}
92+
93+
void warning(Throwable thrown, String msg) {
94+
logWithCaller(Level.WARNING, thrown, () -> msg);
95+
}
96+
97+
void warning(Throwable thrown, String format, Object... args) {
98+
logWithCaller(Level.WARNING, thrown, () -> String.format(format, args));
5599
}
56100

57101
void severe(String format, Object... args) {
58-
this.severe(() -> String.format(format, args));
102+
logWithCaller(Level.SEVERE, () -> String.format(format, args));
103+
}
104+
105+
void severe(Throwable thrown, String msg) {
106+
logWithCaller(Level.SEVERE, thrown, () -> msg);
107+
}
108+
109+
void severe(Throwable thrown, String format, Object... args) {
110+
logWithCaller(Level.SEVERE, thrown, () -> String.format(format, args));
59111
}
60112
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ static Map<String, String> parseProxyProperties(DataSource ds, String callerClas
7171
String proxyPort = ds.getProxyPort();
7272
if (proxyPort != null) {
7373
if (!Pattern.compile(validPortRegex).matcher(proxyPort).find()) {
74+
LOG.severe(
75+
"Illegal port number provided %s. Please provide a valid port number.", proxyPort);
7476
throw new IllegalArgumentException(
7577
String.format(
7678
"Illegal port number provided %s. Please provide a valid port number.", proxyPort));
@@ -89,18 +91,23 @@ static Map<String, String> parseProxyProperties(DataSource ds, String callerClas
8991
boolean isMissingProxyHostOrPortWhenProxySet =
9092
(proxyHost == null && proxyPort != null) || (proxyHost != null && proxyPort == null);
9193
if (isMissingProxyHostOrPortWhenProxySet) {
94+
LOG.severe(
95+
"Both ProxyHost and ProxyPort parameters need to be specified. No defaulting behavior occurs.");
9296
throw new IllegalArgumentException(
9397
"Both ProxyHost and ProxyPort parameters need to be specified. No defaulting behavior"
9498
+ " occurs.");
9599
}
96100
boolean isMissingProxyUidOrPwdWhenAuthSet =
97101
(proxyUid == null && proxyPwd != null) || (proxyUid != null && proxyPwd == null);
98102
if (isMissingProxyUidOrPwdWhenAuthSet) {
103+
LOG.severe("Both ProxyUid and ProxyPwd parameters need to be specified for authentication.");
99104
throw new IllegalArgumentException(
100105
"Both ProxyUid and ProxyPwd parameters need to be specified for authentication.");
101106
}
102107
boolean isProxyAuthSetWithoutProxySettings = proxyUid != null && proxyHost == null;
103108
if (isProxyAuthSetWithoutProxySettings) {
109+
LOG.severe(
110+
"Proxy authentication provided via connection string with no proxy host or port set.");
104111
throw new IllegalArgumentException(
105112
"Proxy authentication provided via connection string with no proxy host or port set.");
106113
}
@@ -189,6 +196,7 @@ private static HttpTransportFactory getHttpTransportFactory(
189196
.setSSLSocketFactory(sslSocketFactory)
190197
.build());
191198
} catch (IOException | GeneralSecurityException e) {
199+
LOG.severe(e, "Failed to configure SSL TrustStore for HTTP transport");
192200
throw new BigQueryJdbcRuntimeException(e);
193201
}
194202
}
@@ -278,6 +286,7 @@ public ProxiedSocketAddress proxyFor(SocketAddress socketAddress) {
278286
.sslContext(grpcSslContext);
279287

280288
} catch (IOException | GeneralSecurityException e) {
289+
LOG.severe(e, "Failed to configure SSL TrustStore for GRPC channel");
281290
throw new BigQueryJdbcRuntimeException(e);
282291
}
283292
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ public String format(LogRecord record) {
124124
.append(record.getMessage())
125125
.append(System.lineSeparator());
126126

127+
if (record.getThrown() != null) {
128+
java.io.StringWriter sw = new java.io.StringWriter();
129+
record.getThrown().printStackTrace(new java.io.PrintWriter(sw));
130+
sb.append(sw.toString()).append(System.lineSeparator());
131+
}
132+
127133
return sb.toString();
128134
}
129135
};

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ QueryJobConfiguration.Builder configureParameters(
6666
QueryParameterValue.of(parameterValue, sqlType));
6767
}
6868
} catch (NullPointerException e) {
69+
LOG.severe(e, "Null parameter mapping encountered.");
6970
if (e.getMessage().contains("Null type")) {
7071
throw new BigQueryJdbcException("One or more parameters missing in Prepared statement.", e);
7172
}
@@ -103,6 +104,7 @@ void setParameter(int parameterIndex, Object value, Class type)
103104

104105
private void checkValidIndex(int parameterIndex) {
105106
if (parameterIndex > this.parametersArraySize) {
107+
LOG.severe("All parameters already provided.");
106108
throw new IndexOutOfBoundsException("All parameters already provided.");
107109
}
108110
}
@@ -151,6 +153,7 @@ void setParameter(
151153
LOG.finest("++enter++");
152154
LOG.finest("setParameter called by : %s", type.getName());
153155
if (paramName == null || paramName.isEmpty()) {
156+
LOG.severe("paramName cannot be null or empty");
154157
throw new IllegalArgumentException("paramName cannot be null or empty");
155158
}
156159
BigQueryJdbcParameter parameter = null;

0 commit comments

Comments
 (0)