Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement servlet + default registry
- Loading branch information
Showing
7 changed files
with
211 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
target/ | ||
.idea/ | ||
.idea_modules/ | ||
logs/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,22 @@ | ||
organization:= "com.kenshoo" | ||
|
||
name := "play-metrics" | ||
|
||
version := "0.1.0-SNAPSHOT" | ||
|
||
scalaVersion := "2.10.0" | ||
|
||
resolvers += "Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases/" | ||
|
||
testOptions in Test += Tests.Argument("junitxml", "console") | ||
|
||
libraryDependencies ++= Seq( | ||
"com.codahale.metrics" % "metrics-core" % "3.0.0", | ||
"com.codahale.metrics" % "metrics-json" % "3.0.0", | ||
"com.codahale.metrics" % "metrics-jvm" % "3.0.0", | ||
// "play" % "play" % "2.1.0" % "provided", | ||
"org.specs2" % "specs2_2.10" % "1.13" % "test" | ||
"play" %% "play" % "2.1.0" % "provided", | ||
//test | ||
"play" %% "play-test" % "2.1.0" % "test", | ||
"org.specs2" % "specs2_2.10" % "1.13" % "test", | ||
"org.mockito" % "mockito-all" % "1.9.5" % "test" | ||
) |
48 changes: 48 additions & 0 deletions
48
src/main/scala/com/kenshoo/play/metrics/MertricsPlugin.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.kenshoo.play.metrics | ||
|
||
import com.codahale.metrics.jvm.{ThreadStatesGaugeSet, GarbageCollectorMetricSet, MemoryUsageGaugeSet} | ||
import com.codahale.metrics.{MetricRegistry, SharedMetricRegistries} | ||
import play.api.{Plugin, Application} | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import com.codahale.metrics.json.MetricsModule | ||
import java.util.concurrent.TimeUnit | ||
|
||
|
||
object MetricsRegistry { | ||
def default(implicit app : Application) = { | ||
app.plugin[MetricsPlugin] match { | ||
case Some(plugin) => SharedMetricRegistries.getOrCreate(plugin.registryName) | ||
case None => throw new Exception("metrics plugin is not found") | ||
} | ||
} | ||
} | ||
|
||
|
||
class MetricsPlugin(val app: Application) extends Plugin { | ||
val validUnits = Some(Set("NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS")) | ||
|
||
lazy val registryName = app.configuration.getString("metrics.name").getOrElse("default") | ||
lazy val mapper: ObjectMapper = new ObjectMapper() | ||
lazy val rateUnit = app.configuration.getString("metrics.rateUnit", validUnits).getOrElse("SECONDS") | ||
lazy val durationUnit = app.configuration.getString("metrics.durationUnit", validUnits).getOrElse("SECONDS") | ||
lazy val showSamples = app.configuration.getBoolean("metrics.showSamples").getOrElse(true) | ||
|
||
implicit def stringToTimeUnit(s: String) : TimeUnit = TimeUnit.valueOf(s) | ||
|
||
override def onStart() { | ||
if (enabled) { | ||
val registry: MetricRegistry = SharedMetricRegistries.getOrCreate(registryName) | ||
val jvmMetricsEnabled = app.configuration.getBoolean("metrics.jvm").getOrElse(true) | ||
if (jvmMetricsEnabled) { | ||
registry.registerAll(new GarbageCollectorMetricSet()) | ||
registry.registerAll(new MemoryUsageGaugeSet()) | ||
registry.registerAll(new ThreadStatesGaugeSet()) | ||
} | ||
val module = new MetricsModule(rateUnit, durationUnit, showSamples) | ||
mapper.registerModule(module) | ||
} | ||
} | ||
|
||
override def enabled = app.configuration.getBoolean("metrics.enabled").getOrElse(true) | ||
} | ||
|
41 changes: 41 additions & 0 deletions
41
src/main/scala/com/kenshoo/play/metrics/MetricsController.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.kenshoo.play.metrics | ||
|
||
import play.api.mvc.{Action, Controller} | ||
import com.codahale.metrics.MetricRegistry | ||
import com.fasterxml.jackson.databind.{ObjectWriter, ObjectMapper} | ||
import java.io.StringWriter | ||
import play.api.Play.current | ||
import play.api.Application | ||
|
||
|
||
|
||
trait MetricsController { | ||
self: Controller => | ||
|
||
val registry: MetricRegistry | ||
|
||
val app: Application | ||
|
||
def serialize(mapper: ObjectMapper) = { | ||
val writer: ObjectWriter = mapper.writerWithDefaultPrettyPrinter() | ||
val stringWriter = new StringWriter() | ||
writer.writeValue(stringWriter, registry) | ||
Ok(stringWriter.toString).as("application/json").withHeaders("Cache-Control" -> "must-revalidate,no-cache,no-store") | ||
} | ||
|
||
def metrics = Action { | ||
app.plugin[MetricsPlugin] match { | ||
case Some(plugin) => plugin.enabled match { | ||
case true => serialize(plugin.mapper) | ||
case false => InternalServerError("metrics plugin not enabled") | ||
} | ||
case None => InternalServerError("metrics plugin is not found") | ||
} | ||
} | ||
|
||
} | ||
|
||
object MetricsController extends Controller with MetricsController { | ||
lazy val registry = MetricsRegistry.default | ||
lazy val app = current | ||
} |
This file was deleted.
Oops, something went wrong.
40 changes: 40 additions & 0 deletions
40
src/test/scala/com/kenshoo/play/metrics/MetricsControllerTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.kenshoo.play.metrics | ||
|
||
import org.specs2.mutable.{Before, Specification} | ||
import play.api.mvc.{Controller, Result} | ||
import play.api.test.{WithApplication, FakeApplication, FakeRequest} | ||
import play.api.libs.json.{Json, JsValue} | ||
import play.api.test.Helpers._ | ||
import com.codahale.metrics.MetricRegistry | ||
|
||
class MetricsControllerSpec extends Specification { | ||
"metrics servlet" should { | ||
"returns json result" in new ControllerRegistry { | ||
val result: Result = controller.metrics(FakeRequest()) | ||
val jsValue: JsValue = Json.parse(contentAsString(result)) | ||
(jsValue \ "counters" \ "my-counter" \ "count").as[Int] mustEqual(1) | ||
} | ||
|
||
"sets no cache control" in new ControllerRegistry { | ||
val result: Result = controller.metrics(FakeRequest()) | ||
headers(result) must haveValue("must-revalidate,no-cache,no-store") | ||
} | ||
|
||
} | ||
|
||
abstract class ControllerRegistry extends WithApplication( | ||
FakeApplication(additionalPlugins = Seq("com.kenshoo.play.metrics.MetricsPlugin")) | ||
) with Before { | ||
lazy val testRegistry = new MetricRegistry | ||
|
||
def before { | ||
testRegistry.counter("my-counter").inc() | ||
} | ||
|
||
lazy val controller = new Controller() with MetricsController { | ||
override val registry = testRegistry | ||
override val app = implicitApp | ||
} | ||
} | ||
|
||
} |
70 changes: 70 additions & 0 deletions
70
src/test/scala/com/kenshoo/play/metrics/MetricsPluginTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.kenshoo.play.metrics | ||
|
||
import org.specs2.mutable.Specification | ||
import org.specs2.mock.Mockito | ||
import play.api.{Configuration, Application} | ||
import com.codahale.metrics.{Metric, Meter, SharedMetricRegistries} | ||
import org.specs2.specification.BeforeAfterExample | ||
import scala.collection.JavaConversions._ | ||
import scala.collection.mutable.Map | ||
|
||
|
||
class MetricsPluginSpec extends Specification with Mockito with BeforeAfterExample{ | ||
sequential | ||
"metrics plugin" should { | ||
|
||
"be enabled by default" in { | ||
val plugin = config() | ||
plugin.enabled must beTrue | ||
} | ||
|
||
"can be turned off" in { | ||
val plugin = config(Option(false)) | ||
plugin.enabled must beFalse | ||
} | ||
|
||
"can be turned on" in { | ||
val plugin = config(Option(true)) | ||
plugin.enabled must beTrue | ||
} | ||
|
||
"registers default metric registry" in { | ||
val plugin = config() | ||
plugin.onStart() | ||
SharedMetricRegistries.names().contains("default") must beTrue | ||
} | ||
|
||
"registers metric by name" in { | ||
val plugin = config(name = Option("name")) | ||
plugin.onStart() | ||
SharedMetricRegistries.names().contains("name") must beTrue | ||
} | ||
|
||
"registers jvm metrics" in { | ||
val plugin = config() | ||
plugin.onStart() | ||
val metrics: Map[String, Metric] = SharedMetricRegistries.getOrCreate("default").getMetrics | ||
metrics must haveKey("heap.usage") | ||
} | ||
} | ||
|
||
def config(enabled: Option[Boolean] = Option.empty, | ||
name: Option[String] = Option.empty, | ||
jvm: Option[Boolean] = Option.empty): MetricsPlugin = { | ||
val app = mock[Application] | ||
val config = mock[Configuration] | ||
app.configuration returns config | ||
config.getString(anyString, any[Option[Set[String]]]) returns Option.empty | ||
config.getBoolean("metrics.enabled") returns enabled | ||
config.getString("metrics.name") returns name | ||
config.getBoolean("metrics.jvm") returns jvm | ||
config.getBoolean("metrics.showSamples") returns Option.empty | ||
new MetricsPlugin(app) | ||
} | ||
|
||
def after { | ||
SharedMetricRegistries.clear() | ||
} | ||
|
||
protected def before: Any = {} | ||
} |