Skip to content

Commit

Permalink
PerKey metrics with forKeys method (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
nb-ceffa authored Mar 15, 2022
1 parent 3bed972 commit df680b1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.avast.metrics.scalaeffectapi.perkey

import cats.data.NonEmptyList
import com.avast.metrics.scalaeffectapi.Monitor

private[perkey] object PerKeyHelper {
type MetricBuilder[T] = NonEmptyList[String] => T

def metricBuilder[F[_], T](
monitor: Monitor[F]
)(baseName: String, instanceBuilder: (Monitor[F], String) => T): MetricBuilder[T] = { keys =>
if (keys.length == 1) {
instanceBuilder(monitor.named(baseName), keys.last)
} else {
val tailWithoutLast = keys.tail.dropRight(1)
instanceBuilder(monitor.named(baseName, keys.head, tailWithoutLast: _*), keys.last)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ package com.avast.metrics.scalaeffectapi.perkey

trait PerKeyMetric[M] {
def forKey(str: String): M
def forKeys(name: String, name2: String, names: String*): M
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
package com.avast.metrics.scalaeffectapi.perkey.impl

import cats.effect.std.Dispatcher
import com.avast.metrics.scalaeffectapi.perkey.PerKeyHelper.MetricBuilder
import com.avast.metrics.scalaeffectapi.{Gauge, Monitor, SettableGauge}
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, PerKeyMetric}
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, PerKeyHelper, PerKeyMetric}

import scala.collection.concurrent.TrieMap

class PerKeyGaugeFactoryImpl[F[_]](monitor: Monitor[F]) extends PerKeyGaugeFactory[F] {
private def emptyMap[M] = TrieMap.empty[String, M]

private def metricBuilder[T]: (String, (Monitor[F], String) => T) => MetricBuilder[T] = PerKeyHelper.metricBuilder(monitor)

override def settableLong(baseName: String, replaceExisting: Boolean = false): PerKeyMetric[SettableGauge[F, Long]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[SettableGauge[F, Long]](emptyMap[SettableGauge[F, Long]], instanceBuilder.gauge.settableLong(_, replaceExisting))
val instanceBuilder: (Monitor[F], String) => SettableGauge[F, Long] = (m, n) => m.gauge.settableLong(n, replaceExisting)
new PerKeyMetricImpl[SettableGauge[F, Long]](emptyMap[SettableGauge[F, Long]], metricBuilder(baseName, instanceBuilder))
}

override def settableDouble(baseName: String, replaceExisting: Boolean = false): PerKeyMetric[SettableGauge[F, Double]] = {
val instanceBuilder = monitor.named(baseName)
val instanceBuilder: (Monitor[F], String) => SettableGauge[F, Double] = (m, n) => m.gauge.settableDouble(n, replaceExisting)
new PerKeyMetricImpl[SettableGauge[F, Double]](
emptyMap[SettableGauge[F, Double]],
instanceBuilder.gauge.settableDouble(_, replaceExisting)
metricBuilder(baseName, instanceBuilder)
)
}

override def generic[T](baseName: String, replaceExisting: Boolean = false)(retrieveValue: () => T): PerKeyMetric[Gauge[F, T]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Gauge[F, T]](emptyMap[Gauge[F, T]], instanceBuilder.gauge.generic(_, replaceExisting)(retrieveValue))
val instanceBuilder: (Monitor[F], String) => Gauge[F, T] = (m, n) => m.gauge.generic(n, replaceExisting)(retrieveValue)
new PerKeyMetricImpl[Gauge[F, T]](emptyMap[Gauge[F, T]], metricBuilder(baseName, instanceBuilder))
}

override def genericWithUnsafeRun[T](baseName: String, replaceExisting: Boolean = false)(retrieveValue: F[T])(implicit
dispatcher: Dispatcher[F]
): PerKeyMetric[Gauge[F, T]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Gauge[F, T]](emptyMap[Gauge[F, T]], instanceBuilder.gauge.genericWithUnsafeRun(_, replaceExisting)(retrieveValue))
val instanceBuilder: (Monitor[F], String) => Gauge[F, T] = (m, n) => m.gauge.genericWithUnsafeRun(n, replaceExisting)(retrieveValue)
new PerKeyMetricImpl[Gauge[F, T]](emptyMap[Gauge[F, T]], metricBuilder(baseName, instanceBuilder))
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package com.avast.metrics.scalaeffectapi.perkey.impl

import cats.data.NonEmptyList
import com.avast.metrics.scalaeffectapi.perkey.PerKeyHelper.MetricBuilder
import com.avast.metrics.scalaeffectapi.perkey.PerKeyMetric

import scala.collection.concurrent.{Map => CMap}

private[perkey] class PerKeyMetricImpl[A](map: CMap[String, A], metricBuilder: String => A) extends PerKeyMetric[A] {
override def forKey(str: String): A = {
map.getOrElseUpdate(str, metricBuilder(str))
private[perkey] class PerKeyMetricImpl[A](map: CMap[String, A], metricBuilder: MetricBuilder[A]) extends PerKeyMetric[A] {
override def forKey(name: String): A = {
map.getOrElseUpdate(name, metricBuilder(NonEmptyList(name, Nil)))
}

override def forKeys(name: String, name2: String, names: String*): A = {
val keys = List(name, name2) ::: names.toList
map.getOrElseUpdate(keys.mkString("."), metricBuilder(NonEmptyList(name, keys.tail)))
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
package com.avast.metrics.scalaeffectapi.perkey.impl

import com.avast.metrics.scalaeffectapi._
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, PerKeyMetric, PerKeyOps}
import com.avast.metrics.scalaeffectapi.perkey.PerKeyHelper.MetricBuilder
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, PerKeyHelper, PerKeyMetric, PerKeyOps}

import scala.collection.concurrent.TrieMap

private[perkey] class PerKeyOpsImpl[F[_]](monitor: Monitor[F]) extends PerKeyOps[F] {
private def emptyMap[M] = TrieMap.empty[String, M]

private def metricBuilder[T]: (String, (Monitor[F], String) => T) => MetricBuilder[T] = PerKeyHelper.metricBuilder(monitor)

override def meter(baseName: String): PerKeyMetric[Meter[F]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Meter[F]](emptyMap[Meter[F]], instanceBuilder.meter)
val instanceBuilder: (Monitor[F], String) => Meter[F] = (m, n) => m.meter(n)
new PerKeyMetricImpl[Meter[F]](emptyMap[Meter[F]], metricBuilder(baseName, instanceBuilder))
}

override def counter(baseName: String): PerKeyMetric[Counter[F]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Counter[F]](emptyMap, instanceBuilder.counter)
val instanceBuilder: (Monitor[F], String) => Counter[F] = (m, n) => m.counter(n)
new PerKeyMetricImpl[Counter[F]](emptyMap, metricBuilder(baseName, instanceBuilder))
}

override def timer(baseName: String): PerKeyMetric[Timer[F]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Timer[F]](emptyMap, instanceBuilder.timer)
val instanceBuilder: (Monitor[F], String) => Timer[F] = (m, n) => m.timer(n)
new PerKeyMetricImpl[Timer[F]](emptyMap, metricBuilder(baseName, instanceBuilder))
}

override def timerPair(baseName: String): PerKeyMetric[TimerPair[F]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[TimerPair[F]](emptyMap, instanceBuilder.timerPair)
val instanceBuilder: (Monitor[F], String) => TimerPair[F] = (m, n) => m.timerPair(n)
new PerKeyMetricImpl[TimerPair[F]](emptyMap, metricBuilder(baseName, instanceBuilder))
}

override def histogram(baseName: String): PerKeyMetric[Histogram[F]] = {
val instanceBuilder = monitor.named(baseName)
new PerKeyMetricImpl[Histogram[F]](emptyMap, instanceBuilder.histogram)
val instanceBuilder: (Monitor[F], String) => Histogram[F] = (m, n) => m.histogram(n)
new PerKeyMetricImpl[Histogram[F]](emptyMap, metricBuilder(baseName, instanceBuilder))
}

override def gauge: PerKeyGaugeFactory[F] = {
new PerKeyGaugeFactoryImpl[F](monitor)
}

}

0 comments on commit df680b1

Please sign in to comment.