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

Compile-time and load-time weaving support for aspects #5059

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

marcingrzejszczak
Copy link
Contributor

@marcingrzejszczak marcingrzejszczak commented May 9, 2024

Adds support for CTW (compile time weaving) and LTW (load time weaving) support

fixes #1149

@marcingrzejszczak marcingrzejszczak changed the title Compile-time weaving support for aspects Compile-time and load-time weaving support for aspects May 10, 2024
@mihalyr
Copy link
Contributor

mihalyr commented May 10, 2024

What would be the best way to merge this with my changes from #5060 and https://github.com/mihalyr/micrometer/tree/fix-aspectj-ctw ?

There are a few things I noticed missing from this PR:

I have all this addressed in #5060 and added also CTW in https://github.com/mihalyr/micrometer/tree/fix-aspectj-ctw. I named the module slightly differently micrometer-test-aspectj-ltw and micrometer-test-aspectj-ctw, but that's just a small detail. We could either merge #5060 to main and I will send another PR for your branch with the missing tests for CTW. Or I can change #5060 to be merged into your branch. But I would prefer merging #5060 to main first since that way your change would be more focused and limited to one issue at a time without the pointcut problems fixed in my PR.

But I didn't address the @Observed with the global ObservationRegistry, so that would need to be added for the LTW part too, which I can address in a PR also for your branch.

There is a thread-safety issue with the new Observations class that should be addressed too.

@marcingrzejszczak
Copy link
Contributor Author

I think we can do everything in this PR. So please create a PR to the issues_#1149_ctw branch so that I can merge your changes.

@mihalyr
Copy link
Contributor

mihalyr commented May 10, 2024

Ok, no problem, just wanted to point out that my change in #5060 is a bugfix for the broken pointcut with AspectJ load-time weaving rather an enhancement as the compile-time weaving is.

@marcingrzejszczak
Copy link
Contributor Author

I understand. Regardless, let's go with everything in that PR. I'll merge it to my branch and then will refine the branch.

@mihalyr
Copy link
Contributor

mihalyr commented May 10, 2024

@marcingrzejszczak here we go #5064

This works for me locally the only issue is that Spring aspect check that we know about - it should work with JDK17 and Spring 6.1.7-SNAPSHOT. And of course the japicmp that was mentioned in my other PR. UPDATE: The japicmp issue was fixed in the latest version.

build.gradle Outdated
@@ -408,6 +408,11 @@ subprojects {
description = 'Application monitoring instrumentation facade'

repositories {
// mavenLocal()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: To be removed when 5.3.35 is out

@@ -3,7 +3,7 @@ activemq-artemis = "2.33.0"
application-insights = "2.6.4"
archunit = "1.3.0"
asmForPlugins = "7.3.1"
aspectjweaver = "1.9.22.1"
aspectjweaver = "1.9.20.1"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -75,7 +75,7 @@ rest-assured = "5.4.0"
signalfx = "1.0.41"
slf4j = "1.7.36"
spectator-atlas = "1.7.12"
spring = "5.3.34"
spring = "5.3.35-SNAPSHOT"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to 5.3.35 when released

Copy link
Contributor

@mihalyr mihalyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Looks good, just minor comments.

micrometer-observation/build.gradle Outdated Show resolved Hide resolved
micrometer-observation/build.gradle Outdated Show resolved Hide resolved
Comment on lines 30 to 33
<aspects>
<!-- These are the two aspects we want to switch on for now. -->
<aspect name="io.micrometer.observation.aop.ObservedAspect"/>
</aspects>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this aop.xml file is being used, it should be only needed for LTW with AspectJ which is tested in the micrometer-test-aspectj-ltw module.

marcingrzejszczak and others added 10 commits May 20, 2024 11:44
* Revert "Fix AspectJ pointcut syntax (#5058)"

This reverts commit 5e16809.

* Fix AspectJ load-time weaving and class-level annotations

Fix AspectJ pointcut syntax to use `&& !` instead `and not` which is
invalid for the AspectJ compiler/weaver and only works with the Spring
AOP implementation. Also add `&& execution(* *.*(..))` to match only
methods, because the implementation assumes it gets only
MethodSignatures and crashes on ConstructorSignature at runtime.

Fixed the thread-safety and mutability issues with the singleton
Observations class, so changes are propagated to aspects that are
initialized only once.

Added AspectJ load-time weaving tests to make sure that the further
issues with pointcuts and aspects are noticed at build time.

* Add more AspectJ compile-time tests

Added more class-level annotation tests and moved the module to
'micrometer-test-aspectj-ctw' to align with
'micrometer-test-aspectj-ltw'.

* Revert CountedAspect method change with simpler syntax

A fix kindly provided by @kriegaex that avoids changing the method
signature and thus breaking binary compatibility and still fixes the
problem with double counting in AspectJ.

See the explanation in
#1149 (comment)

---------

Co-authored-by: Marcin Grzejszczak <marcin@grzejszczak.pl>
Co-authored-by: Robert Mihaly <rob@mihalyr.com>
Co-authored-by: Robert Mihaly <rob@mihalyr.com>
@@ -81,6 +82,8 @@ dependencies {
}

// Aspects
implementation libs.aspectjrt
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to add a transitive dependency for micrometer-core users (same for micrometer-observation). When/how is this dependency used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good catch, @mihalyr @kriegaex can you try to shed more light on this?

@kriegaex
Copy link

kriegaex commented May 21, 2024

This is a known fact, and of course it is a dependency. I already explained long ago in #1149 (comment). Using annotations like @Aspect, @Before or classes like JoinPoint are from aspectjrt, so of course it is a dependency. So far, so obvious. Instead, you can remove the aspectjweaver dependency, because the latter is a significantly bigger superset of AspectJ runtime + LTW classes.

Why would you want to avoid the dependency? It is like e.g. using Log4J and trying to avoid declaring a dependency on the library. IMO, it does make a lot of sense to have this dependency. You always had it, both for Spring AOP and AspectJ. If you did not advertise it to users before, it was wrong to begin with and a bug.

Edit: In Maven, there is the concept of an optional dependency. If not all Micrometer users need Spring AOP or AspectJ aspects - I have no idea how to use Micrometer, not being an active user - maybe you can declare it as optional, if Gradle supports that. But I guess anyone using the aspect-driven Micrometer annotations absolutely needs the dependency. How else are the aspects supposed to work?

@marcingrzejszczak
Copy link
Contributor Author

Yeah so that being optional would be the way to go. E.g. in Spring users need to explicitly say that they want aspect support by adding spring-boot-starter-aop dependency

@kriegaex
Copy link

kriegaex commented May 21, 2024

Maybe in the future, you can split the library and create something like a micrometer-aspects library which has an explicit aspectjrt dependency. I believe that the whole concept of optional dependencies is error-prone, burdening users with adding information to the build configuration which the library should take care of. Then, you have a clear opt-in situation, which is also easier to document and clearly expressed in users' build configurations.

@marcingrzejszczak
Copy link
Contributor Author

This commit makes the aspectj deps optional

@mihalyr
Copy link
Contributor

mihalyr commented May 21, 2024

I mentioned this also previously in #1149 (comment)

I also had to include aspectjrt as an implementation (compile-time) dependency, I think previously aspectjweaver was an optional dep (because you decided if you want to weave or not during load time, but it seems to be needed for CTW at build-time, I wonder if we could get away with compileOnly dep for this and users can include the runtime if they use weaving).

But for some reason my build failed when I only used it as an optional as it seemed CTW required the dependency during the build, not sure how does it work with the latest change, but I'm happy with it 😄

java11Implementation libs.aspectjrt
optionalApi 'org.aspectj:aspectjweaver'
optionalApi libs.aspectjrt
java11RuntimeOnly libs.aspectjrt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still adds this as a transient dependency for the Java 11 build, is that OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the closest I could get to optional for java11. I'm not an expert with Gradle 😢 cc @jonatan-ivanov

Copy link
Contributor

@mihalyr mihalyr May 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also not an expert with Gradle and don't know much about the project setup, just caught my 👁️ on the "runtime", but I made a little test with Java 11 locally and I don't see aspecjrt included, so it might be OK

runtimeClasspath - Runtime classpath of source set 'main'.
+--- io.micrometer:micrometer-java11:1.14.0-SNAPSHOT
|    \--- io.micrometer:micrometer-core:1.14.0-SNAPSHOT
|         +--- io.micrometer:micrometer-commons:1.14.0-SNAPSHOT
|         +--- io.micrometer:micrometer-observation:1.14.0-SNAPSHOT
|         |    \--- io.micrometer:micrometer-commons:1.14.0-SNAPSHOT
|         +--- org.hdrhistogram:HdrHistogram:2.2.1
|         \--- org.latencyutils:LatencyUtils:2.0.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compile-time weaving support for TimedAspect
4 participants