Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support of @MeterTag annotation on method level #5587

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
*
* @author Christian Schwerdtfeger
*/
class AnnotatedParameter {
class AnnotatedObject {

final Annotation annotation;

final Object argument;
final Object object;

AnnotatedParameter(Annotation annotation, Object argument) {
AnnotatedObject(Annotation annotation, Object object) {
this.annotation = annotation;
this.argument = argument;
this.object = object;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

/**
Expand Down Expand Up @@ -89,16 +90,36 @@ public void addAnnotatedParameters(T objectToModify, ProceedingJoinPoint pjp) {
try {
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
method = tryToTakeMethodFromTargetClass(pjp, method);
List<AnnotatedParameter> annotatedParameters = AnnotationUtils.findAnnotatedParameters(annotationClass,
method, pjp.getArgs());
getAnnotationsFromInterfaces(pjp, method, annotatedParameters);
List<AnnotatedObject> annotatedParameters = AnnotationUtils.findAnnotatedParameters(annotationClass, method,
pjp.getArgs());
getParametersAnnotationsFromInterfaces(pjp, method, annotatedParameters);
addAnnotatedArguments(objectToModify, annotatedParameters);
}
catch (Exception ex) {
log.error("Exception occurred while trying to add annotated parameters", ex);
}
}

public void addAnnotatedMethodResult(T objectToModify, ProceedingJoinPoint pjp, Object result) {
try {
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
method = tryToTakeMethodFromTargetClass(pjp, method);

List<AnnotatedObject> annotatedResult = new ArrayList<>();
Arrays.stream(method.getAnnotationsByType(annotationClass))
.map(annotation -> new AnnotatedObject(annotation, result))
.forEach(annotatedResult::add);
getMethodAnnotationsFromInterfaces(pjp, method).stream()
.map(annotation -> new AnnotatedObject(annotation, result))
.forEach(annotatedResult::add);

addAnnotatedArguments(objectToModify, annotatedResult);
}
catch (Exception ex) {
log.error("Exception occurred while trying to add annotated method result", ex);
}
}

private static Method tryToTakeMethodFromTargetClass(ProceedingJoinPoint pjp, Method method) {
try {
return pjp.getTarget().getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
Expand All @@ -109,34 +130,48 @@ private static Method tryToTakeMethodFromTargetClass(ProceedingJoinPoint pjp, Me
return method;
}

private void getAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod,
List<AnnotatedParameter> annotatedParameters) {
private void getParametersAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod,
List<AnnotatedObject> annotatedParameters) {
traverseInterfacesHierarchy(pjp, mostSpecificMethod, method -> {
List<AnnotatedObject> annotatedParametersForActualMethod = AnnotationUtils
.findAnnotatedParameters(annotationClass, method, pjp.getArgs());
// annotations for a single parameter can be `duplicated` by the ones
// from parent interface,
// however later on during key-based deduplication the ones from
// specific method(target class)
// will take precedence
annotatedParameters.addAll(annotatedParametersForActualMethod);
});
}

private void traverseInterfacesHierarchy(ProceedingJoinPoint pjp, Method mostSpecificMethod,
Consumer<Method> consumer) {
Class<?>[] implementedInterfaces = pjp.getThis().getClass().getInterfaces();
for (Class<?> implementedInterface : implementedInterfaces) {
for (Method methodFromInterface : implementedInterface.getMethods()) {
if (methodsAreTheSame(mostSpecificMethod, methodFromInterface)) {
List<AnnotatedParameter> annotatedParametersForActualMethod = AnnotationUtils
.findAnnotatedParameters(annotationClass, methodFromInterface, pjp.getArgs());
// annotations for a single parameter can be `duplicated` by the ones
// from parent interface,
// however later on during key-based deduplication the ones from
// specific method(target class)
// will take precedence
annotatedParameters.addAll(annotatedParametersForActualMethod);
consumer.accept(methodFromInterface);
}
}
}
}

private List<Annotation> getMethodAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod) {
List<Annotation> allAnnotations = new ArrayList<>();
traverseInterfacesHierarchy(pjp, mostSpecificMethod,
method -> allAnnotations.addAll(Arrays.asList(method.getAnnotationsByType(annotationClass))));
return allAnnotations;
}

private boolean methodsAreTheSame(Method mostSpecificMethod, Method method) {
return method.getName().equals(mostSpecificMethod.getName())
&& Arrays.equals(method.getParameterTypes(), mostSpecificMethod.getParameterTypes());
}

private void addAnnotatedArguments(T objectToModify, List<AnnotatedParameter> toBeAdded) {
private void addAnnotatedArguments(T objectToModify, List<AnnotatedObject> toBeAdded) {
Set<String> seen = new HashSet<>();
for (AnnotatedParameter container : toBeAdded) {
KeyValue keyValue = toKeyValue.apply(container.annotation, container.argument);
for (AnnotatedObject container : toBeAdded) {
KeyValue keyValue = toKeyValue.apply(container.annotation, container.object);
if (seen.add(keyValue.getKey())) {
keyValueConsumer.accept(keyValue, objectToModify);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ private AnnotationUtils() {

}

static List<AnnotatedParameter> findAnnotatedParameters(Class<? extends Annotation> annotationClazz, Method method,
static List<AnnotatedObject> findAnnotatedParameters(Class<? extends Annotation> annotationClazz, Method method,
Object[] args) {
Parameter[] parameters = method.getParameters();
List<AnnotatedParameter> result = new ArrayList<>();
List<AnnotatedObject> result = new ArrayList<>();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
for (Annotation annotation : parameter.getAnnotationsByType(annotationClazz)) {
result.add(new AnnotatedParameter(annotation, args[i]));
result.add(new AnnotatedObject(annotation, args[i]));
}
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,56 +221,59 @@ private Object perform(ProceedingJoinPoint pjp, Counted counted) throws Throwabl
if (stopWhenCompleted) {
try {
return ((CompletionStage<?>) pjp.proceed())
.whenComplete((result, throwable) -> recordCompletionResult(pjp, counted, throwable));
.whenComplete((result, throwable) -> recordCompletionResult(pjp, result, counted, throwable));
}
catch (Throwable e) {
record(pjp, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
record(pjp, null, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
throw e;
}
}

try {
Object result = pjp.proceed();
if (!counted.recordFailuresOnly()) {
record(pjp, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
record(pjp, result, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
}
return result;
}
catch (Throwable e) {
record(pjp, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
record(pjp, null, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
throw e;
}
}

private void recordCompletionResult(ProceedingJoinPoint pjp, Counted counted, Throwable throwable) {
private void recordCompletionResult(ProceedingJoinPoint pjp, Object methodResult, Counted counted,
Throwable throwable) {

if (throwable != null) {
String exceptionTagValue = throwable.getCause() == null ? throwable.getClass().getSimpleName()
: throwable.getCause().getClass().getSimpleName();
record(pjp, counted, exceptionTagValue, RESULT_TAG_FAILURE_VALUE);
record(pjp, methodResult, counted, exceptionTagValue, RESULT_TAG_FAILURE_VALUE);
}
else if (!counted.recordFailuresOnly()) {
record(pjp, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
record(pjp, methodResult, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
}

}

private void record(ProceedingJoinPoint pjp, Counted counted, String exception, String result) {
counter(pjp, counted).tag(EXCEPTION_TAG, exception)
private void record(ProceedingJoinPoint pjp, Object methodResult, Counted counted, String exception,
String result) {
counter(pjp, methodResult, counted).tag(EXCEPTION_TAG, exception)
.tag(RESULT_TAG, result)
.tags(counted.extraTags())
.register(registry)
.increment();
}

private Counter.Builder counter(ProceedingJoinPoint pjp, Counted counted) {
private Counter.Builder counter(ProceedingJoinPoint pjp, Object methodResult, Counted counted) {
Counter.Builder builder = Counter.builder(counted.value()).tags(tagsBasedOnJoinPoint.apply(pjp));
String description = counted.description();
if (!description.isEmpty()) {
builder.description(description);
}
if (meterTagAnnotationHandler != null) {
meterTagAnnotationHandler.addAnnotatedParameters(builder, pjp);
meterTagAnnotationHandler.addAnnotatedMethodResult(builder, pjp, methodResult);
}
return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.PARAMETER)
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Repeatable(MeterTags.class)
public @interface MeterTag {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.PARAMETER)
@Target({ ElementType.METHOD, ElementType.PARAMETER })
@Documented
public @interface MeterTags {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,39 +218,41 @@ private Object processWithTimer(ProceedingJoinPoint pjp, Timed timed, String met

if (stopWhenCompleted) {
try {
return ((CompletionStage<?>) pjp.proceed()).whenComplete(
(result, throwable) -> record(pjp, timed, metricName, sample, getExceptionTag(throwable)));
return ((CompletionStage<?>) pjp.proceed()).whenComplete((result, throwable) -> record(pjp, result,
timed, metricName, sample, getExceptionTag(throwable)));
}
catch (Throwable e) {
record(pjp, timed, metricName, sample, e.getClass().getSimpleName());
record(pjp, null, timed, metricName, sample, e.getClass().getSimpleName());
throw e;
}
}

String exceptionClass = DEFAULT_EXCEPTION_TAG_VALUE;
Object result = null;
try {
return pjp.proceed();
result = pjp.proceed();
return result;
}
catch (Throwable e) {
exceptionClass = e.getClass().getSimpleName();
throw e;
}
finally {
record(pjp, timed, metricName, sample, exceptionClass);
record(pjp, result, timed, metricName, sample, exceptionClass);
}
}

private void record(ProceedingJoinPoint pjp, Timed timed, String metricName, Timer.Sample sample,
String exceptionClass) {
private void record(ProceedingJoinPoint pjp, Object methodResult, Timed timed, String metricName,
Timer.Sample sample, String exceptionClass) {
try {
sample.stop(recordBuilder(pjp, timed, metricName, exceptionClass).register(registry));
sample.stop(recordBuilder(pjp, methodResult, timed, metricName, exceptionClass).register(registry));
}
catch (Exception e) {
// ignoring on purpose
}
}

private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Timed timed, String metricName,
private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Object methodResult, Timed timed, String metricName,
String exceptionClass) {
Timer.Builder builder = Timer.builder(metricName)
.description(timed.description().isEmpty() ? null : timed.description())
Expand All @@ -266,6 +268,7 @@ private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Timed timed, String

if (meterTagAnnotationHandler != null) {
meterTagAnnotationHandler.addAnnotatedParameters(builder, pjp);
meterTagAnnotationHandler.addAnnotatedMethodResult(builder, pjp, methodResult);
}
return builder;
}
Expand Down
Loading