Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

Commit 75fe9ca

Browse files
committed
fix: use recursive exception logic
1 parent efbe7ba commit 75fe9ca

2 files changed

Lines changed: 45 additions & 50 deletions

File tree

gax-java/gax/src/main/java/com/google/api/gax/tracing/ErrorTypeUtil.java

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,10 @@
3030
package com.google.api.gax.tracing;
3131

3232
import com.google.api.gax.rpc.ApiException;
33-
import com.google.api.gax.rpc.WatchdogTimeoutException;
3433
import com.google.common.base.Strings;
35-
import java.net.ConnectException;
36-
import java.net.SocketTimeoutException;
37-
import java.net.UnknownHostException;
38-
import java.nio.channels.UnresolvedAddressException;
34+
import com.google.common.collect.ImmutableSet;
35+
import java.util.Set;
3936
import javax.annotation.Nullable;
40-
import javax.net.ssl.SSLHandshakeException;
4137

4238
public class ErrorTypeUtil {
4339

@@ -58,6 +54,26 @@ public String toString() {
5854
}
5955
}
6056

57+
private static final Set<String> JSON_DECODING_EXCEPTION_CLASS_NAMES =
58+
ImmutableSet.of(
59+
"com.google.gson.JsonSyntaxException",
60+
"com.google.gson.JsonParseException",
61+
"com.fasterxml.jackson.databind.JsonMappingException",
62+
"com.fasterxml.jackson.core.JsonParseException");
63+
64+
private static final Set<String> AUTHENTICATION_EXCEPTION_CLASS_NAMES =
65+
ImmutableSet.of("com.google.auth.oauth2.GoogleAuthException");
66+
67+
private static final Set<String> CLIENT_TIMEOUT_EXCEPTION_CLASS_NAMES =
68+
ImmutableSet.of(
69+
"java.net.SocketTimeoutException", "com.google.api.gax.rpc.WatchdogTimeoutException");
70+
private static final Set<String> CLIENT_CONNECTION_EXCEPTIONS =
71+
ImmutableSet.of(
72+
"java.net.ConnectException",
73+
"java.net.UnknownHostException",
74+
"javax.net.ssl.SSLHandshakeException",
75+
"java.nio.channels.UnresolvedAddressException");
76+
6177
/**
6278
* Extracts a low-cardinality string representing the specific classification of the error to be
6379
* used in the {@link ObservabilityAttributes#ERROR_TYPE_ATTRIBUTE} attribute.
@@ -206,7 +222,7 @@ private static String getClientSideError(Throwable error) {
206222
* @return true if the error is a client timeout, false otherwise.
207223
*/
208224
private static boolean isClientTimeout(Throwable e) {
209-
return e instanceof SocketTimeoutException || e instanceof WatchdogTimeoutException;
225+
return hasErrorNameInCauseChain(e, CLIENT_TIMEOUT_EXCEPTION_CLASS_NAMES);
210226
}
211227

212228
/**
@@ -217,10 +233,7 @@ private static boolean isClientTimeout(Throwable e) {
217233
* @return true if the error is a client connection error, false otherwise.
218234
*/
219235
private static boolean isClientConnectionError(Throwable e) {
220-
return e instanceof ConnectException
221-
|| e instanceof UnknownHostException
222-
|| e instanceof SSLHandshakeException
223-
|| e instanceof UnresolvedAddressException;
236+
return hasErrorNameInCauseChain(e, CLIENT_CONNECTION_EXCEPTIONS);
224237
}
225238

226239
/**
@@ -231,9 +244,7 @@ private static boolean isClientConnectionError(Throwable e) {
231244
* @return true if the error is a client response decode error, false otherwise.
232245
*/
233246
private static boolean isClientResponseDecodeError(Throwable e) {
234-
return e.getClass().getName().contains("Json")
235-
|| e.getClass().getName().contains("Gson")
236-
|| (e.getCause() != null && e.getCause().getClass().getName().contains("Gson"));
247+
return hasErrorNameInCauseChain(e, JSON_DECODING_EXCEPTION_CLASS_NAMES);
237248
}
238249

239250
/**
@@ -255,7 +266,7 @@ private static boolean isClientRedirectError(Throwable e) {
255266
* @return true if the error is a client authentication error, false otherwise.
256267
*/
257268
private static boolean isClientAuthenticationError(Throwable e) {
258-
return e.getClass().getName().contains("GoogleAuthException");
269+
return hasErrorNameInCauseChain(e, AUTHENTICATION_EXCEPTION_CLASS_NAMES);
259270
}
260271

261272
/**
@@ -267,7 +278,7 @@ private static boolean isClientAuthenticationError(Throwable e) {
267278
* @return true if the error is a client request body error, false otherwise.
268279
*/
269280
private static boolean isRequestBodyError(Throwable e) {
270-
return e.getClass().getName().contains("RestSerializationException");
281+
return hasErrorNameInCauseChain(e, ImmutableSet.of("RestSerializationException"));
271282
}
272283

273284
/**
@@ -281,4 +292,22 @@ private static boolean isRequestBodyError(Throwable e) {
281292
private static boolean isClientUnknownError(Throwable e) {
282293
return e.getClass().getName().toLowerCase().contains("unknown");
283294
}
295+
296+
/**
297+
* Recursively checks the throwable and its cause chain for any of the specified error name.
298+
*
299+
* @param t The Throwable to check.
300+
* @param errorClassNames A set of fully qualified class names to check against.
301+
* @return true if an error from the set is found in the cause chain, false otherwise.
302+
*/
303+
private static boolean hasErrorNameInCauseChain(Throwable t, Set<String> errorClassNames) {
304+
Throwable current = t;
305+
while (current != null) {
306+
if (errorClassNames.contains(current.getClass().getName())) {
307+
return true;
308+
}
309+
current = current.getCause();
310+
}
311+
return false;
312+
}
284313
}

gax-java/gax/src/test/java/com/google/api/gax/tracing/SpanTracerTest.java

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,6 @@ void testAttemptFailed_clientConnectionError() {
210210
verify(attemptHandle).end();
211211
}
212212

213-
@Test
214-
void testAttemptFailed_clientAuthenticationError() {
215-
when(recorder.createSpan(eq(ATTEMPT_SPAN_NAME), anyMap())).thenReturn(attemptHandle);
216-
217-
tracer.attemptStarted(new Object(), 1);
218-
219-
tracer.attemptFailedRetriesExhausted(new TestGoogleAuthException());
220-
221-
verify(attemptHandle)
222-
.addAttribute(
223-
ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE,
224-
ErrorTypeUtil.ErrorType.CLIENT_AUTHENTICATION_ERROR.toString());
225-
verify(attemptHandle).end();
226-
}
227-
228213
@Test
229214
void testAttemptFailed_clientResponseDecodeError() {
230215
when(recorder.createSpan(eq(ATTEMPT_SPAN_NAME), anyMap())).thenReturn(attemptHandle);
@@ -255,21 +240,6 @@ void testAttemptFailed_clientRedirectError() {
255240
verify(attemptHandle).end();
256241
}
257242

258-
@Test
259-
void testAttemptFailed_clientRequestBodyError() {
260-
when(recorder.createSpan(eq(ATTEMPT_SPAN_NAME), anyMap())).thenReturn(attemptHandle);
261-
262-
tracer.attemptStarted(new Object(), 1);
263-
264-
tracer.attemptFailedRetriesExhausted(new TestRestSerializationException());
265-
266-
verify(attemptHandle)
267-
.addAttribute(
268-
ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE,
269-
ErrorTypeUtil.ErrorType.CLIENT_REQUEST_BODY_ERROR.toString());
270-
verify(attemptHandle).end();
271-
}
272-
273243
@Test
274244
void testAttemptFailed_clientRequestError() {
275245
when(recorder.createSpan(eq(ATTEMPT_SPAN_NAME), anyMap())).thenReturn(attemptHandle);
@@ -347,15 +317,11 @@ void testAttemptFailed_internalFallback_nullError() {
347317
verify(attemptHandle).end();
348318
}
349319

350-
private static class TestGoogleAuthException extends RuntimeException {}
351-
352320
private static class RedirectException extends RuntimeException {
353321
public RedirectException(String message) {
354322
super(message);
355323
}
356324
}
357325

358-
private static class TestRestSerializationException extends RuntimeException {}
359-
360326
private static class UnknownClientException extends RuntimeException {}
361327
}

0 commit comments

Comments
 (0)