From 2683cac6ddf1f4c88413e9d67e6b02c9b7ae2e2e Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Wed, 5 Sep 2018 14:24:00 +0200 Subject: [PATCH 1/6] Updated prometheus client version Update Play and Scala dependencies Added setting for automatic loading of default hotspot collectors Updated Readme --- README.md | 10 +++++++++- .../playprometheusfilters/PrometheusModule.scala | 9 +++++++++ build.sbt | 9 +++++---- conf/reference.conf | 5 ++++- project/plugins.sbt | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 78b96f9..253c725 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,12 @@ GET /metrics com.github.stijndehaes.playprometheusfilters.contr You should be able to immediately get the metrics -## Example +## Default Hotspot metrics + +The [Prometheus Hotspot library](https://github.com/prometheus/client_java#included-collectors) provides some default collectors +for garbage collection, memory pool, etc. +Default these collectors are registered. This can be changed by setting the configuration property to `false`. + +``` +play-prometheus-filters.register-default-hotspot-collectors = true +``` diff --git a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala index 78241e7..617b372 100644 --- a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala +++ b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala @@ -3,11 +3,20 @@ package com.github.stijndehaes.playprometheusfilters import play.api.inject.{Binding, Module} import play.api.{Configuration, Environment} import io.prometheus.client.CollectorRegistry +import io.prometheus.client.hotspot.DefaultExports class PrometheusModule extends Module { + private val defaultExportsKey = "play-prometheus-filters.default-exports" override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = { CollectorRegistry.defaultRegistry.clear() + + configuration.getOptional[Boolean](defaultExportsKey).foreach { enabled => + if (enabled) { + DefaultExports.initialize() + } + } + Seq( bind[CollectorRegistry].to(CollectorRegistry.defaultRegistry) ) diff --git a/build.sbt b/build.sbt index e6eae5b..b1fd9df 100644 --- a/build.sbt +++ b/build.sbt @@ -37,14 +37,15 @@ lazy val root = (project in file(".")) ) -scalaVersion := "2.12.5" +scalaVersion := "2.12.6" -crossScalaVersions := Seq(scalaVersion.value, "2.11.11") +crossScalaVersions := Seq(scalaVersion.value, "2.11.12") libraryDependencies ++= Seq( guice, - "io.prometheus" % "simpleclient" % "0.3.0", - "io.prometheus" % "simpleclient_servlet" % "0.3.0" + "io.prometheus" % "simpleclient" % "0.5.0", + "io.prometheus" % "simpleclient_hotspot" % "0.5.0", + "io.prometheus" % "simpleclient_servlet" % "0.5.0" ) libraryDependencies ++= Seq( diff --git a/conf/reference.conf b/conf/reference.conf index b980d58..a900031 100644 --- a/conf/reference.conf +++ b/conf/reference.conf @@ -1 +1,4 @@ -play.modules.enabled += com.github.stijndehaes.playprometheusfilters.PrometheusModule \ No newline at end of file +play.modules.enabled += com.github.stijndehaes.playprometheusfilters.PrometheusModule + +# Registers some default collectors for jvm metrics. See DefaultExports class. +play-prometheus-filters.register-default-hotspot-collectors = true \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 7791ceb..eaea9bb 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ // The Play plugin -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.12") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.18") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") From 8ae1602627e74b8992f3e1b983ed8e499d0dc06a Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Wed, 5 Sep 2018 14:46:44 +0200 Subject: [PATCH 2/6] Updated config key --- .../stijndehaes/playprometheusfilters/PrometheusModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala index 617b372..0cd80ff 100644 --- a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala +++ b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala @@ -6,7 +6,7 @@ import io.prometheus.client.CollectorRegistry import io.prometheus.client.hotspot.DefaultExports class PrometheusModule extends Module { - private val defaultExportsKey = "play-prometheus-filters.default-exports" + private val defaultExportsKey = "play-prometheus-filters.register-default-hotspot-collectors" override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = { CollectorRegistry.defaultRegistry.clear() From c82434f823e83a51c69ca132835d5bff1467b776 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Tue, 11 Sep 2018 15:26:22 +0200 Subject: [PATCH 3/6] Added test cases for default exporters. Changed PrometheusModule not use defaultRegistry since that makes it impossible to test. --- .../PrometheusModule.scala | 30 ++++++++++-- .../PrometheusModuleSpec.scala | 46 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala diff --git a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala index 0cd80ff..70ab2b5 100644 --- a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala +++ b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala @@ -3,22 +3,42 @@ package com.github.stijndehaes.playprometheusfilters import play.api.inject.{Binding, Module} import play.api.{Configuration, Environment} import io.prometheus.client.CollectorRegistry -import io.prometheus.client.hotspot.DefaultExports +import io.prometheus.client.hotspot._ + +object PrometheusModule { + val defaultExportsKey = "play-prometheus-filters.register-default-hotspot-collectors" +} class PrometheusModule extends Module { - private val defaultExportsKey = "play-prometheus-filters.register-default-hotspot-collectors" + import PrometheusModule._ + + /** + * Registering default exporters. See [[DefaultExports.initialize()]] + * + * Not using DefaultExports.initialize since that makes it impossible to test. + * Guice guarantees this is only run once for an application. + */ + def registerDefaultExporters(registry: CollectorRegistry): Unit = { + registry.register(new StandardExports) + registry.register(new MemoryPoolsExports) + registry.register(new BufferPoolsExports) + registry.register(new GarbageCollectorExports) + registry.register(new ThreadExports) + registry.register(new ClassLoadingExports) + registry.register(new VersionInfoExports) + } override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = { - CollectorRegistry.defaultRegistry.clear() + val registry = new CollectorRegistry(true) configuration.getOptional[Boolean](defaultExportsKey).foreach { enabled => if (enabled) { - DefaultExports.initialize() + registerDefaultExporters(registry) } } Seq( - bind[CollectorRegistry].to(CollectorRegistry.defaultRegistry) + bind[CollectorRegistry].to(registry) ) } } diff --git a/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala new file mode 100644 index 0000000..1b443bb --- /dev/null +++ b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala @@ -0,0 +1,46 @@ +package com.github.stijndehaes.playprometheusfilters + +import io.prometheus.client.CollectorRegistry +import org.scalatest.{MustMatchers, WordSpec} +import play.api.inject.guice.GuiceApplicationBuilder + +class PrometheusModuleSpec extends WordSpec with MustMatchers { + + "PrometheusModule" should { + "register default exporters when enabled" in { + // default enabled + val app = new GuiceApplicationBuilder().build() + + val collector = app.injector.instanceOf[CollectorRegistry] + collector.getExporterNames.size must be > 0 + } + + "not register default exporters when disabled" in { + // disable default exporters + val app = new GuiceApplicationBuilder() + .configure(PrometheusModule.defaultExportsKey -> false) + .build() + + val collector = app.injector.instanceOf[CollectorRegistry] + collector.getExporterNames.size must be (0) + } + } + + /** + * Utility to expose exporter names for test on [[CollectorRegistry]]. + */ + implicit class CollectorRegistryExtention(val registry: CollectorRegistry) { + /** + * @return Registered exporter names. + */ + def getExporterNames: Seq[String] = { + val exportNames = collection.mutable.Buffer.empty[String] + val mfs = registry.metricFamilySamples() + while(mfs.hasMoreElements) { + exportNames += mfs.nextElement().name + } + println(exportNames) + exportNames + } + } +} From 972607512a2c867ebc8a0de208fc9fdb6d867a44 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Wed, 12 Sep 2018 12:53:59 +0200 Subject: [PATCH 4/6] Removed println --- .../stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala index 1b443bb..ee138e8 100644 --- a/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala +++ b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala @@ -39,7 +39,6 @@ class PrometheusModuleSpec extends WordSpec with MustMatchers { while(mfs.hasMoreElements) { exportNames += mfs.nextElement().name } - println(exportNames) exportNames } } From f4610aa26911b1458850e62f6ffdf5a7178cd0a7 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Thu, 13 Sep 2018 09:07:27 +0200 Subject: [PATCH 5/6] Switched back to using default registry cause it causes problems with other metrics like Hikari metric. In test clearing registry before each test. Had to change default to 'false' otherwise could not get test working when running all test. Disabling parallel test execution also did not help. No idea why. Updated Readme. --- README.md | 2 +- .../PrometheusModule.scala | 22 ++----------------- conf/reference.conf | 2 +- .../PrometheusModuleSpec.scala | 13 ++++++++--- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 253c725..b007b88 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ You should be able to immediately get the metrics The [Prometheus Hotspot library](https://github.com/prometheus/client_java#included-collectors) provides some default collectors for garbage collection, memory pool, etc. -Default these collectors are registered. This can be changed by setting the configuration property to `false`. +Default these collectors are _not_ registered. This can be changed by setting the configuration property to `true`. ``` play-prometheus-filters.register-default-hotspot-collectors = true diff --git a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala index 70ab2b5..37709da 100644 --- a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala +++ b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala @@ -12,33 +12,15 @@ object PrometheusModule { class PrometheusModule extends Module { import PrometheusModule._ - /** - * Registering default exporters. See [[DefaultExports.initialize()]] - * - * Not using DefaultExports.initialize since that makes it impossible to test. - * Guice guarantees this is only run once for an application. - */ - def registerDefaultExporters(registry: CollectorRegistry): Unit = { - registry.register(new StandardExports) - registry.register(new MemoryPoolsExports) - registry.register(new BufferPoolsExports) - registry.register(new GarbageCollectorExports) - registry.register(new ThreadExports) - registry.register(new ClassLoadingExports) - registry.register(new VersionInfoExports) - } - override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = { - val registry = new CollectorRegistry(true) - configuration.getOptional[Boolean](defaultExportsKey).foreach { enabled => if (enabled) { - registerDefaultExporters(registry) + DefaultExports.initialize() } } Seq( - bind[CollectorRegistry].to(registry) + bind[CollectorRegistry].to(CollectorRegistry.defaultRegistry) ) } } diff --git a/conf/reference.conf b/conf/reference.conf index a900031..1562e5e 100644 --- a/conf/reference.conf +++ b/conf/reference.conf @@ -1,4 +1,4 @@ play.modules.enabled += com.github.stijndehaes.playprometheusfilters.PrometheusModule # Registers some default collectors for jvm metrics. See DefaultExports class. -play-prometheus-filters.register-default-hotspot-collectors = true \ No newline at end of file +play-prometheus-filters.register-default-hotspot-collectors = false \ No newline at end of file diff --git a/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala index ee138e8..6746f0a 100644 --- a/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala +++ b/test/com/github/stijndehaes/playprometheusfilters/PrometheusModuleSpec.scala @@ -1,15 +1,22 @@ package com.github.stijndehaes.playprometheusfilters import io.prometheus.client.CollectorRegistry -import org.scalatest.{MustMatchers, WordSpec} +import org.scalatest.{BeforeAndAfter, MustMatchers, WordSpec} import play.api.inject.guice.GuiceApplicationBuilder -class PrometheusModuleSpec extends WordSpec with MustMatchers { +class PrometheusModuleSpec extends WordSpec with MustMatchers with BeforeAndAfter { + + before { + // clearing registry before each test + CollectorRegistry.defaultRegistry.clear() + } "PrometheusModule" should { "register default exporters when enabled" in { // default enabled - val app = new GuiceApplicationBuilder().build() + val app = new GuiceApplicationBuilder() + .configure(PrometheusModule.defaultExportsKey -> true) + .build() val collector = app.injector.instanceOf[CollectorRegistry] collector.getExporterNames.size must be > 0 From 2214abfac80f70827d4876d4c68b614bbe806a11 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Thu, 13 Sep 2018 09:56:09 +0200 Subject: [PATCH 6/6] Re-added clearing of CollectorRegistry on startup to prevent problems with registring exports when hot-reloading the app like when running Play via Sbt. Note that reloading does _not_ add the default exports since that class has an internal _initialized_ state which stays at _true_ when reloading classes preventing the exports to be added again. --- .../stijndehaes/playprometheusfilters/PrometheusModule.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala index 37709da..a91cfbc 100644 --- a/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala +++ b/app/com/github/stijndehaes/playprometheusfilters/PrometheusModule.scala @@ -13,6 +13,8 @@ class PrometheusModule extends Module { import PrometheusModule._ override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = { + CollectorRegistry.defaultRegistry.clear() + configuration.getOptional[Boolean](defaultExportsKey).foreach { enabled => if (enabled) { DefaultExports.initialize()