Skip to content

Commit e02515e

Browse files
MarinaMoiseenkoshakuzen
authored andcommitted
Added support of @MeterTag annotation on method level
Signed-off-by: Marina Moiseenko <[email protected]>
1 parent 8fa20cd commit e02515e

File tree

9 files changed

+430
-122
lines changed

9 files changed

+430
-122
lines changed
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@
2525
*
2626
* @author Christian Schwerdtfeger
2727
*/
28-
class AnnotatedParameter {
28+
class AnnotatedObject {
2929

3030
final Annotation annotation;
3131

32-
final Object argument;
32+
final Object object;
3333

34-
AnnotatedParameter(Annotation annotation, Object argument) {
34+
AnnotatedObject(Annotation annotation, Object object) {
3535
this.annotation = annotation;
36-
this.argument = argument;
36+
this.object = object;
3737
}
3838

3939
}

micrometer-commons/src/main/java/io/micrometer/common/annotation/AnnotationHandler.java

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.*;
2727
import java.util.function.BiConsumer;
2828
import java.util.function.BiFunction;
29+
import java.util.function.Consumer;
2930
import java.util.function.Function;
3031

3132
/**
@@ -89,16 +90,36 @@ public void addAnnotatedParameters(T objectToModify, ProceedingJoinPoint pjp) {
8990
try {
9091
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
9192
method = tryToTakeMethodFromTargetClass(pjp, method);
92-
List<AnnotatedParameter> annotatedParameters = AnnotationUtils.findAnnotatedParameters(annotationClass,
93-
method, pjp.getArgs());
94-
getAnnotationsFromInterfaces(pjp, method, annotatedParameters);
93+
List<AnnotatedObject> annotatedParameters = AnnotationUtils.findAnnotatedParameters(annotationClass, method,
94+
pjp.getArgs());
95+
getParametersAnnotationsFromInterfaces(pjp, method, annotatedParameters);
9596
addAnnotatedArguments(objectToModify, annotatedParameters);
9697
}
9798
catch (Exception ex) {
9899
log.error("Exception occurred while trying to add annotated parameters", ex);
99100
}
100101
}
101102

103+
public void addAnnotatedMethodResult(T objectToModify, ProceedingJoinPoint pjp, Object result) {
104+
try {
105+
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
106+
method = tryToTakeMethodFromTargetClass(pjp, method);
107+
108+
List<AnnotatedObject> annotatedResult = new ArrayList<>();
109+
Arrays.stream(method.getAnnotationsByType(annotationClass))
110+
.map(annotation -> new AnnotatedObject(annotation, result))
111+
.forEach(annotatedResult::add);
112+
getMethodAnnotationsFromInterfaces(pjp, method).stream()
113+
.map(annotation -> new AnnotatedObject(annotation, result))
114+
.forEach(annotatedResult::add);
115+
116+
addAnnotatedArguments(objectToModify, annotatedResult);
117+
}
118+
catch (Exception ex) {
119+
log.error("Exception occurred while trying to add annotated method result", ex);
120+
}
121+
}
122+
102123
private static Method tryToTakeMethodFromTargetClass(ProceedingJoinPoint pjp, Method method) {
103124
try {
104125
return pjp.getTarget().getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
@@ -109,34 +130,48 @@ private static Method tryToTakeMethodFromTargetClass(ProceedingJoinPoint pjp, Me
109130
return method;
110131
}
111132

112-
private void getAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod,
113-
List<AnnotatedParameter> annotatedParameters) {
133+
private void getParametersAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod,
134+
List<AnnotatedObject> annotatedParameters) {
135+
traverseInterfacesHierarchy(pjp, mostSpecificMethod, method -> {
136+
List<AnnotatedObject> annotatedParametersForActualMethod = AnnotationUtils
137+
.findAnnotatedParameters(annotationClass, method, pjp.getArgs());
138+
// annotations for a single parameter can be `duplicated` by the ones
139+
// from parent interface,
140+
// however later on during key-based deduplication the ones from
141+
// specific method(target class)
142+
// will take precedence
143+
annotatedParameters.addAll(annotatedParametersForActualMethod);
144+
});
145+
}
146+
147+
private void traverseInterfacesHierarchy(ProceedingJoinPoint pjp, Method mostSpecificMethod,
148+
Consumer<Method> consumer) {
114149
Class<?>[] implementedInterfaces = pjp.getThis().getClass().getInterfaces();
115150
for (Class<?> implementedInterface : implementedInterfaces) {
116151
for (Method methodFromInterface : implementedInterface.getMethods()) {
117152
if (methodsAreTheSame(mostSpecificMethod, methodFromInterface)) {
118-
List<AnnotatedParameter> annotatedParametersForActualMethod = AnnotationUtils
119-
.findAnnotatedParameters(annotationClass, methodFromInterface, pjp.getArgs());
120-
// annotations for a single parameter can be `duplicated` by the ones
121-
// from parent interface,
122-
// however later on during key-based deduplication the ones from
123-
// specific method(target class)
124-
// will take precedence
125-
annotatedParameters.addAll(annotatedParametersForActualMethod);
153+
consumer.accept(methodFromInterface);
126154
}
127155
}
128156
}
129157
}
130158

159+
private List<Annotation> getMethodAnnotationsFromInterfaces(ProceedingJoinPoint pjp, Method mostSpecificMethod) {
160+
List<Annotation> allAnnotations = new ArrayList<>();
161+
traverseInterfacesHierarchy(pjp, mostSpecificMethod,
162+
method -> allAnnotations.addAll(Arrays.asList(method.getAnnotationsByType(annotationClass))));
163+
return allAnnotations;
164+
}
165+
131166
private boolean methodsAreTheSame(Method mostSpecificMethod, Method method) {
132167
return method.getName().equals(mostSpecificMethod.getName())
133168
&& Arrays.equals(method.getParameterTypes(), mostSpecificMethod.getParameterTypes());
134169
}
135170

136-
private void addAnnotatedArguments(T objectToModify, List<AnnotatedParameter> toBeAdded) {
171+
private void addAnnotatedArguments(T objectToModify, List<AnnotatedObject> toBeAdded) {
137172
Set<String> seen = new HashSet<>();
138-
for (AnnotatedParameter container : toBeAdded) {
139-
KeyValue keyValue = toKeyValue.apply(container.annotation, container.argument);
173+
for (AnnotatedObject container : toBeAdded) {
174+
KeyValue keyValue = toKeyValue.apply(container.annotation, container.object);
140175
if (seen.add(keyValue.getKey())) {
141176
keyValueConsumer.accept(keyValue, objectToModify);
142177
}

micrometer-commons/src/main/java/io/micrometer/common/annotation/AnnotationUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ private AnnotationUtils() {
3535

3636
}
3737

38-
static List<AnnotatedParameter> findAnnotatedParameters(Class<? extends Annotation> annotationClazz, Method method,
38+
static List<AnnotatedObject> findAnnotatedParameters(Class<? extends Annotation> annotationClazz, Method method,
3939
Object[] args) {
4040
Parameter[] parameters = method.getParameters();
41-
List<AnnotatedParameter> result = new ArrayList<>();
41+
List<AnnotatedObject> result = new ArrayList<>();
4242
for (int i = 0; i < parameters.length; i++) {
4343
Parameter parameter = parameters[i];
4444
for (Annotation annotation : parameter.getAnnotationsByType(annotationClazz)) {
45-
result.add(new AnnotatedParameter(annotation, args[i]));
45+
result.add(new AnnotatedObject(annotation, args[i]));
4646
}
4747
}
4848
return result;

micrometer-core/src/main/java/io/micrometer/core/aop/CountedAspect.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ private Function<ProceedingJoinPoint, Iterable<Tag>> makeSafe(
189189

190190
@Around("@within(io.micrometer.core.annotation.Counted) && !@annotation(io.micrometer.core.annotation.Counted) && execution(* *(..))")
191191
@Nullable
192+
192193
public Object countedClass(ProceedingJoinPoint pjp) throws Throwable {
193194
if (shouldSkip.test(pjp)) {
194195
return pjp.proceed();
@@ -241,48 +242,51 @@ private Object perform(ProceedingJoinPoint pjp, Counted counted) throws Throwabl
241242
Object result = pjp.proceed();
242243
if (result == null) {
243244
if (!counted.recordFailuresOnly()) {
244-
record(pjp, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
245+
record(pjp, result, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
245246
}
246247
return result;
247248
}
248249
else {
249250
CompletionStage<?> stage = ((CompletionStage<?>) result);
250-
return stage.whenComplete((res, throwable) -> recordCompletionResult(pjp, counted, throwable));
251+
return stage
252+
.whenComplete((res, throwable) -> recordCompletionResult(pjp, result, counted, throwable));
251253
}
252254
}
253255
catch (Throwable e) {
254-
record(pjp, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
256+
record(pjp, null, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
255257
throw e;
256258
}
257259
}
258260

259261
try {
260262
Object result = pjp.proceed();
261263
if (!counted.recordFailuresOnly()) {
262-
record(pjp, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
264+
record(pjp, result, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
263265
}
264266
return result;
265267
}
266268
catch (Throwable e) {
267-
record(pjp, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
269+
record(pjp, null, counted, e.getClass().getSimpleName(), RESULT_TAG_FAILURE_VALUE);
268270
throw e;
269271
}
270272
}
271273

272-
private void recordCompletionResult(ProceedingJoinPoint pjp, Counted counted, Throwable throwable) {
274+
private void recordCompletionResult(ProceedingJoinPoint pjp, Object methodResult, Counted counted,
275+
Throwable throwable) {
273276

274277
if (throwable != null) {
275278
String exceptionTagValue = throwable.getCause() == null ? throwable.getClass().getSimpleName()
276279
: throwable.getCause().getClass().getSimpleName();
277-
record(pjp, counted, exceptionTagValue, RESULT_TAG_FAILURE_VALUE);
280+
record(pjp, methodResult, counted, exceptionTagValue, RESULT_TAG_FAILURE_VALUE);
278281
}
279282
else if (!counted.recordFailuresOnly()) {
280-
record(pjp, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
283+
record(pjp, methodResult, counted, DEFAULT_EXCEPTION_TAG_VALUE, RESULT_TAG_SUCCESS_VALUE);
281284
}
282285

283286
}
284287

285-
private void record(ProceedingJoinPoint pjp, Counted counted, String exception, String result) {
288+
private void record(ProceedingJoinPoint pjp, Object methodResult, Counted counted, String exception,
289+
String result) {
286290
try {
287291
Counter.Builder builder = Counter.builder(counted.value())
288292
.description(counted.description().isEmpty() ? null : counted.description())
@@ -292,6 +296,7 @@ private void record(ProceedingJoinPoint pjp, Counted counted, String exception,
292296
.tags(tagsBasedOnJoinPoint.apply(pjp));
293297
if (meterTagAnnotationHandler != null) {
294298
meterTagAnnotationHandler.addAnnotatedParameters(builder, pjp);
299+
meterTagAnnotationHandler.addAnnotatedMethodResult(builder, pjp, methodResult);
295300
}
296301
builder.register(registry).increment();
297302
}

micrometer-core/src/main/java/io/micrometer/core/aop/MeterTag.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*/
3838
@Retention(RetentionPolicy.RUNTIME)
3939
@Inherited
40-
@Target(ElementType.PARAMETER)
40+
@Target({ ElementType.PARAMETER, ElementType.METHOD })
4141
@Repeatable(MeterTags.class)
4242
public @interface MeterTag {
4343

micrometer-core/src/main/java/io/micrometer/core/aop/MeterTags.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*/
3838
@Retention(RetentionPolicy.RUNTIME)
3939
@Inherited
40-
@Target(ElementType.PARAMETER)
40+
@Target({ ElementType.METHOD, ElementType.PARAMETER })
4141
@Documented
4242
public @interface MeterTags {
4343

micrometer-core/src/main/java/io/micrometer/core/aop/TimedAspect.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,45 +238,47 @@ private Object processWithTimer(ProceedingJoinPoint pjp, Timed timed, String met
238238
try {
239239
Object result = pjp.proceed();
240240
if (result == null) {
241-
record(pjp, timed, metricName, sample, DEFAULT_EXCEPTION_TAG_VALUE);
241+
record(pjp, result, timed, metricName, sample, DEFAULT_EXCEPTION_TAG_VALUE);
242242
return result;
243243
}
244244
else {
245245
CompletionStage<?> stage = ((CompletionStage<?>) result);
246-
return stage.whenComplete(
247-
(res, throwable) -> record(pjp, timed, metricName, sample, getExceptionTag(throwable)));
246+
return stage.whenComplete((res, throwable) -> record(pjp, result, timed, metricName, sample,
247+
getExceptionTag(throwable)));
248248
}
249249
}
250250
catch (Throwable e) {
251-
record(pjp, timed, metricName, sample, e.getClass().getSimpleName());
251+
record(pjp, null, timed, metricName, sample, e.getClass().getSimpleName());
252252
throw e;
253253
}
254254
}
255255

256256
String exceptionClass = DEFAULT_EXCEPTION_TAG_VALUE;
257+
Object result = null;
257258
try {
258-
return pjp.proceed();
259+
result = pjp.proceed();
260+
return result;
259261
}
260262
catch (Throwable e) {
261263
exceptionClass = e.getClass().getSimpleName();
262264
throw e;
263265
}
264266
finally {
265-
record(pjp, timed, metricName, sample, exceptionClass);
267+
record(pjp, result, timed, metricName, sample, exceptionClass);
266268
}
267269
}
268270

269-
private void record(ProceedingJoinPoint pjp, Timed timed, String metricName, Timer.Sample sample,
270-
String exceptionClass) {
271+
private void record(ProceedingJoinPoint pjp, Object methodResult, Timed timed, String metricName,
272+
Timer.Sample sample, String exceptionClass) {
271273
try {
272-
sample.stop(recordBuilder(pjp, timed, metricName, exceptionClass).register(registry));
274+
sample.stop(recordBuilder(pjp, methodResult, timed, metricName, exceptionClass).register(registry));
273275
}
274276
catch (Exception e) {
275277
WARN_THEN_DEBUG_LOGGER.log("Failed to record.", e);
276278
}
277279
}
278280

279-
private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Timed timed, String metricName,
281+
private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Object methodResult, Timed timed, String metricName,
280282
String exceptionClass) {
281283
Timer.Builder builder = Timer.builder(metricName)
282284
.description(timed.description().isEmpty() ? null : timed.description())
@@ -292,6 +294,7 @@ private Timer.Builder recordBuilder(ProceedingJoinPoint pjp, Timed timed, String
292294

293295
if (meterTagAnnotationHandler != null) {
294296
meterTagAnnotationHandler.addAnnotatedParameters(builder, pjp);
297+
meterTagAnnotationHandler.addAnnotatedMethodResult(builder, pjp, methodResult);
295298
}
296299
return builder;
297300
}

0 commit comments

Comments
 (0)