diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java index 66e47c1d0555..ac732b688403 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java @@ -81,6 +81,14 @@ public static String toString(final Object object) { return object.toString(); } + public static boolean startWith(String str, String prefix) { + return str != null && str.startsWith(prefix); + } + + public static boolean contains(String str, String prefix) { + return str != null && str.contains(prefix); + } + public static String abbreviate(final String str) { return abbreviate(str, DEFAULT_ABBREVIATE_MAX_WIDTH); diff --git a/grpc/src/main/java/com/navercorp/pinpoint/grpc/StatusErrors.java b/grpc/src/main/java/com/navercorp/pinpoint/grpc/StatusErrors.java index ca5d3c4cd2b8..97daa7e47381 100644 --- a/grpc/src/main/java/com/navercorp/pinpoint/grpc/StatusErrors.java +++ b/grpc/src/main/java/com/navercorp/pinpoint/grpc/StatusErrors.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.grpc; +import com.navercorp.pinpoint.common.util.StringUtils; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -23,21 +24,23 @@ * @author jaehong.kim */ public class StatusErrors { - private static final String CONNECTION_REFUSED_MESSAGE = "Connection refused: no further information"; - private static final String CANCELLED_BEFORE_RECEIVING_HALF_CLOSE = "CANCELLED: cancelled before receiving half close"; + static final String CONNECTION_REFUSED_MESSAGE = "Connection refused: no further information"; + static final String CANCELLED_BEFORE_RECEIVING_HALF_CLOSE = "CANCELLED: cancelled before receiving half close"; public static StatusError throwable(final Throwable t) { if (t instanceof StatusRuntimeException) { - StatusRuntimeException exception = (StatusRuntimeException) t; - if (exception.getStatus().getCode() == Status.UNAVAILABLE.getCode()) { + final StatusRuntimeException exception = (StatusRuntimeException) t; + final Status.Code code = exception.getStatus().getCode(); + if (code == Status.UNAVAILABLE.getCode()) { final String causeMessage = findCauseMessage(t, CONNECTION_REFUSED_MESSAGE, 2); if (causeMessage != null) { final String message = exception.getStatus().getDescription() + ": " + causeMessage; return new SimpleStatusError(message, t); } - } else if (exception.getStatus().getCode() == Status.CANCELLED.getCode()) { - if (exception.getMessage() != null && exception.getMessage().startsWith(CANCELLED_BEFORE_RECEIVING_HALF_CLOSE)) { + } else if (code == Status.CANCELLED.getCode()) { + final String message = exception.getMessage(); + if (StringUtils.contains(message, CANCELLED_BEFORE_RECEIVING_HALF_CLOSE)) { return new SimpleStatusError(CANCELLED_BEFORE_RECEIVING_HALF_CLOSE, t); } } @@ -49,8 +52,9 @@ private static String findCauseMessage(final Throwable t, final String message, int depth = 0; Throwable cause = t.getCause(); while (cause != null && depth < maxDepth) { - if (cause.getMessage().startsWith(message)) { - return cause.getMessage(); + String causeMessage = cause.getMessage(); + if (StringUtils.startWith(causeMessage, message)) { + return causeMessage; } if (cause.getCause() == cause) { @@ -63,6 +67,7 @@ private static String findCauseMessage(final Throwable t, final String message, return null; } + private static class SimpleStatusError implements StatusError { private final String message; private final Throwable throwable; diff --git a/grpc/src/test/java/com/navercorp/pinpoint/grpc/StatusErrorsTest.java b/grpc/src/test/java/com/navercorp/pinpoint/grpc/StatusErrorsTest.java index 43c1ffe116a8..af42366553e2 100644 --- a/grpc/src/test/java/com/navercorp/pinpoint/grpc/StatusErrorsTest.java +++ b/grpc/src/test/java/com/navercorp/pinpoint/grpc/StatusErrorsTest.java @@ -16,12 +16,17 @@ package com.navercorp.pinpoint.grpc; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author jaehong.kim @@ -35,4 +40,55 @@ public void throwable() { assertEquals("test", statusError.getMessage()); assertFalse(statusError.isSimpleError()); } + + + @Test + public void throwable_null_message() { + StatusError statusError = StatusErrors.throwable(new RuntimeException()); + assertNull(statusError.getMessage()); + assertFalse(statusError.isSimpleError()); + } + + @Test + public void throwable_status_cause_message_is_null() { + Status unavailable = Status.UNAVAILABLE.withCause(new RuntimeException()); + StatusRuntimeException t = new StatusRuntimeException(unavailable); + + StatusError statusError = StatusErrors.throwable(t); + assertEquals(Status.UNAVAILABLE.getCode().toString(), statusError.getMessage()); + assertFalse(statusError.isSimpleError()); + } + + @Test + public void throwable_status_cause_message() { + Status unavailable = Status.UNAVAILABLE.withCause(new RuntimeException("test")); + StatusRuntimeException t = new StatusRuntimeException(unavailable); + + StatusError statusError = StatusErrors.throwable(t); + assertEquals(Status.UNAVAILABLE.getCode().toString(), statusError.getMessage()); + assertFalse(statusError.isSimpleError()); + } + + @Test + public void throwable_status_cause_connection_refuse() { + RuntimeException cause = new RuntimeException(StatusErrors.CONNECTION_REFUSED_MESSAGE); + Status unavailable = Status.UNAVAILABLE.withCause(cause); + StatusRuntimeException t = new StatusRuntimeException(unavailable); + + StatusError statusError = StatusErrors.throwable(t); + Assertions.assertThat(statusError.getMessage()) + .contains(StatusErrors.CONNECTION_REFUSED_MESSAGE ); + assertTrue(statusError.isSimpleError()); + } + + @Test + public void throwable_status_cancel() { + Status cancel = Status.CANCELLED.withDescription(StatusErrors.CANCELLED_BEFORE_RECEIVING_HALF_CLOSE); + StatusRuntimeException t = new StatusRuntimeException(cancel); + + StatusError statusError = StatusErrors.throwable(t); + Assertions.assertThat(statusError.getMessage()) + .contains(Status.CANCELLED.getCode().toString()); + assertTrue(statusError.isSimpleError()); + } } \ No newline at end of file