Skip to content

Commit

Permalink
feat!: merge cats2 and cats3 repos into one
Browse files Browse the repository at this point in the history
  • Loading branch information
Tasssadar committed Mar 10, 2023
1 parent 1b92003 commit 229436c
Show file tree
Hide file tree
Showing 57 changed files with 560 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Main advantages of this library:
1) Universal abstraction with misc. implementations
2) Support of multiple exports at once (`MultiMonitor`)
3) Scala API
4) Scala Effect API (cats-effect 3) - If you need cats-effect 2 you can use version 2.9.x of this library.
4) Scala Effect API (cats-effect 2 and 3)

The entry-point into the library is the interface `Monitor`. Your classes need to get an instance of a monitor which they can use to construct different metrics, e.g. meters, timers or histograms.
Instances of the individuals metrics can be used to monitor your application.
Expand Down
31 changes: 29 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ lazy val Versions = new {
val grpc = "1.42.1"
val slf4j = "1.7.30"
val assertj = "3.12.2"
val catsEffect2 = "2.5.3"
val catsEffect3 = "3.3.5"
}

Expand Down Expand Up @@ -59,7 +60,21 @@ lazy val root = (project in file("."))
publish / skip := true,
crossScalaVersions := Nil
)
.aggregate(api, scalaApi, scalaCatsEffect3, core, dropwizardCommon, jmx, jmxAvast, graphite, filter, formatting, statsd, grpc)
.aggregate(
api,
scalaApi,
scalaCatsEffect2,
scalaCatsEffect3,
core,
dropwizardCommon,
jmx,
jmxAvast,
graphite,
filter,
formatting,
statsd,
grpc
)

lazy val api = (project in file("api")).settings(
commonSettings,
Expand All @@ -75,7 +90,19 @@ lazy val scalaApi = (project in file("scala-api"))
)
.dependsOn(api, jmx % "test")

lazy val scalaCatsEffect3 = (project in file("scala-effect-api"))
lazy val scalaCatsEffect2 = (project in file("scala-effect-api-cats2"))
.settings(
commonSettings,
scalaSettings,
scalacOptions += "-language:higherKinds",
name := "metrics-cats-effect-2",
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-effect" % Versions.catsEffect2
)
)
.dependsOn(scalaApi, jmx % "test")

lazy val scalaCatsEffect3 = (project in file("scala-effect-api-cats3"))
.settings(
commonSettings,
scalaSettings,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.avast.metrics.scalaeffectapi

trait GaugeFactory[F[_]] {
def settableLong(name: String, replaceExisting: Boolean = false): SettableGauge[F, Long]
def settableDouble(name: String, replaceExisting: Boolean = false): SettableGauge[F, Double]
def generic[T](name: String, replaceExisting: Boolean = false)(gauge: () => T): Gauge[F, T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.avast.metrics.scalaeffectapi.impl

import cats.effect.Sync
import com.avast.metrics.scalaapi.{Monitor => SMonitor}
import com.avast.metrics.scalaeffectapi.{Gauge, GaugeFactory, SettableGauge}

import java.util.concurrent.atomic.{AtomicLong, AtomicReference}

private class GaugeFactoryImpl[F[_]: Sync](monitor: SMonitor) extends GaugeFactory[F] {

override def settableLong(gaugeName: String, replaceExisting: Boolean = false): SettableGauge[F, Long] = new SettableGauge[F, Long] {
private[this] val valueRef = new AtomicLong(0L)
private[this] val gauge = monitor.gauge(gaugeName, replaceExisting)(valueRef.get)

override def set(value: Long): F[Unit] = Sync[F].delay(valueRef.set(value))

override def name: String = gauge.name

override def value: F[Long] = Sync[F].delay(gauge.value)

override def update(f: Long => Long): F[Long] = Sync[F].delay(valueRef.updateAndGet(f(_)))

override def inc: F[Long] = Sync[F].delay(valueRef.incrementAndGet())

override def dec: F[Long] = Sync[F].delay(valueRef.decrementAndGet())
}

override def settableDouble(gaugeName: String, replaceExisting: Boolean = false): SettableGauge[F, Double] =
new SettableGauge[F, Double] {
private[this] val valueRef = new AtomicReference(0.0)
private[this] val gauge = monitor.gauge(gaugeName, replaceExisting)(valueRef.get)

override def set(value: Double): F[Unit] = Sync[F].delay(valueRef.set(value))

override def name: String = gauge.name

override def value: F[Double] = Sync[F].delay(gauge.value)

override def update(f: Double => Double): F[Double] = Sync[F].delay(valueRef.updateAndGet(f(_)))

override def inc: F[Double] = Sync[F].delay(valueRef.accumulateAndGet(1, (a, b) => a + b))

override def dec: F[Double] = Sync[F].delay(valueRef.accumulateAndGet(1, (a, b) => a - b))
}

override def generic[T](gaugeName: String, replaceExisting: Boolean = false)(gauge: () => T): Gauge[F, T] = new Gauge[F, T] {
private[this] val sGauge = monitor.gauge(gaugeName, replaceExisting)(gauge)

override def value: F[T] = Sync[F].delay(sGauge.value)

override def name: String = sGauge.name
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.avast.metrics.scalaeffectapi.perkey

import com.avast.metrics.scalaeffectapi.{Gauge, SettableGauge}

trait PerKeyGaugeFactory[F[_]] {
def settableLong(baseName: String, replaceExisting: Boolean = false): PerKeyMetric[SettableGauge[F, Long]]
def settableDouble(baseName: String, replaceExisting: Boolean = false): PerKeyMetric[SettableGauge[F, Double]]
def generic[T](baseName: String, replaceExisting: Boolean = false)(gauge: () => T): PerKeyMetric[Gauge[F, T]]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.avast.metrics.scalaeffectapi.perkey

trait PerKeyMetric[M] {
def forKey(str: String): M
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.avast.metrics.scalaeffectapi.perkey.impl

import com.avast.metrics.scalaeffectapi.{Gauge, Monitor, SettableGauge}
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, PerKeyMetric}

import scala.collection.concurrent.TrieMap

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

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))
}

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

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

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))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.avast.metrics.scalaeffectapi.perkey.impl

import com.avast.metrics.scalaeffectapi._
import com.avast.metrics.scalaeffectapi.perkey.{PerKeyGaugeFactory, 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]

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

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

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

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

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

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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.avast.metrics.examples

import cats.effect.{ExitCode, IO, IOApp, Timer}
import com.avast.metrics.dropwizard.JmxMetricsMonitor
import com.avast.metrics.scalaeffectapi.Monitor

import java.util.concurrent.TimeUnit
import scala.concurrent.duration.FiniteDuration

object EffectMonitor extends IOApp {

val jmxMetricsMonitor = new JmxMetricsMonitor("com.avast.some.app")

override def run(args: List[String]): IO[ExitCode] = {
val monitor = Monitor.wrapJava[IO](jmxMetricsMonitor)
val counter = monitor.counter("counter")
val timer = monitor.timer("timer")

for {
_ <- counter.inc
_ <- timer.time {
Timer[IO](IO.timer(executionContext)).sleep(FiniteDuration(500, TimeUnit.MILLISECONDS))
}
} yield ExitCode.Success
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.avast.metrics.scalaeffectapi

import com.avast.metrics.scalaapi.Metric

trait Counter[F[_]] extends Counting[F] with Metric {
def inc: F[Unit]
def inc(n: Long): F[Unit]
def dec: F[Unit]
def dec(n: Int): F[Unit]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.avast.metrics.scalaeffectapi

trait Counting[F[_]] {
def count: F[Long]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.avast.metrics.scalaeffectapi

import com.avast.metrics.scalaapi.Metric

trait Gauge[F[_], T] extends Metric {
def value: F[T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.avast.metrics.scalaeffectapi

import com.avast.metrics.scalaapi.Metric

trait Histogram[F[_]] extends Metric {
def update(value: Long): F[Unit]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.avast.metrics.scalaeffectapi

import com.avast.metrics.scalaapi.Metric

trait Meter[F[_]] extends Counting[F] with Metric {
def mark: F[Unit]
def mark(n: Long): F[Unit]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.avast.metrics.scalaeffectapi

import cats.effect.Sync
import com.avast.metrics.api.{Monitor => JMonitor, Naming}
import com.avast.metrics.scalaapi.{Monitor => SMonitor}
import com.avast.metrics.test.NoOpMonitor

trait Monitor[F[_]] extends AutoCloseable {
def named(name: String): Monitor[F]
def named(name1: String, name2: String, restOfNames: String*): Monitor[F]
def getName: String
def meter(name: String): Meter[F]
def counter(name: String): Counter[F]
def timer(name: String): Timer[F]
def timerPair(name: String): TimerPair[F]
def histogram(name: String): Histogram[F]

def gauge: GaugeFactory[F]

def asJava: JMonitor
def asPlainScala: SMonitor
}

object Monitor {

def wrapJava[F[_]: Sync](monitor: JMonitor): Monitor[F] = wrapJava(monitor, Naming.defaultNaming())
def wrapJava[F[_]: Sync](monitor: JMonitor, naming: Naming): Monitor[F] = wrap(SMonitor(monitor), naming)

def wrap[F[_]: Sync](monitor: SMonitor): Monitor[F] = wrap(monitor, Naming.defaultNaming())
def wrap[F[_]: Sync](monitor: SMonitor, naming: Naming): Monitor[F] = new impl.MonitorImpl(monitor, naming)

def noOp[F[_]: Sync](): Monitor[F] = {
wrapJava(NoOpMonitor.INSTANCE)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.avast.metrics.scalaeffectapi

trait SettableGauge[F[_], T] extends Gauge[F, T] {
def set(value: T): F[Unit]
def update(f: T => T): F[T]
def inc: F[T]
def dec: F[T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.avast.metrics.scalaeffectapi

import java.time.{Duration => JDuration}
import scala.concurrent.duration.Duration

trait Timer[F[_]] {
trait TimeContext extends AutoCloseable {
def stop: F[Duration]
}

def start: F[TimeContext]
def update(duration: JDuration): F[Unit]
def update(duration: Duration): F[Unit]
def time[A](block: F[A]): F[A]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.avast.metrics.scalaeffectapi

import java.time.{Duration => JDuration}
import scala.concurrent.duration.Duration

trait TimerPair[F[_]] {
trait TimerPairContext extends AutoCloseable {
def stop: F[Duration]
def stopFailure: F[Duration]
}

def start: F[TimerPairContext]
def update(duration: JDuration): F[Unit]
def updateFailure(duration: JDuration): F[Unit]
def update(duration: Duration): F[Unit]
def updateFailure(duration: Duration): F[Unit]
def time[T](action: F[T]): F[T]
def time[T](action: F[T])(successCheck: T => Boolean): F[T]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.avast.metrics.scalaeffectapi.impl

import cats.effect.Sync
import com.avast.metrics.scalaapi.{Counter => SCounter}
import com.avast.metrics.scalaeffectapi.Counter

private class CounterImpl[F[_]: Sync](inner: SCounter) extends Counter[F] {
override def inc: F[Unit] = Sync[F].delay(inner.inc())

override def inc(n: Long): F[Unit] = Sync[F].delay(inner.inc(n))

override def dec: F[Unit] = Sync[F].delay(inner.dec())

override def dec(n: Int): F[Unit] = Sync[F].delay(inner.dec(n))

override def count: F[Long] = Sync[F].delay(inner.count)

override def name: String = inner.name
}
Loading

0 comments on commit 229436c

Please sign in to comment.