diff --git a/infinite-tracing/src/main/java/com/newrelic/ResponseObserver.java b/infinite-tracing/src/main/java/com/newrelic/ResponseObserver.java index a475773de8..ca72f74971 100644 --- a/infinite-tracing/src/main/java/com/newrelic/ResponseObserver.java +++ b/infinite-tracing/src/main/java/com/newrelic/ResponseObserver.java @@ -43,7 +43,10 @@ public void onError(Throwable t) { return; } - logger.log(Level.WARNING, t, "Encountered gRPC exception"); + if (!isConnectionTimeoutException(t)) { + logger.log(Level.WARNING, t, "Encountered gRPC exception"); + } + metricAggregator.incrementCounter("Supportability/InfiniteTracing/Response/Error"); Status status = null; @@ -70,6 +73,14 @@ private boolean isChannelClosing(Throwable t) { return t instanceof StatusRuntimeException && t.getCause() instanceof ChannelClosingException; } + /** + * Detects if the error received was a connection timeout exception. This can happen if the agent hasn't sent any spans for more than 15 seconds. + */ + private boolean isConnectionTimeoutException(Throwable t) { + return t instanceof StatusRuntimeException + && t.getMessage().startsWith("INTERNAL: No error: A GRPC status of OK should have been sent"); + } + /** * Attempts to detect if the error received indicates that ALPN support is not provided by this JVM. */ diff --git a/infinite-tracing/src/test/java/com/newrelic/ResponseObserverTest.java b/infinite-tracing/src/test/java/com/newrelic/ResponseObserverTest.java index c71cc24536..a107c2a9b8 100644 --- a/infinite-tracing/src/test/java/com/newrelic/ResponseObserverTest.java +++ b/infinite-tracing/src/test/java/com/newrelic/ResponseObserverTest.java @@ -8,13 +8,18 @@ import org.junit.jupiter.api.Test; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; class ResponseObserverTest { + + AtomicBoolean shouldRecreateCall = new AtomicBoolean(); + @Test public void shouldIncrementCounterOnNext() { MetricAggregator metricAggregator = mock(MetricAggregator.class); @@ -115,5 +120,56 @@ public void shouldTerminateOnALPNError() { verify(disconnectionHandler).terminate(); } - AtomicBoolean shouldRecreateCall = new AtomicBoolean(); + @Test + public void testIsConnectionTimeoutException() { + DisconnectionHandler disconnectionHandler = mock(DisconnectionHandler.class); + MetricAggregator metricAggregator = mock(MetricAggregator.class); + Logger logger = mock(Logger.class); + + ResponseObserver target = new ResponseObserver( + metricAggregator, + logger, + disconnectionHandler, shouldRecreateCall); + + Throwable exception = new StatusRuntimeException( + Status.fromCode(Status.Code.INTERNAL).withDescription("No error: A GRPC status of OK should have been sent\nRst Stream")); + target.onError(exception); + + verify(logger, never()).log(Level.WARNING, exception, "Encountered gRPC exception"); + } + + @Test + public void testConnectionTimeoutExceptionWrongType() { + DisconnectionHandler disconnectionHandler = mock(DisconnectionHandler.class); + MetricAggregator metricAggregator = mock(MetricAggregator.class); + Logger logger = mock(Logger.class); + + ResponseObserver target = new ResponseObserver( + metricAggregator, + logger, + disconnectionHandler, shouldRecreateCall); + + Throwable exception = new RuntimeException("No error: A GRPC status of OK should have been sent\nRst Stream"); + target.onError(exception); + + verify(logger).log(Level.WARNING, exception, "Encountered gRPC exception"); + } + + @Test + public void testConnectionTimeoutExceptionWrongMessage() { + DisconnectionHandler disconnectionHandler = mock(DisconnectionHandler.class); + MetricAggregator metricAggregator = mock(MetricAggregator.class); + Logger logger = mock(Logger.class); + + ResponseObserver target = new ResponseObserver( + metricAggregator, + logger, + disconnectionHandler, shouldRecreateCall); + + Throwable exception = new StatusRuntimeException(Status.fromCode(Status.Code.INTERNAL).withDescription("A REALLY BAD ERROR: PRINT ME")); + target.onError(exception); + + verify(logger).log(Level.WARNING, exception, "Encountered gRPC exception"); + } + } \ No newline at end of file