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 weaving support for TimedAspect #1149

Open
jefftap opened this issue Jan 11, 2019 · 15 comments
Open

Compile-time weaving support for TimedAspect #1149

jefftap opened this issue Jan 11, 2019 · 15 comments
Labels
Projects

Comments

@jefftap
Copy link

jefftap commented Jan 11, 2019

Hi, I am attempting to make use of TimedAspect via AspectJ compile-time weaving using the aspectj-maven-plugin. When the aspect code is executed, it throws one of the two errors, depending on what is being executed:

java.lang.NoSuchMethodError: io.micrometer.core.aop.TimedAspect.aspectOf()Lio/micrometer/core/aop/TimedAspect
java.lang.NoSuchMethodException: io.micrometer.core.aop.TimedAspect.aspectOf()

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:

  • micrometer-core version: 1.1.1
  • Spring Boot version: 2.1.1.RELEASE
  • AspectJ verison: 1.9.2
  • Java version: 1.8
  • aspectj-maven-plugin version: 1.11

aspectj-maven-plugin configuration:

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <configuration>
                    <complianceLevel>1.8</complianceLevel>
                    <source>1.8</source>
                    <target>1.8</target>
                    <showWeaveInfo>true</showWeaveInfo>
                    <Xlint>ignore</Xlint>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                        <aspectLibrary>
                            <groupId>io.micrometer</groupId>
                            <artifactId>micrometer-core</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
@jkschneider jkschneider added the question A user question, probably better suited for StackOverflow label Jan 12, 2019
@jkschneider
Copy link
Contributor

Have you added aspectj weaving to the build section of your POM?

<build>
<plugins>
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <executions>
      <execution>
        <goals>
          <goal>compile</goal> 
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>

@jefftap
Copy link
Author

jefftap commented Jan 14, 2019

Yes. The aspectj-maven-plugin configuration I posted in my initial post is under <build>/<plugins>.

@jefftap
Copy link
Author

jefftap commented Jan 17, 2019

My current hypothesis is that the build.gradle file needs the aspectj plugin applied to it. This should cause the Micrometer build to use ajc, which should process the aspect.

@jefftap
Copy link
Author

jefftap commented Jan 17, 2019

Also, one way to work around this is to write your own aspect that weaves around an annotation and use the Timer methods in there. It still needs to be coupled with Spring, though. Inject the MeterRegistry as a dependency. The bean should be declared in the Spring configuration using the Aspects.aspectOf method to pull in the AspectJ instance, and Spring handles the injection from there.

@izeye
Copy link
Contributor

izeye commented Feb 12, 2019

I don't have much expertise on AspectJ but after some quick research, it seems to require a similar configuration to spring-aspects to support compile-time weaving as already pointed out by @jefftap although I'm not sure there's any plan for compile-time weaving support.

@jefftap
Copy link
Author

jefftap commented Feb 12, 2019

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.

@ewencluley
Copy link

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 TimedAspect classes. The documentation for micrometer suggests the @Timed annotation should be supported using compile time aspectj weaving. (https://micrometer.io/docs/concepts#_the_code_timed_code_annotation)

use in your application either through compile/load time AspectJ weaving or through framework facilities that interpret AspectJ aspects

Would be great to have some documentation on how to get this working.

thm-deploy pushed a commit to particify/arsnova-server that referenced this issue Aug 4, 2019
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.
@Phil-Ba
Copy link

Phil-Ba commented Nov 14, 2019

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 only solution I found, was to do LTW and have the micrometer-core classes also be woven during load time.
Another solution would be the recompile the micrometer-core jar with the aspectj maven plugin, but this also requires all dependencies...

@Exidex
Copy link

Exidex commented Jun 18, 2020

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

@innovationhub-asia
Copy link

Same issue here, CTW does not work. Is there any plan to support it properly, so CTW will work ?

@venushka
Copy link

venushka commented Sep 13, 2020

I've had the same issue with CTW, although I got around this by wrapping the aspect like this for now.

@Aspect
public class MetricsAspect {
  @Around("execution (@io.micrometer.core.annotation.Timed * *.*(..))")
  public Object timedMethod(ProceedingJoinPoint pjp) throws Throwable {
    final TimedAspect timeAspect = new TimedAspect(MetricsServlet.getRegistry());
    return timeAspect.timedMethod(pjp);
  }
}

and adding the following to the aop.xml

<aspectj>
  <aspects>
    <aspect name="com.venushka.metrics.MetricsAspect"/>
  </aspects>
</aspectj>

It would be great if this works out of the box for CTW.

@shakuzen shakuzen added enhancement A general enhancement and removed question A user question, probably better suited for StackOverflow labels Sep 24, 2020
@shakuzen shakuzen added this to the 1.x milestone Sep 24, 2020
@shakuzen shakuzen changed the title java.lang.NoSuchMethodException: io.micrometer.core.aop.TimedAspect.aspectOf() Compile-time weaving support for TimedAspect Sep 24, 2020
@shakuzen shakuzen added this to To do in Aspect epic Mar 24, 2021
@dalbani
Copy link

dalbani commented May 15, 2021

Hi, for those on the interweb who came here for load time weaving (LTW), I confirm that it works.
That's my META-INF/aop.xml file:

<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 @EnableLoadTimeWeaving annotation.

I'm a newbie when it comes to aspects, but I'm wondering what the advantages of CTW over LTW are.
@Exidex: when you said that "you do not have access to the deployment setup", did you mean that you couldn't make sure that the JVM was configured with the appropriate agent?
I don't know if that would solve your problem, but I personally use https://github.com/invesdwin/invesdwin-instrument to have the application code register the agent by itself.

@kriegaex
Copy link

kriegaex commented Jun 5, 2021

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 TimedAspect via @Timed, using compile-time weaving with AspectJ Maven plugin. The same basic approach should also work with Gradlle, but I am a Maven guy.

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.

@marcingrzejszczak
Copy link
Contributor

Since there are ways of how to achieve this is there anything else we should do here, other than maybe document this?

@marcingrzejszczak marcingrzejszczak removed this from the 1.x milestone Dec 21, 2023
@marcingrzejszczak marcingrzejszczak added the waiting for feedback We need additional information before we can continue label Dec 21, 2023
@kriegaex
Copy link

kriegaex commented Dec 22, 2023

Since there are ways of how to achieve 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.

is there anything else we should do here, other than maybe document this?

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, ...

* AspectJ aspect for intercepting types or methods annotated with
* {@link Timed @Timed}.<br>

... does actually really 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, aspectjrt would become a dependency of this library, but in fact it already is anyway, because as-is, you need LTW and aspectjweaver,

// Aspects
optionalApi 'org.aspectj:aspectjweaver'

which is a superset of aspectjrt and actually more than the library really needs. The dependency should be downgraded to aspectjrt.

@shakuzen shakuzen added feedback-provided and removed waiting for feedback We need additional information before we can continue labels Dec 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

No branches or pull requests