{"id":18848728,"url":"https://github.com/astefanutti/metrics-aspectj","last_synced_at":"2025-04-14T08:42:02.824Z","repository":{"id":57731436,"uuid":"12847265","full_name":"astefanutti/metrics-aspectj","owner":"astefanutti","description":"AspectJ integration for Dropwizard Metrics","archived":false,"fork":false,"pushed_at":"2020-10-13T07:12:29.000Z","size":366,"stargazers_count":82,"open_issues_count":3,"forks_count":40,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-27T22:13:06.581Z","etag":null,"topics":["aop","aspectj","dropwizard","java","metrics"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/astefanutti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-09-15T15:05:58.000Z","updated_at":"2024-12-31T03:01:03.000Z","dependencies_parsed_at":"2022-09-07T19:40:16.771Z","dependency_job_id":null,"html_url":"https://github.com/astefanutti/metrics-aspectj","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astefanutti%2Fmetrics-aspectj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astefanutti%2Fmetrics-aspectj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astefanutti%2Fmetrics-aspectj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astefanutti%2Fmetrics-aspectj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astefanutti","download_url":"https://codeload.github.com/astefanutti/metrics-aspectj/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248849261,"owners_count":21171550,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aop","aspectj","dropwizard","java","metrics"],"created_at":"2024-11-08T03:16:58.702Z","updated_at":"2025-04-14T08:42:02.797Z","avatar_url":"https://github.com/astefanutti.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AspectJ for Metrics\n\n[![Build Status][Travis badge]][Travis build] [![Coverage Status][Coveralls badge]][Coveralls build] [![Maven Central][Maven Central badge]][Maven Central build]\n\n[Travis badge]: https://travis-ci.org/astefanutti/metrics-aspectj.svg?branch=master\n[Travis build]: https://travis-ci.org/astefanutti/metrics-aspectj\n[Coveralls badge]: https://coveralls.io/repos/astefanutti/metrics-aspectj/badge.svg\n[Coveralls build]: https://coveralls.io/github/astefanutti/metrics-aspectj\n[Maven Central badge]: http://img.shields.io/maven-central/v/io.astefanutti.metrics.aspectj/metrics-aspectj.svg\n[Maven Central build]: http://central.maven.org/maven2/io/astefanutti/metrics/aspectj/metrics-aspectj/1.2.0/\n\n[AspectJ][] integration for Dropwizard [Metrics][] with optional [Expression Language 3.0 (JSR-341)][] support.\n\n[AspectJ]: http://eclipse.org/aspectj/\n[Metrics]: http://metrics.codahale.com/\n[Expression Language 3.0 (JSR-341)]: http://jcp.org/en/jsr/detail?id=341\n\n## About\n\n_Metrics AspectJ_ provides support for the [_Metrics_ annotations][Metrics annotations] in Java SE environments using _AspectJ_ to perform AOP instrumentation. It implements the contract specified by these annotations with the following level of functionality:\n+ Intercept invocations of instance and class methods annotated with [`@ExceptionMetered`][], [`@Metered`][] and [`@Timed`][],\n+ Create [`Gauge`][] metrics for instance and class methods annotated with [`@Gauge`][],\n+ Register / retrieve the [`Metric`][] instances in the resolved [`MetricRegistry`][] instance,\n+ Resolve the [`MetricRegistry`][] instance by looking up into the [`SharedMetricRegistries`][] class or optionally by dynamically evaluating EL expressions.\n\n_Metrics AspectJ_ is compatible with _Metrics_ version `3.0.0`+ and requires Java 6 or higher.\n\n[Metrics annotations]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/package-summary.html\n[`@ExceptionMetered`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/ExceptionMetered.html\n[`@Gauge`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/Gauge.html\n[`@Metered`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/Metered.html\n[`@Timed`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/annotation/Timed.html\n[`Gauge`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/Gauge.html\n[`Metric`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/Metric.html\n[`MetricRegistry`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/MetricRegistry.html\n[`SharedMetricRegistries`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/SharedMetricRegistries.html\n\n## Getting Started\n\n#### Using Maven\n\nAdd the `metrics-aspectj` library as a dependency:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.astefanutti.metrics.aspectj\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-aspectj\u003c/artifactId\u003e\n    \u003cversion\u003e1.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nAnd configure the `maven-aspectj-plugin` to compile-time weave (CTW) the `metrics-aspectj` aspects into your project:\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.codehaus.mojo\u003c/groupId\u003e\n    \u003cartifactId\u003easpectj-maven-plugin\u003c/artifactId\u003e\n    \u003cconfiguration\u003e\n        \u003caspectLibraries\u003e\n            \u003caspectLibrary\u003e\n                \u003cgroupId\u003eio.astefanutti.metrics.aspectj\u003c/groupId\u003e\n                \u003cartifactId\u003emetrics-aspectj\u003c/artifactId\u003e\n            \u003c/aspectLibrary\u003e\n        \u003c/aspectLibraries\u003e\n    \u003c/configuration\u003e\n    \u003cexecutions\u003e\n        \u003cexecution\u003e\n            \u003cgoals\u003e\n                \u003cgoal\u003ecompile\u003c/goal\u003e\n            \u003c/goals\u003e\n        \u003c/execution\u003e\n    \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\nMore information can be found in the [Maven AspectJ plugin][] documentation.\n\n[Maven AspectJ plugin]: http://mojo.codehaus.org/aspectj-maven-plugin/\n\n#### Using Ant\n\nUse the [AjcTask][] (`iajc`) Ant task:\n\n```xml\n\u003ctarget name=\"{target}\" \u003e\n    \u003ciajc sourceroots=\"${basedir}/src\"\n          classpath=\"${basedir}/lib/aspectjrt.jar\"\n          outjar=\"${basedir}/build/${ant.project.name}.jar\"\u003e\n        ...\n        \u003caspectpath\u003e\n            \u003cpathelement location=\"${basedir}/lib/metrics-aspectj.jar\"/\u003e\n        \u003c/aspectpath\u003e\n        ...\n    \u003c/iajc\u003e\n\u003c/target\u003e\n```\n\nOther options are detailed in the [AspectJ Ant tasks][] documentation.\n\n[AjcTask]: http://www.eclipse.org/aspectj/doc/next/devguide/antTasks-iajc.html\n[AspectJ Ant tasks]: http://www.eclipse.org/aspectj/doc/next/devguide/antTasks.html\n\n#### Using Gradle\n\n[gradle example]: https://github.com/paegun/metrics-aspectj-gradle-example\nA working [gradle example][] is available, but each integration point is described here.\n\n##### build.gradle snippets\n\n```groovy\nbuildscript {\n    // ensure the gradle-aspectj integration is w/i the build classpath\n    dependencies {\n        classpath 'nl.eveoh:gradle-aspectj:1.6'\n    }\n}\n\n// specify the aspectjVersion, used by gradle-aspectj\nproject.ext {\n    aspectjVersion = '1.8.10'\n}\n\n// specify the Dropwizard Metrics version (metricsVer)\n//  and the aspect-oriented metrics version (metricsAspectVer, this solution)\next {\n    metricsVer = '3.2.2'\n    metricsAspectVer = '1.2.0'\n}\n\n// via the gradle-aspectj integration, run \"aspect weaving\"\napply plugin: 'aspectj'\n\n// ensure Dropwizard Metrics as well as the aspect-oriented metrics (astefanutti.metrics.aspectj)\n//  runtime dependencies of your solution are satisfied.\ndependencies {\n    compile \"io.astefanutti.metrics.aspectj:metrics-aspectj:${metricsAspectVer}\"\n    // add a path for the gradle-aspectj \"aspect weaving\" (AspectJ Compiler compile)\n    aspectpath \"io.astefanutti.metrics.aspectj:metrics-aspectj:${metricsAspectVer}\"\n\n    compile \"io.dropwizard.metrics:metrics-core:${metricsVer}\"\n    compile \"io.dropwizard.metrics:metrics-annotation:${metricsVer}\"\n}\n```\n\n#### Using the AspectJ Compiler\n\nThe AspectJ compiler can be used directly by executing the following command:\n\n```\najc -aspectpath metrics-aspectj.jar [Options] [file...]\n```\n\nMore information can be found in the [AspectJ compiler / weaver][] documentation.\n\n[AspectJ compiler / weaver]: http://www.eclipse.org/aspectj/doc/next/devguide/ajc-ref.html\n\n#### Required Dependencies\n\nBesides depending on _Metrics_ (`metrics-core` and `metrics-annotation` modules), _Metrics AspectJ_ requires the AspectJ `aspectjrt` module:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.aspectj\u003c/groupId\u003e\n    \u003cartifactId\u003easpectjrt\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\nThese three modules are transitive dependencies of the `metrics-aspectj` Maven module.\n\nAlternatively, the `metrics-aspectj-deps` artifact that re-packages the `metrics-annotation` and the `aspectjrt` modules can be used so that the only required dependency is `metrics-core`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.astefanutti.metrics.aspectj\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-aspectj-deps\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\n#### Optional Dependencies\n\nIn addition to that, _Metrics AspectJ_ optional support of EL 3.0 expression for `MetricRegistry` resolution and `Metric` name evaluation requires an implementation of [Expression Language 3.0 (JSR-341)][] to be present at runtime. For example, the [`metrics-aspectj-el`][] module is using the [GlassFish reference implementation][] as `test` dependency for its unit tests execution:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.glassfish\u003c/groupId\u003e\n    \u003cartifactId\u003ejavax.el\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\n[`metrics-aspectj-el`]: https://github.com/astefanutti/metrics-aspectj/tree/master/envs/el\n[GlassFish reference implementation]: https://glassfish.java.net/downloads/ri/\n\n## Usage\n\n#### _Metrics AspectJ_ Activation\n\nIn order to activate _Metrics AspectJ_ for a particular class, it must be annotated with the `@Metrics` annotation:\n\n```java\nimport com.codahale.metrics.annotation.Timed;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics\nclass TimedMethod {\n\n    @Timed(name = \"timerName\")\n    void timedMethod() {} // Timer name =\u003e TimedMethod.timerName\n}\n```\n\nAt weaving time, _Metrics AspectJ_ will detect the `@Metrics` annotation, scan all the declared methods of the target class that are annotated with _Metrics_ annotations, then create and register the corresponding `Metric` instances and weave its aspects around these methods. At runtime, these `Metric` instances will eventually get called according to the _Metrics_ annotations specification.\n\nNote that _Metrics_ annotations won't be inherited if declared on an interface or a parent class method. More details are available in the [Limitations](#limitations) section.\n\n#### The _Metrics_ Annotations\n\n_Metrics_ comes with the [`metrics-annotation`][] module that contains a set of annotations and provides a standard way to integrate _Metrics_ with frameworks supporting Aspect Oriented Programming (AOP). These annotations are supported by _Metrics AspectJ_ that implements their contract as documented in their Javadoc.\n\n[`metrics-annotation`]: https://github.com/dropwizard/metrics/tree/master/metrics-annotation\n\nFor example, a method can be annotated with the `@Timed` annotation so that its execution can be monitored using _Metrics_:\n\n```java\nimport com.codahale.metrics.annotation.Timed;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics\nclass TimedMethod {\n\n    @Timed(name = \"timerName\")\n    void timedMethod() {} // Timer name =\u003e TimedMethod.timerName\n}\n```\n\nIn that example, _Metrics AspectJ_ will instrument all the constructors of the `TimedMethod` class by injecting Java bytecode that will automatically create a `Timer` instance with the provided `name` (or retrieve an existing `Timer` with the same `name` already registered in the `MetricRegistry`) right after the instantiation of the `TimedMethod` class and inline the method invocation around with the needed code to time the method execution using that `Timer` instance.\n\nA `static` method can also be annotated with the `@Timed` annotation so that its execution can be monitored using _Metrics_:\n\n```java\nimport com.codahale.metrics.annotation.Timed;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics\nclass TimedMethod {\n\n    @Timed(name = \"timerName\")\n    static void timedStaticMethod() {} // Timer name =\u003e TimedMethod.timerName\n}\n```\n\nIn that example, _Metrics AspectJ_ will instrument the `TimedMethod` class so that, when it's loaded, a `Timer` instance with the provided `name` will be created (or an existing `Timer` with the same `name` already registered in the `MetricRegistry` will be retrieved) and inline the method invocation around with the needed code to time the method execution using that `Timer` instance.\n\nOptionally, the `Metric` name can be resolved with an EL expression that evaluates to a `String`:\n\n```java\nimport com.codahale.metrics.annotation.Timed;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics\nclass TimedMethod {\n\n    private long id;\n\n    public long getId() {\n        return id;\n    }\n\n    @Timed(name = \"timerName ${this.id}\")\n    void timedMethod() {} // Timer name =\u003e TimedMethod.timerName \u003cid\u003e\n}\n```\n\nIn that example, _Metrics AspectJ_ will automatically create a `Timer` instance (respectively retrieve an existing `Timer` instance with the same `name` already registered in the `MetricRegistry`) right after the instantiation of the `TimedMethod` class and evaluate the EL expression based on the value of the `id` attribute of that newly created `TimedMethod` instance to name the `Timer` instance (respectively resolve the `Timer` instance registered in the `MetricRegistry`). If the value of the `id` attribute changes over time, the `name` of the `Timer` instance won't be re-evaluated.\n\nNote that these annotations won't be inherited if they are placed on interface or parent class methods. Indeed, according to the Java language specification, non-type annotations are not inherited. It is discussed in more details in the [Limitations](#limitations) section.\n\n#### _Metrics_ Registry Resolution\n\nThe `Metrics.registry` annotation attribute provides the way to declare the `MetricRegistry` to register the generated `Metric` instances into. Its value can either be a string literal that identifies a `MetricRegistry` accessible by name from the [`SharedMetricRegistries`][] class or a valid EL expression that evaluates to the registry name or the registry instance. The resultant `MetricRegistry` is used to register the `Metric` instantiated into each time a _Metrics_ annotation is present on that class methods. It defaults to the string literal `metrics-registry`.\n\nThe `MetricRegistry` can thus be resolved by name relying on the [`SharedMetricRegistries.getOrCreate(String name)`][] method:\n\n```java\nimport com.codahale.metrics.annotation.Metered;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics(registry = \"registryName\")\nclass MeteredMethodWithRegistryByName {\n\n    @Metered(name = \"meterName\")\n    void meteredMethod() {} // Registry =\u003e SharedMetricRegistries.getOrCreate(\"registryName\")\n}\n```\n\nOr with an EL expression that evaluates to a bean property of type `MetricRegistry`:\n\n```java\nimport com.codahale.metrics.MetricRegistry;\nimport com.codahale.metrics.annotation.Metered;\n\nimport io.astefanutti.metrics.aspectj.Metrics;\n\n@Metrics(registry = \"${this.registry}\")\nclass MeteredMethodWithRegistryFromProperty {\n\n    final MetricRegistry registry;\n\n    MeteredMethodWithRegistryFromProperty(MetricRegistry registry) {\n        this.registry = registry;\n    }\n\n    MetricRegistry getRegistry() {\n        return registry;\n    }\n\n    @Metered(name = \"meterName\")\n    void meteredMethod() {} // Registry =\u003e this.getRegistry()\n}\n```\n\nOr with an EL expression that evaluates to a `String`. In that case the registry is resolved by name using the [`SharedMetricRegistries.getOrCreate(String name)`][] method.\n\n[`SharedMetricRegistries.getOrCreate(String name)`]: http://metrics.dropwizard.io/3.1.0/apidocs/com/codahale/metrics/SharedMetricRegistries.html#getOrCreate%28java.lang.String%29\n\n## Limitations\n\nThe _Metrics_ annotations are not inherited whether these are declared on a parent class or an implemented interface method. The root causes of that limitation, according to the Java language specification, are:\n+ Non-type annotations are not inherited,\n+ Annotations on types are only inherited if they have the `@Inherited` meta-annotation,\n+ Annotations on interfaces are not inherited irrespective to having the `@Inherited` meta-annotation.\n\nSee the [`@Inherited`][] Javadoc and [Annotation types][] from the Java language specification for more details.\n\nAspectJ follows the Java language specification and has documented to what extent it's impacted in [Annotation inheritance][] and [Annotation inheritance and pointcut matching][]. There would have been ways of working around that though:\n+ That would have been working around the Java language specification in the first place,\n+ Plus that would have required to rely on a combination of [Expression-based pointcuts][], [Runtime type matching][] and [Reflective access][] to define conditional pointcut expressions which:\n    + Would have widen the scope of matching joint points thus introducing side-effects in addition to being inefficient,\n    + Would have been evaluated at runtime for each candidate join point relying on the Java Reflection API thus impacting the application performance and incidentally voiding the non-intrusive benefit of AOP in a larger sense.\n\n[`@Inherited`]: http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/Inherited.html\n[Annotation types]: http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.6\n[Annotation inheritance]: http://eclipse.org/aspectj/doc/next/adk15notebook/printable.html#annotation-inheritance\n[Annotation inheritance and pointcut matching]: http://eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html#annotation-inheritance-and-pointcut-matching\n[Expression-based pointcuts]: http://eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html#d0e5549\n[Runtime type matching]: http://eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html#runtime-type-matching-and-context-exposure\n[Reflective access]: http://eclipse.org/aspectj/doc/released/progguide/semantics-advice.html#reflective-access-to-the-join-point\n\n## Spring AOP vs. AspectJ\n\n[Spring AOP][] and [AspectJ][] provides Aspect Oriented Programming (AOP) in two very different ways:\n+ AspectJ provides a full-fledged aspect definition and support both Compile Time Weaving (CTW) and Load Time Weaving (LTW) (with a Java agent) and implements AOP with class instrumentation (byte code manipulation),\n+ Spring AOP does not support the whole AspectJ aspect definition and does not support Compile Time Weaving,\n+ Spring AOP implements AOP either using (see [Spring proxying mechanisms][]):\n    + JDK dynamic proxies, which add little runtime overhead, clutter stack traces and can be incompatible with other Spring functionality like Spring JMX (for dynamic MBean export for example),\n    + Or [CGLIB][] (byte code manipulation), that has to be added as a runtime dependency:\n        + It dynamically extends classes thus it is incompatible with `final` classes or methods,\n        + CGLIB development isn't active, Hibernate has been deprecating it in favor of [Javassist][] (see [Deprecated CGLIB support][]),\n+ [AJDT (AspectJ Development Tools)][AJDT] provides deep integration between AspectJ and the Eclipse platform which is not possible with Spring AOP due to the runtime / dynamic nature of its AOP implementation.\n\nFurther details can be found in [Choosing which AOP declaration style to use][] from the Spring framework documentation. The [Spring AOP vs AspectJ][] question on Stack Overflow provides some insights as well.\n\n[Spring AOP]: http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html\n[AspectJ]: http://eclipse.org/aspectj/\n[CGLIB]: http://cglib.sourceforge.net/\n[Javassist]: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/\n[AJDT]: http://www.eclipse.org/ajdt/\n[Spring proxying mechanisms]: http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html#aop-proxying\n[Deprecated CGLIB support]: http://relation.to/16658.lace\n[Choosing which AOP declaration style to use]: http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/aop.html#aop-choosing\n[Spring AOP vs AspectJ]: http://stackoverflow.com/questions/1606559/spring-aop-vs-aspectj\n\n## License\n\nCopyright © 2013-2016, Antonin Stefanutti\n\nPublished under Apache Software License 2.0, see LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastefanutti%2Fmetrics-aspectj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastefanutti%2Fmetrics-aspectj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastefanutti%2Fmetrics-aspectj/lists"}