Skip to content

htimur/metrics-annotation-play

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Download

Metrics Annotation Support for Play Framework

Metrics Annotations Support for Play Framework through Guice AOP. Inspired by Dropwizard Metrics Guice.

Dependencies

Quick Start

Get the artifacts

Artifacts are released in Bintray. For sbt, use resolvers += Resolver.jcenterRepo, for gradle, use the jcenter() repository. For maven, go here and click "Set me up".

SBT:

libraryDependencies += Seq(
  "com.typesafe.play" %% "play" % "2.5.10",
  "io.dropwizard.metrics" % "metrics-core" % "3.1.2",
  "de.khamrakulov" %% "metrics-annotation-play" % "1.0.3"
)

Maven:

<dependencies>
  <dependency>
    <groupId>com.typesafe.play</groupId>
    <artifactId>play_2.11</artifactId>
    <version>2.5.10</version>
  </dependency>
  <dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>3.1.2</version>
  </dependency>
  <dependency>
    <groupId>de.khamrakulov</groupId>
    <artifactId>metrics-annotation-play_2.11</artifactId>
    <version>1.0.3</version>
  </dependency>
</dependencies>

Gradle:

compile 'com.typesafe.play:play:2.5.10'
compile 'io.dropwizard.metrics:metrics-core:3.1.2'
compile 'de.khamrakulov:metrics-annotation-play_2.11:1.0.3'

Enable MetricsAnnotationModule module in your application configuration

play.modules.enabled += "de.khamrakulov.play.metrics.annotation.MetricsAnnotationModule"

Use it

The MetricsAnnotationModule you installed above will create and appropriately invoke a Timer for @Timed, a Meter for @Metered, a Counter for @Counted, and a Gauge for @Gauge. @ExceptionMetered is also supported; this creates a Meter that measures how often a method throws exceptions.

The annotations have some configuration options available for metric name, etc. You can also provide a custom MetricNamer implementation if the default name scheme does not work for you.

Example

If you have a method like this:

class SuperCriticalFunctionality {
    def doSomethingImportant = {
        // critical business logic
    }
}

and you want to use a Timer to measure duration, etc, you could always do it by hand:

def doSomethingImportant() = {
    // timer is some Timer instance
    val context = timer.time()
    try // critical business logic
    finally context.stop()
}

However, if you're instantiating that class with Guice, you could just do this:

@Timed
def doSomethingImportant = {
    // critical business logic
}

or this:

@Timed
class SuperCriticalFunctionality {
    def doSomethingImportant = {
        // critical business logic
    }
}

Type level annotations

Type level annotation support is implemented for: Timed, Metered, Counted and ExceptionMetered annotations.

Configuration

metrics {
  annotation {
    metric-namer = "de.khamrakulov.play.metrics.annotation.DefaultMetricNamer" //Metric namer implementation
    annotation-matchers = [ //Annotation matchers, to derrive annotations from type
      "de.khamrakulov.play.metrics.annotation.matcher.ClassAnnotationMatcher",
      "de.khamrakulov.play.metrics.annotation.matcher.MethodAnnotationMatcher",
    ]
  }
}

Limitations

Since this uses Guice AOP, instances must be created by Guice; see the Guice wiki. This means that using a Provider where you create the instance won't work, or binding a singleton to an instance, etc.

Guice AOP doesn't allow us to intercept method calls to annotated methods in supertypes, so @Counted, etc, will not have metrics generated for them if they are in supertypes of the injectable class. One small consolation is that @Gauge methods can be anywhere in the type hierarchy since they work differently from the other metrics (the generated Gauge object invokes the java.lang.reflect.Method directly, so we can call the supertype method unambiguously).