diff --git a/common/src/main/scala/zio/metrics/typeclasses.scala b/common/src/main/scala/zio/metrics/typeclasses.scala index 86a5a29b..f2fae21d 100644 --- a/common/src/main/scala/zio/metrics/typeclasses.scala +++ b/common/src/main/scala/zio/metrics/typeclasses.scala @@ -3,7 +3,7 @@ package zio.metrics import scala.math.Numeric import scala.math.Numeric.Implicits._ -case class Label[A: Show](name: A, labels: Array[String]) +case class Label[A: Show](name: A, labels: Array[String], help: String) trait Show[A] { def show(value: A): String diff --git a/dropwizard/src/main/scala/zio/metrics/dropwizard/helpers/package.scala b/dropwizard/src/main/scala/zio/metrics/dropwizard/helpers/package.scala index b3e9f05d..3d5e1aea 100644 --- a/dropwizard/src/main/scala/zio/metrics/dropwizard/helpers/package.scala +++ b/dropwizard/src/main/scala/zio/metrics/dropwizard/helpers/package.scala @@ -15,23 +15,23 @@ package object helpers { RIO.accessM(_.get.getCurrent()) def registerCounter(name: String, labels: Array[String]): RIO[Registry, DWCounter] = - RIO.accessM(_.get.registerCounter(Label(name, labels))) + RIO.accessM(_.get.registerCounter(Label(name, labels, s"$name counter"))) def registerGauge[A](name: String, labels: Array[String], f: () => A): RIO[Registry, DWGauge[A]] = - RIO.accessM(_.get.registerGauge[String, A](Label(name, labels), f)) + RIO.accessM(_.get.registerGauge[String, A](Label(name, labels, s"$name gauge"), f)) def registerTimer(name: String, labels: Array[String]): RIO[Registry, DWTimer] = - RIO.accessM(_.get.registerTimer(Label(name, labels))) + RIO.accessM(_.get.registerTimer(Label(name, labels, s"$name timer"))) def registerMeter(name: String, labels: Array[String]): RIO[Registry, DWMeter] = - RIO.accessM(_.get.registerMeter(Label(name, labels))) + RIO.accessM(_.get.registerMeter(Label(name, labels, s"$name meter"))) def registerHistogram( name: String, labels: Array[String], reservoir: Reservoir ): RIO[Registry, DWHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, labels), reservoir)) + RIO.accessM(_.get.registerHistogram(Label(name, labels, s"$name histogram"), reservoir)) object counter { def register(name: String) = Counter(name, Array.empty[String]) diff --git a/dropwizard/src/test/scala/zio/metrics/DropwizardTest.scala b/dropwizard/src/test/scala/zio/metrics/DropwizardTest.scala index 198c088d..14c06e4f 100644 --- a/dropwizard/src/test/scala/zio/metrics/DropwizardTest.scala +++ b/dropwizard/src/test/scala/zio/metrics/DropwizardTest.scala @@ -19,7 +19,7 @@ object DropwizardTest { val testCounter: RIO[Registry, MetricRegistry] = for { dwr <- RIO.environment[Registry] - dwc <- dwr.get.registerCounter(Label(DropwizardTest.getClass(), Array("test", "counter"))) + dwc <- dwr.get.registerCounter(Label(DropwizardTest.getClass(), Array("test", "counter"), "")) c <- Task(new Counter(dwc)) _ <- c.inc() _ <- c.inc(2.0) diff --git a/prometheus/src/main/scala/zio/metrics/prometheus/Metrics.scala b/prometheus/src/main/scala/zio/metrics/prometheus/Metrics.scala index 0c6b2609..8928b19c 100644 --- a/prometheus/src/main/scala/zio/metrics/prometheus/Metrics.scala +++ b/prometheus/src/main/scala/zio/metrics/prometheus/Metrics.scala @@ -38,6 +38,10 @@ object Counter { for { c <- registerCounter(name, labels) } yield new Counter(c) + def apply(name: String, labels: Array[String], help: String): RIO[Registry, Counter] = + for { + c <- registerCounter(name, labels, help) + } yield new Counter(c) } case class Gauge(private val pGauge: PGauge) extends Metric { @@ -129,6 +133,11 @@ object Gauge { for { g <- registerGauge(name, labels) } yield new Gauge(g) + + def apply(name: String, labels: Array[String], help: String): RIO[Registry, Gauge] = + for { + g <- registerGauge(name, labels, help) + } yield new Gauge(g) } case class Histogram(private val pHistogram: PHistogram) extends Metric { @@ -211,6 +220,11 @@ object Histogram { for { h <- registerHistogram(name, labels, buckets) } yield new Histogram(h) + + def apply(name: String, labels: Array[String], buckets: Buckets, help: String): RIO[Registry, Histogram] = + for { + h <- registerHistogram(name, labels, buckets, help) + } yield new Histogram(h) } case class Summary(private val pSummary: PSummary) extends Metric { @@ -300,4 +314,14 @@ object Summary { for { s <- registerSummary(name, labels, percentiles) } yield new Summary(s) + + def apply( + name: String, + labels: Array[String], + percentiles: List[(Percentile, Tolerance)], + help: String + ): RIO[Registry, Summary] = + for { + s <- registerSummary(name, labels, percentiles, help) + } yield new Summary(s) } diff --git a/prometheus/src/main/scala/zio/metrics/prometheus/helpers/package.scala b/prometheus/src/main/scala/zio/metrics/prometheus/helpers/package.scala index bae2f778..bf373ca1 100644 --- a/prometheus/src/main/scala/zio/metrics/prometheus/helpers/package.scala +++ b/prometheus/src/main/scala/zio/metrics/prometheus/helpers/package.scala @@ -17,127 +17,263 @@ package object helpers { ZIO.accessM(_.get.getCurrent()) def registerCounter(name: String): RIO[Registry, PCounter] = - ZIO.accessM(_.get.registerCounter(Label(name, Array.empty[String]))) + ZIO.accessM(_.get.registerCounter(Label(name, Array.empty[String], s"$name counter"))) + + def registerCounter(name: String, help: String): RIO[Registry, PCounter] = + RIO.accessM(_.get.registerCounter(Label(name, Array.empty[String], help))) def registerCounter(name: String, labels: Array[String]): RIO[Registry, PCounter] = - RIO.accessM(_.get.registerCounter(Label(name, labels))) + RIO.accessM(_.get.registerCounter(Label(name, labels, s"$name counter"))) + + def registerCounter(name: String, labels: Array[String], help: String): RIO[Registry, PCounter] = + RIO.accessM(_.get.registerCounter(Label(name, labels, help))) def registerGauge(name: String): RIO[Registry, PGauge] = - RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String]))) + RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String], s"$name gauge"))) + + def registerGauge(name: String, help: String): RIO[Registry, PGauge] = + RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String], help))) def registerGauge(name: String, labels: Array[String]): RIO[Registry, PGauge] = - RIO.accessM(_.get.registerGauge(Label(name, labels))) + RIO.accessM(_.get.registerGauge(Label(name, labels, s"$name gauge"))) + + def registerGauge(name: String, labels: Array[String], help: String): RIO[Registry, PGauge] = + RIO.accessM(_.get.registerGauge(Label(name, labels, help))) def registerHistogram(name: String): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String]), DefaultBuckets(Seq.empty[Double]))) + RIO.accessM( + _.get.registerHistogram(Label(name, Array.empty[String], s"$name histogram"), DefaultBuckets(Seq.empty[Double])) + ) + + def registerHistogram(name: String, help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], help), DefaultBuckets(Seq.empty[Double]))) def registerHistogram(name: String, labels: Array[String]): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, labels), DefaultBuckets(Seq.empty[Double]))) + RIO.accessM(_.get.registerHistogram(Label(name, labels, s"$name histogram"), DefaultBuckets(Seq.empty[Double]))) + + def registerHistogram(name: String, labels: Array[String], help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, labels, help), DefaultBuckets(Seq.empty[Double]))) def registerHistogram(name: String, buckets: Buckets): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String]), buckets)) + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], s"$name histogram"), buckets)) + + def registerHistogram(name: String, buckets: Buckets, help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], help), buckets)) def registerHistogram(name: String, labels: Array[String], buckets: Buckets): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, labels), buckets)) + RIO.accessM(_.get.registerHistogram(Label(name, labels, s"$name histogram"), buckets)) + + def registerHistogram( + name: String, + labels: Array[String], + buckets: Buckets, + help: String + ): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, labels, help), buckets)) def registerSummary(name: String): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String]), List.empty[(Double, Double)])) + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], s"$name summary"), List.empty[(Double, Double)])) + + def registerSummary(name: String, help: String): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], help), List.empty[(Double, Double)])) def registerSummary(name: String, labels: Array[String]): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, labels), List.empty[(Double, Double)])) + RIO.accessM(_.get.registerSummary(Label(name, labels, s"$name summary"), List.empty[(Double, Double)])) + + def registerSummary(name: String, labels: Array[String], help: String): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, labels, help), List.empty[(Double, Double)])) def registerSummary(name: String, percentiles: List[(Percentile, Tolerance)]): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String]), percentiles)) + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], s"$name summary"), percentiles)) + + def registerSummary(name: String, percentiles: List[(Percentile, Tolerance)], help: String): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], help), percentiles)) def registerSummary( name: String, labels: Array[String], percentiles: List[(Percentile, Tolerance)] ): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, labels), percentiles)) + RIO.accessM(_.get.registerSummary(Label(name, labels, s"$name summary"), percentiles)) + + def registerSummary( + name: String, + labels: Array[String], + percentiles: List[(Percentile, Tolerance)], + help: String + ): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, labels, help), percentiles)) def registerCounter(name: Class[_]): RIO[Registry, PCounter] = - RIO.accessM(_.get.registerCounter(Label(name, Array.empty[String]))) + RIO.accessM(_.get.registerCounter(Label(name, Array.empty[String], s"$name counter"))) + + def registerCounter(name: Class[_], help: String): RIO[Registry, PCounter] = + RIO.accessM(_.get.registerCounter(Label(name, Array.empty[String], help))) def registerCounter(name: Class[_], labels: Array[String]): RIO[Registry, PCounter] = - RIO.accessM(_.get.registerCounter(Label(name, labels))) + RIO.accessM(_.get.registerCounter(Label(name, labels, s"$name counter"))) + + def registerCounter(name: Class[_], labels: Array[String], help: String): RIO[Registry, PCounter] = + RIO.accessM(_.get.registerCounter(Label(name, labels, help))) def registerGauge(name: Class[_]): RIO[Registry, PGauge] = - RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String]))) + RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String], s"$name gauge"))) + + def registerGauge(name: Class[_], help: String): RIO[Registry, PGauge] = + RIO.accessM(_.get.registerGauge(Label(name, Array.empty[String], help))) def registerGauge(name: Class[_], labels: Array[String]): RIO[Registry, PGauge] = - RIO.accessM(_.get.registerGauge(Label(name, labels))) + RIO.accessM(_.get.registerGauge(Label(name, labels, s"$name gauge"))) + + def registerGauge(name: Class[_], labels: Array[String], help: String): RIO[Registry, PGauge] = + RIO.accessM(_.get.registerGauge(Label(name, labels, help))) def registerHistogram(name: Class[_]): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String]), DefaultBuckets(Seq.empty[Double]))) + RIO.accessM( + _.get.registerHistogram(Label(name, Array.empty[String], s"$name gauge"), DefaultBuckets(Seq.empty[Double])) + ) + + def registerHistogram(name: Class[_], help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], help), DefaultBuckets(Seq.empty[Double]))) def registerHistogram(name: Class[_], labels: Array[String]): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, labels), DefaultBuckets(Seq.empty[Double]))) + RIO.accessM(_.get.registerHistogram(Label(name, labels, s"$name histogram"), DefaultBuckets(Seq.empty[Double]))) + + def registerHistogram(name: Class[_], labels: Array[String], help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, labels, help), DefaultBuckets(Seq.empty[Double]))) def registerHistogram(name: Class[_], buckets: Buckets): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String]), buckets)) + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], s"$name histogram"), buckets)) + + def registerHistogram(name: Class[_], buckets: Buckets, help: String): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, Array.empty[String], help), buckets)) def registerHistogram(name: Class[_], labels: Array[String], buckets: Buckets): RIO[Registry, PHistogram] = - RIO.accessM(_.get.registerHistogram(Label(name, labels), buckets)) + RIO.accessM(_.get.registerHistogram(Label(name, labels, s"$name histogram"), buckets)) + + def registerHistogram( + name: Class[_], + labels: Array[String], + buckets: Buckets, + help: String + ): RIO[Registry, PHistogram] = + RIO.accessM(_.get.registerHistogram(Label(name, labels, help), buckets)) def registerSummary(name: Class[_]): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String]), List.empty[(Double, Double)])) + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], s"$name summary"), List.empty[(Double, Double)])) + + def registerSummary(name: Class[_], help: String): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], help), List.empty[(Double, Double)])) def registerSummary(name: Class[_], labels: Array[String]): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, labels), List.empty[(Double, Double)])) + RIO.accessM(_.get.registerSummary(Label(name, labels, s"$name summary"), List.empty[(Double, Double)])) + + def registerSummary(name: Class[_], labels: Array[String], help: String): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, labels, help), List.empty[(Double, Double)])) def registerSummary(name: Class[_], percentiles: List[(Percentile, Tolerance)]): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String]), percentiles)) + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], s"$name summary"), percentiles)) + + def registerSummary( + name: Class[_], + percentiles: List[(Percentile, Tolerance)], + help: String + ): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, Array.empty[String], help), percentiles)) def registerSummary( name: Class[_], labels: Array[String], percentiles: List[(Percentile, Tolerance)] ): RIO[Registry, PSummary] = - RIO.accessM(_.get.registerSummary(Label(name, labels), percentiles)) + RIO.accessM(_.get.registerSummary(Label(name, labels, s"$name summary"), percentiles)) + + def registerSummary( + name: Class[_], + labels: Array[String], + percentiles: List[(Percentile, Tolerance)], + help: String + ): RIO[Registry, PSummary] = + RIO.accessM(_.get.registerSummary(Label(name, labels, help), percentiles)) object counter { def register(name: String) = Counter(name, Array.empty[String]) + def register(name: String, help: String) = + Counter(name, Array.empty[String], help) + def register(name: String, labels: Array[String]) = Counter(name, labels) + + def register(name: String, labels: Array[String], help: String) = + Counter(name, labels, help) } object gauge { def register(name: String) = Gauge(name, Array.empty[String]) + def register(name: String, help: String) = + Gauge(name, Array.empty[String], help) + def register(name: String, labels: Array[String]) = Gauge(name, labels) + + def register(name: String, labels: Array[String], help: String) = + Gauge(name, labels, help) } object histogram { def register(name: String) = Histogram(name, Array.empty[String], DefaultBuckets(Seq.empty[Double])) + def register(name: String, help: String) = + Histogram(name, Array.empty[String], DefaultBuckets(Seq.empty[Double]), help) + def register(name: String, labels: Array[String]) = Histogram(name, labels, DefaultBuckets(Seq.empty[Double])) + def register(name: String, labels: Array[String], help: String) = + Histogram(name, labels, DefaultBuckets(Seq.empty[Double]), help) + def register(name: String, buckets: Buckets) = Histogram(name, Array.empty[String], buckets) + def register(name: String, buckets: Buckets, help: String) = + Histogram(name, Array.empty[String], buckets, help) + def register(name: String, labels: Array[String], buckets: Buckets) = Histogram(name, labels, buckets) + + def register(name: String, labels: Array[String], buckets: Buckets, help: String) = + Histogram(name, labels, buckets, help) } object summary { def register(name: String) = Summary(name, Array.empty[String], List.empty[(Double, Double)]) + def register(name: String, help: String) = + Summary(name, Array.empty[String], List.empty[(Double, Double)], help) + def register(name: String, labels: Array[String]) = Summary(name, labels, List.empty[(Percentile, Tolerance)]) + def register(name: String, labels: Array[String], help: String) = + Summary(name, labels, List.empty[(Percentile, Tolerance)], help) + def register(name: String, percentiles: List[(Percentile, Tolerance)]) = Summary(name, Array.empty[String], percentiles) + def register(name: String, percentiles: List[(Percentile, Tolerance)], help: String) = + Summary(name, Array.empty[String], percentiles, help) + def register(name: String, labels: Array[String], percentiles: List[(Percentile, Tolerance)]) = Summary(name, labels, percentiles) + + def register(name: String, labels: Array[String], percentiles: List[(Percentile, Tolerance)], help: String) = + Summary(name, labels, percentiles, help) } def http(r: CollectorRegistry, port: Int): RIO[Exporters, HTTPServer] = diff --git a/prometheus/src/main/scala/zio/metrics/prometheus/package.scala b/prometheus/src/main/scala/zio/metrics/prometheus/package.scala index 40d42c45..a1c5d7f0 100644 --- a/prometheus/src/main/scala/zio/metrics/prometheus/package.scala +++ b/prometheus/src/main/scala/zio/metrics/prometheus/package.scala @@ -44,7 +44,7 @@ package object prometheus { .build() .name(name) .labelNames(label.labels: _*) - .help(s"$name counter") + .help(label.help) .register(r) (c, r) })) @@ -56,7 +56,7 @@ package object prometheus { .build() .name(name) .labelNames(label.labels: _*) - .help(s"$name gauge") + .help(label.help) .register(r) (g, r) })) @@ -68,7 +68,7 @@ package object prometheus { .build() .name(name) .labelNames(label.labels: _*) - .help(s"$name histogram") + .help(label.help) val h = buckets match { case DefaultBuckets(bs) => if (bs.isEmpty) hb else hb.buckets(bs: _*) @@ -85,7 +85,7 @@ package object prometheus { .build() .name(name) .labelNames(label.labels: _*) - .help(s"$name timer") + .help(label.help) val s = quantiles.foldLeft(sb)((acc, c) => acc.quantile(c._1, c._2)).register(r) (s, r) diff --git a/prometheus/src/test/scala/zio/metrics/ExportersTest.scala b/prometheus/src/test/scala/zio/metrics/ExportersTest.scala index 6c406a2d..662ad966 100644 --- a/prometheus/src/test/scala/zio/metrics/ExportersTest.scala +++ b/prometheus/src/test/scala/zio/metrics/ExportersTest.scala @@ -6,6 +6,7 @@ import zio.metrics.prometheus._ import zio.metrics.prometheus.helpers._ import zio.metrics.prometheus.exporters.Exporters import io.prometheus.client.exporter.HTTPServer +import testz.{ assert, Harness, PureHarness } import zio.console.Console object ExportersTest { @@ -29,8 +30,28 @@ object ExportersTest { _ <- putStrLn(s) } yield hs - val program = exporterTest >>= (server => putStrLn(s"Server port: ${server.getPort()}")) + def tests[T](harness: Harness[T]): T = { + import harness._ + section( + test("Exporter returns help text") { () => + val ex = for { + r <- getCurrentRegistry() + c <- Counter("ExportersTest", Array("exporter"), "help text") + _ <- c.inc(Array("counter")) + s <- write004(r) + _ <- putStrLn(s) + } yield s + val exportedString = rt.unsafeRun(ex) + assert(exportedString.contains("# HELP ExportersTest help text")) + } + ) + } + + val harness: Harness[PureHarness.Uses[Unit]] = + PureHarness.makeFromPrinter((result, name) => { + println(s"${name.reverse.mkString("[\"", "\"->\"", "\"]:")} $result") + }) def main(args: Array[String]): Unit = - rt.unsafeRun(program) + tests(harness)((), Nil).print() }