Skip to content

Commit

Permalink
set root cause as the exception_name in micrometer tags (#1883)
Browse files Browse the repository at this point in the history
* set root cause as the exception_name in micrometer tags

* set root cause as the exception_name in other metrics system

* set root cause as the exception_name in other metrics system

* Update ExceptionUtilsTest.java

* reformat

* reformat

* add root_cause_name instead of changing exception_name

Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
  • Loading branch information
chao-chang-paypay and velo committed Dec 18, 2022
1 parent 5f17624 commit 62277a9
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 4 deletions.
44 changes: 44 additions & 0 deletions core/src/main/java/feign/utils/ExceptionUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2012-2022 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.utils;

import java.util.HashSet;
import java.util.Set;

public class ExceptionUtils {
/**
* Introspects the {@link Throwable} to obtain the root cause.
*
* <p>
* This method walks through the exception chain to the last element, "root" of the tree, using
* {@link Throwable#getCause()}, and returns that exception.
*
* @param throwable the throwable to get the root cause for, may be null
* @return the root cause of the {@link Throwable}, {@code null} if null throwable input
*/
public static Throwable getRootCause(Throwable throwable) {
if (throwable == null) {
return null;
}
Throwable rootCause = throwable;
// this is to avoid infinite loops for recursive cases
final Set<Throwable> seenThrowables = new HashSet<>();
seenThrowables.add(rootCause);
while ((rootCause.getCause() != null && !seenThrowables.contains(rootCause.getCause()))) {
seenThrowables.add(rootCause.getCause());
rootCause = rootCause.getCause();
}
return rootCause;
}
}
41 changes: 41 additions & 0 deletions core/src/test/java/feign/utils/ExceptionUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2012-2022 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.utils;

import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class ExceptionUtilsTest {
@Test
public void rootCauseOfNullIsNull() {
Throwable e = null;
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertThat(rootCause).isNull();
}

@Test
public void rootCauseIsSelf() {
Throwable e = new Exception();
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertThat(rootCause).isSameAs(e);
}

@Test
public void rootCauseIsDifferent() {
Throwable rootCause = new Exception();
Throwable e = new Exception(rootCause);
Throwable actualRootCause = ExceptionUtils.getRootCause(e);
assertThat(actualRootCause).isSameAs(rootCause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import feign.FeignException;
import feign.RequestTemplate;
import feign.Response;
import feign.utils.ExceptionUtils;

class BaseMeteredClient {

Expand Down Expand Up @@ -65,6 +66,8 @@ protected void recordFailure(RequestTemplate template, FeignException e) {
httpResponseCode(template),
"exception_name",
e.getClass().getSimpleName(),
"root_cause_name",
ExceptionUtils.getRootCause(e).getClass().getSimpleName(),
"status_group",
e.status() / 100 + "xx",
"http_status",
Expand All @@ -82,6 +85,8 @@ protected void recordFailure(RequestTemplate template, Exception e) {
httpResponseCode(template),
"exception_name",
e.getClass().getSimpleName(),
"root_cause_name",
ExceptionUtils.getRootCause(e).getClass().getSimpleName(),
"uri",
template.methodMetadata().template().path()),
metricSuppliers.meters())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import feign.FeignException;
import feign.RequestTemplate;
import feign.Response;
import feign.utils.ExceptionUtils;
import io.dropwizard.metrics5.MetricName;
import io.dropwizard.metrics5.MetricRegistry;
import io.dropwizard.metrics5.Timer;
Expand Down Expand Up @@ -60,6 +61,8 @@ protected void recordFailure(RequestTemplate template, FeignException e) {
.counter(
httpResponseCode(template)
.tagged("exception_name", e.getClass().getSimpleName())
.tagged("root_cause_name",
ExceptionUtils.getRootCause(e).getClass().getSimpleName())
.tagged("http_status", String.valueOf(e.status()))
.tagged("status_group", e.status() / 100 + "xx")
.tagged("uri", template.methodMetadata().template().path()))
Expand All @@ -71,6 +74,8 @@ protected void recordFailure(RequestTemplate template, Exception e) {
.counter(
httpResponseCode(template)
.tagged("exception_name", e.getClass().getSimpleName())
.tagged("root_cause_name",
ExceptionUtils.getRootCause(e).getClass().getSimpleName())
.tagged("uri", template.methodMetadata().template().path()))
.inc();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import feign.utils.ExceptionUtils;
import io.dropwizard.metrics5.MetricRegistry;
import io.dropwizard.metrics5.Timer.Context;

Expand Down Expand Up @@ -64,13 +65,15 @@ public Object decode(Response response, Type type)
metricRegistry.meter(
metricName.metricName(template.methodMetadata(), template.feignTarget(), "error_count")
.tagged("exception_name", e.getClass().getSimpleName())
.tagged("root_cause_name", ExceptionUtils.getRootCause(e).getClass().getSimpleName())
.tagged("uri", template.methodMetadata().template().path()),
metricSuppliers.meters()).mark();
throw e;
} catch (Exception e) {
metricRegistry.meter(
metricName.metricName(template.methodMetadata(), template.feignTarget(), "error_count")
.tagged("exception_name", e.getClass().getSimpleName())
.tagged("root_cause_name", ExceptionUtils.getRootCause(e).getClass().getSimpleName())
.tagged("uri", template.methodMetadata().template().path()),
metricSuppliers.meters()).mark();
throw new IOException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
package feign.metrics5;


import feign.utils.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationHandler;
Expand Down Expand Up @@ -86,7 +86,9 @@ public InvocationHandler create(Target target, Map<Method, MethodHandler> dispat
metricRegistry
.meter(metricName.metricName(clientClass, method, target.url())
.resolve("exception")
.tagged("exception_name", e.getClass().getSimpleName()),
.tagged("exception_name", e.getClass().getSimpleName())
.tagged("root_cause_name",
ExceptionUtils.getRootCause(e).getClass().getSimpleName()),
metricSuppliers.meters())
.mark();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import feign.MethodMetadata;
import feign.Target;
import feign.utils.ExceptionUtils;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -50,6 +51,8 @@ public Tags tag(Class<?> targetType, Method method, String url, Throwable e, Tag
tags.add(Tag.of("host", extractHost(url)));
if (e != null) {
tags.add(Tag.of("exception_name", e.getClass().getSimpleName()));
tags.add(
Tag.of("root_cause_name", ExceptionUtils.getRootCause(e).getClass().getSimpleName()));
}
tags.addAll(Arrays.asList(extraTags));
return Tags.of(tags);
Expand All @@ -72,4 +75,5 @@ private String extractHost(final String targetUrl) {
? targetUrl
: targetUrl.substring(0, 20);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import feign.utils.ExceptionUtils;
import io.micrometer.core.instrument.*;
import java.io.IOException;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -95,7 +96,8 @@ protected Counter createExceptionCounter(Response response, Type type, Exception
final RequestTemplate template = response.request().requestTemplate();
final Tags allTags = metricTagResolver.tag(template.methodMetadata(), template.feignTarget(),
Tag.of("uri", template.methodMetadata().template().path()),
Tag.of("exception_name", e.getClass().getSimpleName()))
Tag.of("exception_name", e.getClass().getSimpleName()),
Tag.of("root_cause_name", ExceptionUtils.getRootCause(e).getClass().getSimpleName()))
.and(extraTags);
return meterRegistry.counter(metricName.name("error_count"), allTags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ public void shouldMetricCollectionWithCustomException() {
assertThat(thrown.getMessage(), equalTo("Test error"));

assertThat(
getMetric("exception", "exception_name", "RuntimeException", "method", "get"),
getMetric("exception", "exception_name", "RuntimeException", "method", "get",
"root_cause_name", "RuntimeException"),
notNullValue());
}

Expand Down

0 comments on commit 62277a9

Please sign in to comment.