I'm trying to automatically publish metrics to my MetricRegistry using annotations like @Timed (http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/package-summary.html).
This doesn't work out of the box. On searching for questions, I found Codahale Metrics: using @Timed metrics annotation in plain Java where it was mentioned that the only way for this to work would be by using aspectj. I added this to my project, but still do not see my metrics in my MetricRegistry.
This is my pom file. I added a librato library, which loads in com.codahale.metrics:metrics-annotation.
<dependency>
<groupId>io.astefanutti.metrics.aspectj</groupId>
<artifactId>metrics-aspectj</artifactId>
<version>${metrics-aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>1.8</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>true</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>io.astefanutti.metrics.aspectj</groupId>
<artifactId>metrics-aspectj</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<dependency>
<groupId>com.librato.metrics</groupId>
<artifactId>metrics-librato</artifactId>
<version>${metrics-librato.version}</version>
</dependency>
This is how I'm trying to use the metrics
@Metrics(registry = "default") // this.metricRegistry is default
public class Foo {
@Inject
private MetricRegistry metricRegistry;
...
@Metered(name = "meterName")
public void bar() {
Meter meter = metricRegistry.meter("manual");
meter.mark();
// this.metricRegistry does not contain "meterName" after the ConsoleReporter prints the metrics for "default"
// this.metricRegistry contains "manual" after the ConsoleReporter prints the metrics for "default"
}
I'm seeing this in my logs when I compile:
[INFO] Extending interface set for type 'Foo' (Foo.java) to include 'io.astefanutti.metrics.aspectj.Profiled' (MetricAspect.aj)
[INFO] Type 'Foo' (Foo.java) has intertyped field from 'io.astefanutti.metrics.aspectj.MetricAspect' (MetricAspect.aj:'java.util.Map<java.lang.String,io.astefanutti.metrics.aspectj.AnnotatedMetric<com.codahale.metrics.Gauge>> io.astefanutti.metrics.aspectj.Profiled.gauges')
[INFO] Type 'Foo' (Foo.java) has intertyped field from 'io.astefanutti.metrics.aspectj.MetricAspect' (MetricAspect.aj:'java.util.Map<java.lang.String,io.astefanutti.metrics.aspectj.AnnotatedMetric<com.codahale.metrics.Meter>> io.astefanutti.metrics.aspectj.Profiled.meters')
[INFO] Type 'Foo' (Foo.java) has intertyped field from 'io.astefanutti.metrics.aspectj.MetricAspect' (MetricAspect.aj:'java.util.Map<java.lang.String,io.astefanutti.metrics.aspectj.AnnotatedMetric<com.codahale.metrics.Timer>> io.astefanutti.metrics.aspectj.Profiled.timers')
[INFO] Join point 'staticinitialization(void Foo.<clinit>())' in Type 'Foo' (Foo.java:46) advised by after advice from 'io.astefanutti.metrics.aspectj.MetricStaticAspect' (metrics-aspectj-1.2.0.jar!MetricStaticAspect.class:41(from MetricStaticAspect.aj))
[INFO] Join point 'method-execution(void Foo.bar())' in Type 'Foo' (Foo.java:74) advised by around advice from 'io.astefanutti.metrics.aspectj.TimedAspect' (metrics-aspectj-1.2.0.jar!TimedAspect.class:26(from TimedAspect.aj))
[INFO] Join point 'method-execution(void Foo.bar())' in Type 'Foo' (Foo.java:74) advised by before advice from 'io.astefanutti.metrics.aspectj.MeteredAspect' (metrics-aspectj-1.2.0.jar!MeteredAspect.class:26(from MeteredAspect.aj))
It seems to indicate the annotated metrics I setup are working properly. However, I also see this in my logs too
[WARNING] advice defined in io.astefanutti.metrics.aspectj.TimedStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/TimedStaticAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredStaticAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.MeteredStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/MeteredStaticAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.TimedAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/TimedAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.TimedStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/TimedStaticAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.MetricAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/MetricAspect.class:45
[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.MeteredAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/MeteredAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredStaticAspect.class:26
[WARNING] advice defined in io.astefanutti.metrics.aspectj.MetricStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/MetricStaticAspect.class:41
[WARNING] advice defined in io.astefanutti.metrics.aspectj.MeteredStaticAspect has not been applied [Xlint:adviceDidNotMatch]
/Users/x/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/metrics-aspectj-1.2.0.jar!io/astefanutti/metrics/aspectj/MeteredStaticAspect.class:26
Here is my app setup
@Override
public void run(AppConfiguration configuration, Environment environment) {
ConsoleReporter reporter = ConsoleReporter.forRegistry(environment.metrics())
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(2, TimeUnit.MINUTES);
}
I just tried this out and it works well. Here is my entire setup:
pom.xml:
Note that I need to add the
aspectj-maven-plugin. I am also adding anassemblyplugin for testing later. This is not really necessary, I just didn't want to go hunting for dependencies on my local box.My timed class:
And the app:
What happens here is that while compiling the maven plugin for aspect will find the annotations you use and apply the aspects.
In your case (and mine) for example this one from the metrics-aspect source:
All the above does is to say:
Any method that is non static and has a
@Timedannotation should be executed within the "around" method.Now, you may compile and package that by doing:
mvn clean install packageThis will print a bunch of warning for non-applied aspects, but that is perfectly fine (we are not actually using them).
Further, you now have a fat-jar containing your application and you can execute it to see if what we did worked:
java -cp target/my-app-1.0-SNAPSHOT-jar-with-dependencies.jar com.mycompany.app.AppWhich will print:
Few points:
This does not work within Eclipse. You will have to install an extension to get that to work (I have not tried that), see here:
https://github.com/astefanutti/metrics-aspectj/blob/master/README.md
And for instructions on how to use AJDT:
https://www.ibm.com/developerworks/library/j-ajdt/
The reason is (vague because I have not spend too much time on this) that the aspects are applied at compile time, not at runtime. Eclipse uses its own compiler when run within the IDE, so it just executes your code. The maven plugin inside your pom file however is what applies the aspects when compiling your code.
I hope that helps,
P.S. forgive my naming/packaging - i used the default maven generator
-- Artur
Follow up:
To add your dropwizard metrics you can just add it to the shared one if you want to use the above solution. For example:
In your case, this would come from
environment().metrics()or similar.