Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
janstenpickle committed Sep 5, 2023
1 parent e32fd26 commit 560d51f
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 144 deletions.
3 changes: 0 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ val Scala213 = "2.13.11"

val Cats = "2.10.0"

val CatsMtl = "1.3.0"

val CatsEffect = "3.5.1"

val Log4Cats = "2.6.0"
Expand All @@ -56,7 +54,6 @@ lazy val core = project
name := "prometheus4cats",
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % Cats,
"org.typelevel" %%% "cats-mtl" % CatsMtl,
"org.typelevel" %%% "cats-effect-kernel" % CatsEffect,
"org.typelevel" %%% "cats-effect" % CatsEffect % Test,
"org.typelevel" %% "cats-effect-testkit" % CatsEffect % Test,
Expand Down
133 changes: 95 additions & 38 deletions core/src/main/scala/prometheus4cats/Counter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,54 @@

package prometheus4cats

import cats.effect.kernel.Clock
import cats.syntax.flatMap._
import cats.syntax.foldable._
import cats.syntax.functor._
import cats.{Applicative, Contravariant, FlatMap, Functor, ~>}
import prometheus4cats.internal.{Neq, Refined}
import cats.{Applicative, Contravariant, FlatMap, Functor, Monad, ~>}
import prometheus4cats.internal.Refined.Regex
import prometheus4cats.internal.{Neq, Refined}

sealed abstract class Counter[F[_], -A, B] extends Metric[A] with Metric.Labelled[B] {
sealed abstract class Counter[F[_], A, B](
protected[prometheus4cats] val getPreviousExemplar: F[Option[Exemplar.Data]],
protected[prometheus4cats] val setPreviousExemplar: Exemplar.Data => F[Unit]
) extends Metric[A]
with Metric.Labelled[B] {
self =>

protected def incProvidedExemplarImpl(
labels: B,
exemplar: Option[Exemplar.Labels]
): F[Option[Exemplar.Data] => F[Unit]]
): F[Unit]

protected def incProvidedExemplarImpl(
n: A,
labels: B,
exemplar: Either[Option[Exemplar.Data] => F[Option[Exemplar.Labels]], Option[Exemplar.Labels]]
exemplar: Option[Exemplar.Labels]
): F[Unit]

def contramap[C](f: C => A): Counter[F, C, B] = new Counter[F, C, B] {
def contramap[C](f: C => A): Counter[F, C, B] = new Counter[F, C, B](getPreviousExemplar, setPreviousExemplar) {
override def incProvidedExemplarImpl(labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.incProvidedExemplarImpl(labels, exemplar)

override def incProvidedExemplarImpl(n: C, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.incProvidedExemplarImpl(f(n), labels, exemplar)
}

def contramapLabels[C](f: C => B): Counter[F, A, C] = new Counter[F, A, C] {
def contramapLabels[C](f: C => B): Counter[F, A, C] = new Counter[F, A, C](getPreviousExemplar, setPreviousExemplar) {
override def incProvidedExemplarImpl(labels: C, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.incProvidedExemplarImpl(f(labels), exemplar)
override def incProvidedExemplarImpl(n: A, labels: C, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.incProvidedExemplarImpl(n, f(labels), exemplar)
}

final def mapK[G[_]: Functor](fk: F ~> G): Counter[G, A, B] =
new Counter[G, A, B] {
new Counter[G, A, B](fk(getPreviousExemplar), ex => fk(setPreviousExemplar(ex))) {
override def incProvidedExemplarImpl(
labels: B,
exemplar: Option[Exemplar.Labels]
): G[Option[Exemplar.Data] => G[Unit]] =
fk(self.incProvidedExemplarImpl(labels, exemplar)).map(x => x.andThen(fk.apply))
): G[Unit] =
fk(self.incProvidedExemplarImpl(labels, exemplar))

override def incProvidedExemplarImpl(n: A, labels: B, exemplar: Option[Exemplar.Labels]): G[Unit] =
fk(self.incProvidedExemplarImpl(n, labels, exemplar))
Expand All @@ -66,14 +72,36 @@ sealed abstract class Counter[F[_], -A, B] extends Metric[A] with Metric.Labelle

object Counter {

implicit class CounterSyntax[F[_], -A](counter: Counter[F, A, Unit])(implicit
exemplarSampler: CounterExemplarSampler[F, A]
) {
final def inc: F[Unit] =
counter.incProvidedExemplarImpl((), Left((data: Option[Exemplar.Data]) => exemplarSampler.sample(data)))

final def inc(n: A): F[Unit] =
counter.incProvidedExemplarImpl((), Left((data: Option[Exemplar.Data]) => exemplarSampler.sample(n, data)))
implicit class CounterSyntax[F[_], A](counter: Counter[F, A, Unit]) {
final def inc: F[Unit] = incProvidedExemplar(None)

final def inc(n: A): F[Unit] = incProvidedExemplar(n, None)

final def incWithSampledExemplar(implicit
F: Monad[F],
clock: Clock[F],
exemplarSampler: CounterExemplarSampler[F, A]
): F[Unit] =
for {
previous <- counter.getPreviousExemplar
next <- exemplarSampler.sample(previous)
_ <- incProvidedExemplar(next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => counter.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def incWithSampledExemplar(
n: A
)(implicit F: Monad[F], clock: Clock[F], exemplarSampler: CounterExemplarSampler[F, A]): F[Unit] =
for {
previous <- counter.getPreviousExemplar
next <- exemplarSampler.sample(previous)
_ <- incProvidedExemplar(n, next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => counter.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def incWithExemplar(implicit F: FlatMap[F], exemplar: Exemplar[F]): F[Unit] =
exemplar.get.flatMap(incProvidedExemplar)
Expand All @@ -82,20 +110,44 @@ object Counter {
exemplar.get.flatMap(incProvidedExemplar(n, _))

final def incProvidedExemplar(exemplar: Option[Exemplar.Labels]): F[Unit] =
counter.incProvidedExemplarImpl((), Right(exemplar))
counter.incProvidedExemplarImpl((), exemplar)
final def incProvidedExemplar(n: A, exemplar: Option[Exemplar.Labels]): F[Unit] =
counter.incProvidedExemplarImpl(n, (), Right(exemplar))
counter.incProvidedExemplarImpl(n, (), exemplar)
}

implicit class LabelledCounterSyntax[F[_], -A, B](counter: Counter[F, A, B])(implicit
ev: Unit Neq B,
exemplarSampler: CounterExemplarSampler[F, A]
implicit class LabelledCounterSyntax[F[_], A, B](counter: Counter[F, A, B])(implicit
ev: Unit Neq B
) {
final def inc(labels: B)(implicit F: FlatMap[F]): F[Unit] =
exemplarSampler.sample.flatMap(incProvidedExemplar(labels, _))

final def inc(n: A, labels: B)(implicit F: FlatMap[F]): F[Unit] =
exemplarSampler.sample(n).flatMap(incProvidedExemplar(n, labels, _))
final def inc(labels: B): F[Unit] = incProvidedExemplar(labels, None)

final def inc(n: A, labels: B): F[Unit] = incProvidedExemplar(n, labels, None)

final def incWithSampledExemplar(labels: B)(implicit
F: Monad[F],
clock: Clock[F],
exemplarSampler: CounterExemplarSampler[F, A]
): F[Unit] =
for {
previous <- counter.getPreviousExemplar
next <- exemplarSampler.sample(previous)
_ <- incProvidedExemplar(labels, next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => counter.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def incWithSampledExemplar(
n: A,
labels: B
)(implicit F: Monad[F], clock: Clock[F], exemplarSampler: CounterExemplarSampler[F, A]): F[Unit] =
for {
previous <- counter.getPreviousExemplar
next <- exemplarSampler.sample(previous)
_ <- incProvidedExemplar(n, labels, next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => counter.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def incWithExemplar(labels: B)(implicit F: FlatMap[F], exemplar: Exemplar[F]): F[Unit] =
exemplar.get.flatMap(incProvidedExemplar(labels, _))
Expand Down Expand Up @@ -129,10 +181,12 @@ object Counter {
}

def make[F[_], A, B](
getPreviousExemplar: F[Option[Exemplar.Data]],
setPreviousExemplar: Exemplar.Data => F[Unit],
default: A,
_inc: (A, B, Either[Option[Exemplar.Data] => F[Option[Exemplar.Labels]], Option[Exemplar.Labels]]) => F[Unit]
_inc: (A, B, Option[Exemplar.Labels]) => F[Unit]
): Counter[F, A, B] =
new Counter[F, A, B] {
new Counter[F, A, B](getPreviousExemplar, setPreviousExemplar) {
override def incProvidedExemplarImpl(labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
_inc(default, labels, exemplar)

Expand All @@ -141,18 +195,21 @@ object Counter {
}

def make[F[_], A, B](
_inc: (A, B, Either[Option[Exemplar.Data] => F[Option[Exemplar.Labels]], Option[Exemplar.Labels]]) => F[Unit]
getPreviousExemplar: F[Option[Exemplar.Data]],
setPreviousExemplar: Exemplar.Data => F[Unit],
_inc: (A, B, Option[Exemplar.Labels]) => F[Unit]
)(implicit
A: Numeric[A]
): Counter[F, A, B] =
make(A.one, _inc)
make(getPreviousExemplar, setPreviousExemplar, A.one, _inc)

def noop[F[_]: Applicative, A, B]: Counter[F, A, B] = new Counter[F, A, B] {
override def incProvidedExemplarImpl(labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
Applicative[F].unit
def noop[F[_]: Applicative, A, B]: Counter[F, A, B] =
new Counter[F, A, B](Applicative[F].pure(None), _ => Applicative[F].unit) {
override def incProvidedExemplarImpl(labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
Applicative[F].unit

override def incProvidedExemplarImpl(n: A, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
Applicative[F].unit
}
override def incProvidedExemplarImpl(n: A, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
Applicative[F].unit
}

}
39 changes: 19 additions & 20 deletions core/src/main/scala/prometheus4cats/ExemplarSampler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,42 @@ package prometheus4cats
import cats.Applicative
import cats.data.NonEmptySeq

trait CounterExemplarSampler[F[_], A] {
trait CounterExemplarSampler[F[_], -A] {
def sample(previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]]
def sample(value: A, previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]]
}

object CounterExemplarSampler extends Implicits {
object CounterExemplarSampler extends Common {
def apply[F[_], A](implicit sampler: CounterExemplarSampler[F, A]): CounterExemplarSampler[F, A] = implicitly
}

trait HistogramExemplarSampler[F[_], A] {
def sample(value: A, buckets: NonEmptySeq[A], previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]]
trait HistogramExemplarSampler[F[_], -A] {
def sample(value: A, buckets: NonEmptySeq[Double], previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]]
}

object HistogramExemplarSampler extends Implicits {
object HistogramExemplarSampler extends Common {
def apply[F[_], A](implicit sampler: HistogramExemplarSampler[F, A]): HistogramExemplarSampler[F, A] = implicitly
}

trait ExemplarSampler[F[_], A] extends CounterExemplarSampler[F, A] with HistogramExemplarSampler[F, A]
trait ExemplarSampler[F[_], -A] extends CounterExemplarSampler[F, A] with HistogramExemplarSampler[F, A]

object ExemplarSampler extends Implicits {
object ExemplarSampler extends Common {
def apply[F[_], A](implicit sampler: ExemplarSampler[F, A]): ExemplarSampler[F, A] = implicitly
}

trait Implicits extends LowPriorityImplicits0 {}
trait Common {
object Implicits {
implicit def noop[F[_]: Applicative, A]: ExemplarSampler[F, A] = new ExemplarSampler[F, A] {
override def sample(previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]] = Applicative[F].pure(None)

trait LowPriorityImplicits0 {
implicit def default[F[_]: Applicative, A]: ExemplarSampler[F, A] = new ExemplarSampler[F, A] {
override def sample(
value: A,
buckets: NonEmptySeq[A],
previous: Option[Exemplar.Data]
): F[Option[Exemplar.Labels]] =
Applicative[F].pure(None)
override def sample(value: A, previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]] =
Applicative[F].pure(None)

override def sample(value: A, previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]] =
Applicative[F].pure(None)

override def sample(previous: Option[Exemplar.Data]): F[Option[Exemplar.Labels]] = Applicative[F].pure(None)
override def sample(
value: A,
buckets: NonEmptySeq[Double],
previous: Option[Exemplar.Data]
): F[Option[Exemplar.Labels]] = Applicative[F].pure(None)
}
}
}
59 changes: 46 additions & 13 deletions core/src/main/scala/prometheus4cats/Histogram.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,38 @@
package prometheus4cats

import cats.data.NonEmptySeq
import cats.effect.kernel.Clock
import cats.syntax.flatMap._
import cats.{Applicative, Contravariant, FlatMap, ~>}
import cats.syntax.foldable._
import cats.syntax.functor._
import cats.{Applicative, Contravariant, FlatMap, Monad, ~>}
import prometheus4cats.internal.{Neq, Refined}
import prometheus4cats.internal.Refined.Regex

sealed abstract class Histogram[F[_], -A, B] extends Metric[A] with Metric.Labelled[B] {
sealed abstract class Histogram[F[_], A, B](
protected[prometheus4cats] val buckets: NonEmptySeq[Double],
protected[prometheus4cats] val getPreviousExemplar: F[Option[Exemplar.Data]],
protected[prometheus4cats] val setPreviousExemplar: Exemplar.Data => F[Unit]
) extends Metric[A]
with Metric.Labelled[B] {
self =>

protected def observeProvidedExemplarImpl(n: A, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit]

def contramap[C](f: C => A): Histogram[F, C, B] = new Histogram[F, C, B] {
override def observeProvidedExemplarImpl(n: C, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.observeProvidedExemplarImpl(f(n), labels, exemplar)
}
def contramap[C](f: C => A): Histogram[F, C, B] =
new Histogram[F, C, B](buckets, getPreviousExemplar, setPreviousExemplar) {
override def observeProvidedExemplarImpl(n: C, labels: B, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.observeProvidedExemplarImpl(f(n), labels, exemplar)
}

def contramapLabels[C](f: C => B): Histogram[F, A, C] = new Histogram[F, A, C] {
override def observeProvidedExemplarImpl(n: A, labels: C, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.observeProvidedExemplarImpl(n, f(labels), exemplar)
}
def contramapLabels[C](f: C => B): Histogram[F, A, C] =
new Histogram[F, A, C](buckets, getPreviousExemplar, setPreviousExemplar) {
override def observeProvidedExemplarImpl(n: A, labels: C, exemplar: Option[Exemplar.Labels]): F[Unit] =
self.observeProvidedExemplarImpl(n, f(labels), exemplar)
}

final def mapK[G[_]](fk: F ~> G): Histogram[G, A, B] =
new Histogram[G, A, B] {
new Histogram[G, A, B](buckets, fk(getPreviousExemplar), ex => fk(setPreviousExemplar(ex))) {
override def observeProvidedExemplarImpl(n: A, labels: B, exemplar: Option[Exemplar.Labels]): G[Unit] =
fk(self.observeProvidedExemplarImpl(n, labels, exemplar))
}
Expand All @@ -47,19 +57,42 @@ sealed abstract class Histogram[F[_], -A, B] extends Metric[A] with Metric.Label

object Histogram {

implicit class HistogramSyntax[F[_], -A](histogram: Histogram[F, A, Unit]) {
implicit class HistogramSyntax[F[_], A](histogram: Histogram[F, A, Unit]) {
final def observe(n: A): F[Unit] = observeProvidedExemplar(n, None)

final def observeWithSampledExemplar(
n: A
)(implicit F: Monad[F], clock: Clock[F], exemplarSampler: HistogramExemplarSampler[F, A]): F[Unit] = for {
previous <- histogram.getPreviousExemplar
next <- exemplarSampler.sample(n, histogram.buckets, previous)
_ <- observeProvidedExemplar(n, next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => histogram.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def observeWithExemplar(n: A)(implicit F: FlatMap[F], exemplar: Exemplar[F]): F[Unit] =
exemplar.get.flatMap(observeProvidedExemplar(n, _))

final def observeProvidedExemplar(n: A, exemplar: Option[Exemplar.Labels]): F[Unit] =
histogram.observeProvidedExemplarImpl(n = n, labels = (), exemplar = exemplar)
}

implicit class LabelledCounterSyntax[F[_], -A, B](histogram: Histogram[F, A, B])(implicit ev: Unit Neq B) {
implicit class LabelledCounterSyntax[F[_], A, B](histogram: Histogram[F, A, B])(implicit ev: Unit Neq B) {
final def observe(n: A, labels: B): F[Unit] = observeProvidedExemplar(n, labels, None)

final def observeWithSampledExemplar(
n: A,
labels: B
)(implicit F: Monad[F], clock: Clock[F], exemplarSampler: HistogramExemplarSampler[F, A]): F[Unit] = for {
previous <- histogram.getPreviousExemplar
next <- exemplarSampler.sample(n, histogram.buckets, previous)
_ <- observeProvidedExemplar(n, labels, next)
_ <- next.traverse_(labels =>
Clock[F].realTimeInstant.flatMap(time => histogram.setPreviousExemplar(Exemplar.Data(labels, time)))
)
} yield ()

final def observeWithExemplar(n: A, labels: B)(implicit F: FlatMap[F], exemplar: Exemplar[F]): F[Unit] =
exemplar.get.flatMap(observeProvidedExemplar(n, labels, _))

Expand Down
Loading

0 comments on commit 560d51f

Please sign in to comment.