-
Notifications
You must be signed in to change notification settings - Fork 962
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 weaving support for TimedAspect #1149
Comments
Have you added aspectj weaving to the build section of your POM?
|
Yes. The aspectj-maven-plugin configuration I posted in my initial post is under |
My current hypothesis is that the |
Also, one way to work around this is to write your own aspect that weaves around an annotation and use the |
I don't have much expertise on AspectJ but after some quick research, it seems to require a similar configuration to |
Looks like spring-aspects.jar compiles with ajc, then. I think the solution to this ticket is to either compile Micrometer with ajc, or improve the documentation on how to get Micrometer to work properly with AspectJ. I can write a small addition to the documentation explaining this, if desired. |
I am running into the exact same issue as @jefftap. While the compile time weaving seems to succeed, at runtime the aspectOf methods are not there on the
Would be great to have some documentation on how to get this working. |
Methods annotated with @timed now use Micrometers annotation. The @Gauge annotation has been remove without replacement for now. While configuration for the use of Micrometer's TimedAspect has been prepared, it is not yet active because of compatibility issues with compile-time weaving. See micrometer-metrics/micrometer#1149.
I didn't manage to get this working with CTW. As far as I understood it, it seems that micrometer-core is not compiled with the ajc and thus the aspects are missing the required factory methods. |
The issue still persist. As noted higher it could be resolved by using LTW, but in my case it is not an option because I do not have access to the deployment setup, and the only option is CTW which doesn't work with this library |
Same issue here, CTW does not work. Is there any plan to support it properly, so CTW will work ? |
I've had the same issue with CTW, although I got around this by wrapping the aspect like this for now.
and adding the following to the aop.xml
It would be great if this works out of the box for CTW. |
Hi, for those on the interweb who came here for load time weaving (LTW), I confirm that it works. <aspectj>
<weaver>
<include within="io.micrometer.core..*"/>
<include within="my.app..*"/>
</weaver>
<aspects>
<aspect name="io.micrometer.core.aop.TimedAspect"/>
</aspects>
</aspectj> To be used in conjunction with a class like: package my.app;
public class App {
@Timed("xyz")
public void fun1() { }
} In a Spring Boot application with the I'm a newbie when it comes to aspects, but I'm wondering what the advantages of CTW over LTW are. |
Because I often answer questions on StackOverflow, I found this issue, not for the first time in the last few years. Today I took some time to look into it, producing a little example project, showing how to apply https://github.com/kriegaex/SO_AJ_MicrometerTimed_67803726 The project simply consists of one class and a POM + an explanatory read-me file. The gist of it is: You must make sure to apply binary weaving to the Micrometer aspect in order to transform it into a real AspectJ aspect, and then apply that aspect to your own project. |
Since there are ways of how to achieve this is there anything else we should do here, other than maybe document this? |
My workaround is very contrived. IMO, it is unreasonable to assume that any normal user who does not happen to be an AspectJ expert can find out how to do this. Even if it was documented, users would be doing the Micrometer team's work there.
Yes, add an AspectJ compilation step to the Gradle build (e.g. using Freefair plugin) and make sure that what is advertised as an AspectJ aspect, ... micrometer/micrometer-core/src/main/java/io/micrometer/core/aop/TimedAspect.java Lines 36 to 37 in 2252347
... actually really does deserve its name, and avoid that incomplete non-AspectJ compilation with Javac needs to be finished by the user. That this happens to work with LTW, because the AspectJ weaver is smart enough to notice and finish the job, does not mean that CTW is some kind of second-class citizen. Make your product easy to use. The correctly compiled aspect would, of course, still work with LTW. With CTW, the library could just be put on the aspectpath, as is customary. No extra build steps or extra modules, creating a refined version of this library as an input for later steps. Of course, micrometer/micrometer-core/build.gradle Lines 80 to 81 in 2252347
which is a superset of |
I am trying to migrate my project from Dropwizard Metrics to Micrometer and I'm blocked on this issue as I am trying to use compile-time weaving just like with Dropwizard annotations before and it doesn't seem to work with Micrometer despite the documentation saying it can be used also with compile time weaving. I have a Gradle project and was trying to convert the above mentioned workaround from Maven to Gradle, but the plugins are different and am running into various build failures. I tried to revert to Spring AOP proxies, but that doesn't work on my project, CGLIB breaking some of the classes. Are there any updates on the fix? Or did anyone make it work with Gradle (Freefair plugin)? (Update: Fixed it by configuring AspectJ load-time weaving, seems to be working alongside CTW for other classes) |
@marcingrzejszczak, see, this is what I mean. It is possible to finish the job unfinished by Micrometer manually as a user, but it is not trivial. Instead of burdening users, trying to figure out how to use your aspect, because you think it is unnecessary to compile it with the AspectJ compiler, you should finally get this issue off the table. Or are you expecting me to convert my Maven solution to Gradle on behalf of @mihalyr-prospect? |
@kriegaex I don't think that your answer is nice or brings any value to this discussion. We will take care of this issue whenever we have bandwith to do so. |
@marcingrzejszczak: I wanted to be clear rather than nice. I was not super nice, maybe, but also not non-nice. I did not insult anyone. I simply want to push this forward. Honestly, this issue has been open for more than 5 years, and I do not really buy the bandwidth argument, because
The product I maintain, AspectJ, is a cornerstone of Micrometer, so please understand that I would rather like to see it fixed than feeling compelled to devise custom workarounds to various users for a few more years. |
@jhoeller, sorry for asking instead of digging into the source code, but I am neither involved in Spring nor Micrometer and a bit under time pressure today: Is that relaxed check something that could be backported to older Spring versions which still receive regular or occasional updates? |
That's a good questions, because the Micrometer build seems to be using Spring 5.x too for some JDK11 compatibility perhaps.
|
If there is a concrete need for upcoming Micrometer releases, we can consider backporting this to 6.0.20 and 5.3.35. It is not entirely trivial though since it involves some potential issues for mixed AspectJ usage (using different @marcingrzejszczak please advise how concrete the need for a backport is here. |
I quickly checked the new Spring 6.1.7 snapshot on my branch, bumped compatibility to Java 17 and tests worked for Spring AOP, AspectJ LTW and CTW too. This looks like a good direction, just need to solve the compatibility issue in some way. |
Thanks for the immediate check, @mihalyr! The present arrangement in 6.1.7 is good to go, there's just the question of the backports... mostly a concern with unexpected side effects in niche scenarios where we currently limit the problem to 6.1.x, unless we have a scenario where this has to work in older branches as well. |
We still maintain micrometer 1.11.x and 1.12.x which both are using Spring 5.3.x. If we backported Spring Framework for this version then all of the OSS supported versions would be fixed |
So you intend to backport the ajc compilation step to Micrometer 1.11.x and 1.12.x as well, @marcingrzejszczak? I originally assumed that would only apply to the latest Micrometer feature branch... I guess it depends on whether you see this as an enhancement or a bug fix. |
Oh yeah, that's a good question. I wouldn't say it's a bug, I'd say that's a new feature. So we could stay with the current version and release this for Micrometer 1.14.0. I'll ping @shakuzen and @jonatan-ivanov to know what they think. |
I also think it is an improvement rather than a bug fix, but a very useful one. Is there a strict bugfix-only policy in Micrometer? |
Yeah we try to follow that rule as much as possible - features in new minors, bug fixes in patches |
OK, i.e. users who want to use Micrometer with AspectJ in a CTW scenario need to use the latest version and also upgrade to Spring 6 - or use my workaround. (No need to reply, unless I am wrong.) |
We can document the workaround for older versions and add this as a feature in 1.14 |
If somebody knows how to do in Gradle what I suggested for Maven, yeah. |
@kriegaex to make LTW/CTW work I had to make some changes to pointcuts - but I'm not that good with aspects in general, would it be possible for you to take a quick look? My changes are now in #5064 to be merged to Marcin's PR in #5059 One change I had to make was to make the pointcuts match only methods and not constructors because the implementation casted the signature to MethodSignature and getting a ConstructorSignature crashed it. This is the one for class-level annotations which should match all methods within an annotated class that are otherwise not annotated already and exclude constructors. - @Around("@within(io.micrometer.core.annotation.Counted) && !@annotation(io.micrometer.core.annotation.Counted)")
+ @Around("@within(io.micrometer.core.annotation.Counted) && !@annotation(io.micrometer.core.annotation.Counted) && execution(* *(..))") The other issue was with a method pointcut for which I changed the aspect method signature to make it work, but this breaks some binary compatibility checks in the project, so would be perhaps easier if we could find a fix without the method signature change if possible. Here is my change currently which works with LTW/CTW and Spring AOP too: - @Around(value = "@annotation(counted)", argNames = "pjp,counted")
+ @Around("execution (@io.micrometer.core.annotation.Counted * *.*(..))")
@Nullable
- public Object interceptAndRecord(ProceedingJoinPoint pjp, Counted counted) throws Throwable {
+ public Object interceptAndRecord(ProceedingJoinPoint pjp) throws Throwable { Please let me know if there is a better way to do this. |
@mihalyr, maybe we should talk (not write) one of these days, because the back-and-forth might get tedious. I need to learn more about your usage scenarios before being able to answer. For instance, I do not understand why you would need to change anything in your pointcuts for CTW in the first place. The only reason would be that that it was broken before for LTW, too, which is unrelated to this issue here. But of course, it should be fixed anyway if it is broken. |
This comment was marked as resolved.
This comment was marked as resolved.
Exactly, it was broken for LTW too. The annotations could be added for a whole class and for separate methods. If it is on a class, it would instrument all methods (that are otherwise not annotated with the same annotation). But this class level annotation was broken because of the After all this I noticed that I get double counts using Counted used: While Timed used: So I changed Counted also to So right now with these pointcut changes everything seems to be working, AspectJ with CTW or LTW and also Spring AOP (with 6.1.7-SNAPSHOT and JDK17). I'm not really involved with Micrometer project though, I just wanted to use this library the first time ever and naturally went for CTW which didn't work and ended up here, found a little free time to help out, but don't know much about why things were written in a certain way or what other goals are here. For that I think Marcin is the person to ask. |
Thanks for the clarification. I recommend a more readable change like this instead as a minimal and clean change compared to the main branch: @Around(value = "@annotation(counted) && execution(* *(..))", argNames = "pjp,counted") I find that more readable, and it is a simple and mechanical thing to do to just add |
BTW, I tested a manually Ajc-compiled aspect in my old Spring AOP playground project with Spring 5.3.16 in the debugger, setting a breakpoint inside |
Another hint, just in case you happen to be using or be planning to use pointcuts with something like Probably, this is not a problem at the moment, otherwise I guess you would be running into test problems already. Just a caveat for the future... |
Thank you Alexander, super useful information and the simpler syntax would solve binary compatibility issue I have also.
I can't comment on this part as it was @jhoeller who made that change in Spring, but I also assume it was something like that. |
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 micrometer-metrics#1149 (comment)
* 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>
@kriegaex we're building micrometer with jdk11. Can we fix the AspectJ compiler to 1.9.20.1? |
@marcingrzejszczak, yes, if you do not mind missing compiler enhancements and bugfixes. Would it be a big deal to build on JDK 17+ instead? JDKs 17 and 21 are LTS. |
We would have to discuss this internally @shakuzen @jonatan-ivanov |
* 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>
Ok, #5059 is ready for review. Let's try to close this 5 year old issue ;) |
* 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>
Hi, I am attempting to make use of
TimedAspect
via AspectJ compile-time weaving using theaspectj-maven-plugin
. When the aspect code is executed, it throws one of the two errors, depending on what is being executed:This usually indicates that the AspectJ weaver has not properly processed the aspect code. I am not sure if this is a problem with my own code/configuration, or if it's an issue in Micrometer's jar. The aspect works perfectly fine using Spring AOP, but I would prefer to use AspectJ weaving with
@Timed
to allow it access to private/protected methods and the other various benefits one gets from AspectJ integration.Relevant information:
aspectj-maven-plugin configuration:
The text was updated successfully, but these errors were encountered: