Skip to content

Commit

Permalink
MeterTags wrapper to support multiple MeterTag-s on a single method p…
Browse files Browse the repository at this point in the history
…arameter (#5055)

Resolves gh-4081

---------

Co-authored-by: Maksym Symonov <maksym.symonov@nordstrom.com>
  • Loading branch information
smaxx and Maksym Symonov committed Jul 9, 2024
1 parent 3cc137b commit dd9194a
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
Expand All @@ -36,16 +38,15 @@ private AnnotationUtils() {

static List<AnnotatedParameter> findAnnotatedParameters(Class<? extends Annotation> annotationClazz, Method method,
Object[] args) {
Annotation[][] parameters = method.getParameterAnnotations();
List<AnnotatedParameter> result = new ArrayList<>();
int i = 0;
for (Annotation[] parameter : parameters) {
for (Annotation parameter2 : parameter) {
if (annotationClazz.isAssignableFrom(parameter2.annotationType())) {
result.add(new AnnotatedParameter(i, parameter2, args[i]));
}
}
i++;
Parameter[] parameters = method.getParameters();
List<AnnotatedParameter> result = new LinkedList<>();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Annotation[] annotations = parameter.getAnnotationsByType(annotationClazz);
final int parameterIndex = i;
Arrays.stream(annotations)
.map(annotation -> new AnnotatedParameter(parameterIndex, annotation, args[parameterIndex]))
.forEach(result::add);
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.PARAMETER)
@Repeatable(MeterTags.class)
public @interface MeterTag {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright 2024 the original author or 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
*
* https://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 io.micrometer.core.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Container annotation that aggregates several {@link MeterTag} annotations.
*
* Can be used natively, declaring several nested {@link MeterTag} annotations. Can also
* be used in conjunction with Java 8's support for repeatable annotations, where
* {@link MeterTag} can simply be declared several times on the same parameter, implicitly
* generating this container annotation.
*
* @author Maksym Symonov
* @author Marcin Grzejszczak
* @since 1.14.0
* @see MeterTag
*/
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.PARAMETER)
@Documented
public @interface MeterTags {

MeterTag[] value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,49 @@ void meterTagsWithExpression(AnnotatedTestClass annotatedClass) {
assertThat(registry.get("method.timed").tag("test", "hello characters").timer().count()).isEqualTo(1);
}

@ParameterizedTest
@EnumSource(AnnotatedTestClass.class)
void multipleMeterTagsWithExpression(AnnotatedTestClass annotatedClass) {
MeterRegistry registry = new SimpleMeterRegistry();
TimedAspect timedAspect = new TimedAspect(registry);
timedAspect.setMeterTagAnnotationHandler(meterTagAnnotationHandler);

AspectJProxyFactory pf = new AspectJProxyFactory(annotatedClass.newInstance());
pf.addAspect(timedAspect);

MeterTagClassInterface service = pf.getProxy();

service.getMultipleAnnotationsForTagValueExpression(new DataHolder("zxe", "qwe"));

assertThat(registry.get("method.timed")
.tag("value1", "value1: zxe")
.tag("value2", "value2: qwe")
.timer()
.count()).isEqualTo(1);
}

@ParameterizedTest
@EnumSource(AnnotatedTestClass.class)
void multipleMeterTagsWithinContainerWithExpression(AnnotatedTestClass annotatedClass) {
MeterRegistry registry = new SimpleMeterRegistry();
TimedAspect timedAspect = new TimedAspect(registry);
timedAspect.setMeterTagAnnotationHandler(meterTagAnnotationHandler);

AspectJProxyFactory pf = new AspectJProxyFactory(annotatedClass.newInstance());
pf.addAspect(timedAspect);

MeterTagClassInterface service = pf.getProxy();

service.getMultipleAnnotationsWithContainerForTagValueExpression(new DataHolder("zxe", "qwe"));

assertThat(registry.get("method.timed")
.tag("value1", "value1: zxe")
.tag("value2", "value2: qwe")
.tag("value3", "value3: ZXEQWE")
.timer()
.count()).isEqualTo(1);
}

@Test
void meterTagOnPackagePrivateMethod() {
MeterRegistry registry = new SimpleMeterRegistry();
Expand Down Expand Up @@ -525,6 +568,17 @@ void getAnnotationForTagValueExpression(
@Timed
void getAnnotationForArgumentToString(@MeterTag("test") Long param);

@Timed
void getMultipleAnnotationsForTagValueExpression(
@MeterTag(key = "value1", expression = "'value1: ' + value1") @MeterTag(key = "value2",
expression = "'value2: ' + value2") DataHolder param);

@Timed
void getMultipleAnnotationsWithContainerForTagValueExpression(@MeterTags({
@MeterTag(key = "value1", expression = "'value1: ' + value1"),
@MeterTag(key = "value2", expression = "'value2: ' + value2"), @MeterTag(key = "value3",
expression = "'value3: ' + value1.toUpperCase + value2.toUpperCase") }) DataHolder param);

}

static class MeterTagClass implements MeterTagClassInterface {
Expand All @@ -550,6 +604,22 @@ public void getAnnotationForArgumentToString(@MeterTag("test") Long param) {
void getAnnotationForPackagePrivateMethod(@MeterTag("foo") String foo) {
}

@Timed
@Override
public void getMultipleAnnotationsForTagValueExpression(
@MeterTag(key = "value1", expression = "'value1: ' + value1") @MeterTag(key = "value2",
expression = "'value2: ' + value2") DataHolder param) {

}

@Timed
@Override
public void getMultipleAnnotationsWithContainerForTagValueExpression(@MeterTags({
@MeterTag(key = "value1", expression = "'value1: ' + value1"),
@MeterTag(key = "value2", expression = "'value2: ' + value2"), @MeterTag(key = "value3",
expression = "'value3: ' + value1.toUpperCase + value2.toUpperCase") }) DataHolder param) {
}

}

static class MeterTagClassChild implements MeterTagClassInterface {
Expand All @@ -569,6 +639,18 @@ public void getAnnotationForTagValueExpression(String test) {
public void getAnnotationForArgumentToString(Long param) {
}

@Timed
@Override
public void getMultipleAnnotationsForTagValueExpression(DataHolder param) {

}

@Timed
@Override
public void getMultipleAnnotationsWithContainerForTagValueExpression(DataHolder param) {

}

}

static class MeterTagSuper {
Expand Down Expand Up @@ -699,4 +781,25 @@ public void call() {

}

public static final class DataHolder {

private final String value1;

private final String value2;

private DataHolder(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}

public String getValue1() {
return value1;
}

public String getValue2() {
return value2;
}

}

}

0 comments on commit dd9194a

Please sign in to comment.