diff --git a/build.gradle b/build.gradle index 7a19a5fc25..e70271d10a 100644 --- a/build.gradle +++ b/build.gradle @@ -126,7 +126,7 @@ subprojects { javadoc { - if (project.name.contains('samples')) { + if (project.name.contains('samples') || project.name.contains("-test-aspectj")) { enabled = false } else { configure(options) { @@ -289,7 +289,7 @@ subprojects { } // Do not publish some modules - if (!['samples', 'benchmarks', 'micrometer-osgi-test', 'concurrency-tests'].find { project.name.contains(it) }) { + if (!['samples', 'benchmarks', 'micrometer-osgi-test', 'concurrency-tests', 'micrometer-test-aspectj-ctw', 'micrometer-test-aspectj-ltw'].find { project.name.contains(it) }) { apply plugin: 'com.netflix.nebula.maven-publish' apply plugin: 'com.netflix.nebula.maven-manifest' apply plugin: 'com.netflix.nebula.maven-developer' @@ -337,7 +337,7 @@ subprojects { check.dependsOn("testModules") - if (!(project.name in [])) { // add projects here that do not exist in the previous minor so should be excluded from japicmp + if (!(project.name in ['micrometer-test-aspectj-ltw', 'micrometer-test-aspectj-ctw'])) { // add projects here that do not exist in the previous minor so should be excluded from japicmp apply plugin: 'me.champeau.gradle.japicmp' apply plugin: 'de.undercouch.download' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ead04d89c2..eb91f2afad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ activemq-artemis = "2.34.0" application-insights = "2.6.4" archunit = "1.3.0" asmForPlugins = "7.3.1" -aspectjweaver = "1.9.22.1" +aspectjweaver = "1.9.20.1" assertj = "3.26.0" awaitility = "4.2.1" caffeine = "2.9.3" @@ -89,6 +89,7 @@ activemqArtemisJunit5 = { module = "org.apache.activemq:artemis-junit-5", versio applicationInsights = { module = "com.microsoft.azure:applicationinsights-core", version.ref = "application-insights" } archunitJunit5 = { module = "com.tngtech.archunit:archunit-junit5", version.ref = "archunit" } asmForPlugins = { module = "org.ow2.asm:asm", version.ref = "asmForPlugins" } +aspectjrt = { module = "org.aspectj:aspectjrt", version.ref = "aspectjweaver" } aspectjweaver = { module = "org.aspectj:aspectjweaver", version.ref = "aspectjweaver" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" } @@ -232,3 +233,4 @@ plugin-bnd = "biz.aQute.bnd:biz.aQute.bnd.gradle:6.4.0" kotlin19 = { id = "org.jetbrains.kotlin.jvm", version = "1.9.23" } kotlin17 = { id = "org.jetbrains.kotlin.jvm", version = "1.7.22" } jcstress = { id = "io.github.reyerizo.gradle.jcstress", version = "0.8.15" } +aspectj = { id = 'io.freefair.aspectj.post-compile-weaving', version = '8.6' } diff --git a/micrometer-core/build.gradle b/micrometer-core/build.gradle index 71472d0bb2..4e18fb1e95 100644 --- a/micrometer-core/build.gradle +++ b/micrometer-core/build.gradle @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.kotlin19) + alias(libs.plugins.aspectj) id 'me.champeau.mrjar' version "0.1.1" } @@ -81,7 +82,8 @@ dependencies { } // Aspects - optionalApi 'org.aspectj:aspectjweaver' + optionalApi libs.aspectjrt + java11RuntimeOnly libs.aspectjrt // instrumentation options optionalApi 'io.dropwizard.metrics:metrics-core' // TODO move dropwizard out of core module? DropwizardMeterRegistry for e.g. JMX registry @@ -209,6 +211,8 @@ dependencies { testImplementation 'io.grpc:grpc-inprocess' testImplementation 'io.grpc:grpc-testing-proto' testImplementation 'com.squareup.retrofit2:retrofit' + + testImplementation 'org.aspectj:aspectjweaver' } task shenandoahTest(type: Test) { diff --git a/micrometer-core/src/main/java/io/micrometer/core/aop/CountedAspect.java b/micrometer-core/src/main/java/io/micrometer/core/aop/CountedAspect.java index d0682e98eb..39d3f47c19 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/aop/CountedAspect.java +++ b/micrometer-core/src/main/java/io/micrometer/core/aop/CountedAspect.java @@ -167,7 +167,7 @@ public CountedAspect(MeterRegistry registry, Function delegate = new AtomicReference<>(ObservationRegistry.NOOP); + + DelegatingObservationRegistry(ObservationRegistry delegate) { + setDelegate(delegate); + } + + void setDelegate(ObservationRegistry delegate) { + this.delegate.set(Objects.requireNonNull(delegate, "Delegate must not be null")); + } + + @Nullable + @Override + public Observation getCurrentObservation() { + return delegate.get().getCurrentObservation(); + } + + @Nullable + @Override + public Observation.Scope getCurrentObservationScope() { + return delegate.get().getCurrentObservationScope(); + } + + @Override + public void setCurrentObservationScope(@Nullable Observation.Scope current) { + delegate.get().setCurrentObservationScope(current); + } + + @Override + public ObservationConfig observationConfig() { + return delegate.get().observationConfig(); + } + + @Override + public boolean isNoop() { + return delegate.get().isNoop(); + } + + } + +} diff --git a/micrometer-observation/src/main/java/io/micrometer/observation/aop/ObservedAspect.java b/micrometer-observation/src/main/java/io/micrometer/observation/aop/ObservedAspect.java index 8976077d67..18654aa0c7 100644 --- a/micrometer-observation/src/main/java/io/micrometer/observation/aop/ObservedAspect.java +++ b/micrometer-observation/src/main/java/io/micrometer/observation/aop/ObservedAspect.java @@ -19,6 +19,7 @@ import io.micrometer.common.lang.Nullable; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.Observations; import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.ObservationConvention; import org.aspectj.lang.ProceedingJoinPoint; @@ -84,6 +85,11 @@ public class ObservedAspect { private final Predicate shouldSkip; + // For Compile Time Weaving + public ObservedAspect() { + this(Observations.getGlobalRegistry(), null, DONT_SKIP_ANYTHING); + } + public ObservedAspect(ObservationRegistry registry) { this(registry, null, DONT_SKIP_ANYTHING); } @@ -105,7 +111,7 @@ public ObservedAspect(ObservationRegistry registry, this.shouldSkip = shouldSkip; } - @Around("@within(io.micrometer.observation.annotation.Observed) and not @annotation(io.micrometer.observation.annotation.Observed)") + @Around("@within(io.micrometer.observation.annotation.Observed) && !@annotation(io.micrometer.observation.annotation.Observed) && execution(* *.*(..))") @Nullable public Object observeClass(ProceedingJoinPoint pjp) throws Throwable { if (shouldSkip.test(pjp)) { diff --git a/micrometer-observation/src/test/java/io/micrometer/observation/aop/ObservedAspectTests.java b/micrometer-observation/src/test/java/io/micrometer/observation/aop/ObservedAspectTests.java index 262280107b..eb1f1ecd61 100644 --- a/micrometer-observation/src/test/java/io/micrometer/observation/aop/ObservedAspectTests.java +++ b/micrometer-observation/src/test/java/io/micrometer/observation/aop/ObservedAspectTests.java @@ -364,7 +364,8 @@ void skipPredicateShouldTakeEffectForClass() { void ignoreClassLevelAnnotationIfMethodLevelPresent() { registry.observationConfig().observationHandler(new ObservationTextPublisher()); - AspectJProxyFactory pf = new AspectJProxyFactory(new ObservedClassLevelAnnotatedService()); + ObservedClassLevelAnnotatedService annotatedService = new ObservedClassLevelAnnotatedService(); + AspectJProxyFactory pf = new AspectJProxyFactory(annotatedService); pf.addAspect(new ObservedAspect(registry)); ObservedClassLevelAnnotatedService service = pf.getProxy(); diff --git a/settings.gradle b/settings.gradle index 1f4a3ecaa0..03ba8db956 100644 --- a/settings.gradle +++ b/settings.gradle @@ -31,7 +31,7 @@ include 'micrometer-commons', 'micrometer-core', 'micrometer-observation' project(":micrometer-samples-$sample").projectDir = new File(rootProject.projectDir, "samples/micrometer-samples-$sample") } -include 'micrometer-test', 'micrometer-observation-test' +include 'micrometer-test', 'micrometer-observation-test', 'micrometer-test-aspectj-ltw', 'micrometer-test-aspectj-ctw' ['atlas', 'prometheus', 'prometheus-simpleclient', 'datadog', 'elastic', 'ganglia', 'graphite', 'health', 'jmx', 'influx', 'otlp', 'statsd', 'new-relic', 'cloudwatch2', 'signalfx', 'wavefront', 'dynatrace', 'azure-monitor', 'humio', 'appoptics', 'kairos', 'stackdriver', 'opentsdb'].each { sys -> include "micrometer-registry-$sys" diff --git a/tests/micrometer-test-aspectj-ctw/build.gradle b/tests/micrometer-test-aspectj-ctw/build.gradle new file mode 100644 index 0000000000..62facd4f57 --- /dev/null +++ b/tests/micrometer-test-aspectj-ctw/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' + alias(libs.plugins.aspectj) +} + +description 'AspectJ compile-time weaving test for Micrometer aspects' + +dependencies { + implementation project(':micrometer-core') + aspect project(':micrometer-core') + aspect project(':micrometer-observation') + + testImplementation libs.junitJupiter + testImplementation libs.assertj +} + +test { + useJUnitPlatform() +} diff --git a/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/MeasuredClass.java b/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/MeasuredClass.java new file mode 100644 index 0000000000..aaf5fb0b29 --- /dev/null +++ b/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/MeasuredClass.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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.test.ctw; + +import io.micrometer.core.annotation.Counted; +import io.micrometer.core.annotation.Timed; +import io.micrometer.observation.annotation.Observed; + +@Observed +@Counted +@Timed +public class MeasuredClass { + + @Timed + public void timedMethod() { + } + + @Counted + public void countedMethod() { + } + + @Observed + public void observedMethod() { + } + + public void classLevelTimedMethod() { + } + + public void classLevelCountedMethod() { + } + + public void classLevelObservedMethod() { + } + +} diff --git a/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/package-info.java b/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/package-info.java new file mode 100644 index 0000000000..4aa89e5f1d --- /dev/null +++ b/tests/micrometer-test-aspectj-ctw/src/main/java/io/micrometer/test/ctw/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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. + */ +@NonNullApi +@NonNullFields +package io.micrometer.test.ctw; + +import io.micrometer.common.lang.NonNullApi; +import io.micrometer.common.lang.NonNullFields; diff --git a/tests/micrometer-test-aspectj-ctw/src/test/java/io/micrometer/test/ctw/MeasuredClassTest.java b/tests/micrometer-test-aspectj-ctw/src/test/java/io/micrometer/test/ctw/MeasuredClassTest.java new file mode 100644 index 0000000000..f5897d92b7 --- /dev/null +++ b/tests/micrometer-test-aspectj-ctw/src/test/java/io/micrometer/test/ctw/MeasuredClassTest.java @@ -0,0 +1,171 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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.test.ctw; + +import io.micrometer.core.aop.TimedAspect; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.Observations; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collection; + +import static org.assertj.core.api.BDDAssertions.then; + +class MeasuredClassTest { + + MeterRegistry registry = new SimpleMeterRegistry(); + + ObservationRegistry observationRegistry = ObservationRegistry.create(); + + MeasuredClass measured = new MeasuredClass(); + + @BeforeEach + void setUp() { + observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(registry)); + // Global registry must be used because aspect gets created for us + Metrics.addRegistry(registry); + Observations.setRegistry(observationRegistry); + } + + @AfterEach + void cleanUp() { + Metrics.removeRegistry(registry); + Observations.resetRegistry(); + } + + @Test + void shouldWrapMethodWithTimedAspectThroughCTW() { + // when + measured.timedMethod(); + // then + Collection timers = registry.find(TimedAspect.DEFAULT_METRIC_NAME) + .tag("class", MeasuredClass.class.getName()) + .tag("method", "timedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.timedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithCountedAspectThroughCTW() { + // when + measured.countedMethod(); + // then + Collection counters = registry.find("method.counted") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "countedMethod") + .counters(); + then(counters).hasSize(1); + Counter counter = counters.iterator().next(); + then(counter.count()).isEqualTo(1); + + // when + measured.countedMethod(); + // then + then(counter.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithObservedAspectThroughCTW() { + // when + measured.observedMethod(); + // then + Collection timers = registry.find("method.observed") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "observedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.observedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelTimedAspectThroughCTW() { + // when + measured.classLevelTimedMethod(); + // then + Collection timers = registry.find(TimedAspect.DEFAULT_METRIC_NAME) + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelTimedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.classLevelTimedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelCountedAspectThroughCTW() { + // when + measured.classLevelCountedMethod(); + // then + Collection counters = registry.find("method.counted") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelCountedMethod") + .counters(); + then(counters).hasSize(1); + Counter counter = counters.iterator().next(); + then(counter.count()).isEqualTo(1); + + // when + measured.classLevelCountedMethod(); + // then + then(counter.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelObservedAspectThroughCTW() { + // when + measured.classLevelObservedMethod(); + // then + Collection timers = registry.find("method.observed") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelObservedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.classLevelObservedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + +} diff --git a/tests/micrometer-test-aspectj-ctw/src/test/resources/logback.xml b/tests/micrometer-test-aspectj-ctw/src/test/resources/logback.xml new file mode 100644 index 0000000000..9240fdf2fb --- /dev/null +++ b/tests/micrometer-test-aspectj-ctw/src/test/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/tests/micrometer-test-aspectj-ltw/build.gradle b/tests/micrometer-test-aspectj-ltw/build.gradle new file mode 100644 index 0000000000..57ad0df217 --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' +} + +description 'AspectJ load-time weaving test for Micrometer aspects' + +configurations { + agents +} + +dependencies { + agents libs.aspectjweaver + implementation project(':micrometer-core') + implementation project(':micrometer-observation') + + testImplementation libs.junitJupiter + testImplementation libs.assertj +} + +test { + useJUnitPlatform() + jvmArgs '-javaagent:' + configurations.agents.files.find { it.name.startsWith('aspectjweaver') } +} diff --git a/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/MeasuredClass.java b/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/MeasuredClass.java new file mode 100644 index 0000000000..28543dd215 --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/MeasuredClass.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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.test.ltw; + +import io.micrometer.core.annotation.Counted; +import io.micrometer.core.annotation.Timed; +import io.micrometer.observation.annotation.Observed; + +@Observed +@Counted +@Timed +public class MeasuredClass { + + @Timed + public void timedMethod() { + } + + @Counted + public void countedMethod() { + } + + @Observed + public void observedMethod() { + } + + public void classLevelTimedMethod() { + } + + public void classLevelCountedMethod() { + } + + public void classLevelObservedMethod() { + } + +} diff --git a/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/package-info.java b/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/package-info.java new file mode 100644 index 0000000000..9be98388a7 --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/src/main/java/io/micrometer/test/ltw/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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. + */ +@NonNullApi +@NonNullFields +package io.micrometer.test.ltw; + +import io.micrometer.common.lang.NonNullApi; +import io.micrometer.common.lang.NonNullFields; diff --git a/tests/micrometer-test-aspectj-ltw/src/main/resources/META-INF/aop.xml b/tests/micrometer-test-aspectj-ltw/src/main/resources/META-INF/aop.xml new file mode 100644 index 0000000000..4b2666819d --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/src/main/resources/META-INF/aop.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/tests/micrometer-test-aspectj-ltw/src/test/java/io/micrometer/test/ltw/MeasuredClassTest.java b/tests/micrometer-test-aspectj-ltw/src/test/java/io/micrometer/test/ltw/MeasuredClassTest.java new file mode 100644 index 0000000000..dfcdb703fe --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/src/test/java/io/micrometer/test/ltw/MeasuredClassTest.java @@ -0,0 +1,171 @@ +/* + * Copyright 2024 VMware, Inc. + * + * 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.test.ltw; + +import io.micrometer.core.aop.TimedAspect; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.Observations; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collection; + +import static org.assertj.core.api.BDDAssertions.then; + +class MeasuredClassTest { + + MeterRegistry registry = new SimpleMeterRegistry(); + + ObservationRegistry observationRegistry = ObservationRegistry.create(); + + MeasuredClass measured = new MeasuredClass(); + + @BeforeEach + void setUp() { + observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(registry)); + // Global registry must be used because aspect gets created for us + Metrics.addRegistry(registry); + Observations.setRegistry(observationRegistry); + } + + @AfterEach + void cleanUp() { + Metrics.removeRegistry(registry); + Observations.resetRegistry(); + } + + @Test + void shouldWrapMethodWithTimedAspectThroughLTW() { + // when + measured.timedMethod(); + // then + Collection timers = registry.find(TimedAspect.DEFAULT_METRIC_NAME) + .tag("class", MeasuredClass.class.getName()) + .tag("method", "timedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.timedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithCountedAspectThroughLTW() { + // when + measured.countedMethod(); + // then + Collection counters = registry.find("method.counted") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "countedMethod") + .counters(); + then(counters).hasSize(1); + Counter counter = counters.iterator().next(); + then(counter.count()).isEqualTo(1); + + // when + measured.countedMethod(); + // then + then(counter.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithObservedAspectThroughLTW() { + // when + measured.observedMethod(); + // then + Collection timers = registry.find("method.observed") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "observedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.observedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelTimedAspectThroughLTW() { + // when + measured.classLevelTimedMethod(); + // then + Collection timers = registry.find(TimedAspect.DEFAULT_METRIC_NAME) + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelTimedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.classLevelTimedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelCountedAspectThroughLTW() { + // when + measured.classLevelCountedMethod(); + // then + Collection counters = registry.find("method.counted") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelCountedMethod") + .counters(); + then(counters).hasSize(1); + Counter counter = counters.iterator().next(); + then(counter.count()).isEqualTo(1); + + // when + measured.classLevelCountedMethod(); + // then + then(counter.count()).isEqualTo(2); + } + + @Test + void shouldWrapMethodWithClassLevelObservedAspectThroughLTW() { + // when + measured.classLevelObservedMethod(); + // then + Collection timers = registry.find("method.observed") + .tag("class", MeasuredClass.class.getName()) + .tag("method", "classLevelObservedMethod") + .timers(); + then(timers).hasSize(1); + Timer timer = timers.iterator().next(); + then(timer.count()).isEqualTo(1); + + // when + measured.classLevelObservedMethod(); + // then + then(timer.count()).isEqualTo(2); + } + +} diff --git a/tests/micrometer-test-aspectj-ltw/src/test/resources/logback.xml b/tests/micrometer-test-aspectj-ltw/src/test/resources/logback.xml new file mode 100644 index 0000000000..9240fdf2fb --- /dev/null +++ b/tests/micrometer-test-aspectj-ltw/src/test/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + +