Counter
Counter metric, to track counts, running totals, or events.
If your use case can go up or down consider using a Gauge
instead.
Use the rate()
function in Prometheus to calculate the rate of increase of a Counter.
By convention, the names of Counters are suffixed by _total
. This suffix is added to metric's name by underlying prometheus-metrics library, do not add it yourself.
A Counter
is a cumulative metric that represents a single monotonically increasing counter whose value can only increase or be reset to zero on restart. For example, you can use a counter to represent the number of requests served, tasks completed, or errors.
Do not use a counter to expose a value that can decrease. For example, do not use a counter for the number of currently running processes; instead use a gauge.
Imports
import io.chrisdavenport.epimetheus._
import cats.effect._
import cats.effect.unsafe.implicits.global
An Example Counter without Labels:
val noLabelsExample = {
for {
pr <- PrometheusRegistry.build[IO]
successCounter <- Counter.noLabels(
pr,
Name("example_success"),
"Example Counter of Success"
)
failureCounter <- Counter.noLabels(
pr,
Name("example_failure"),
"Example Counter of Failure"
)
_ <- IO(println("Action Here")).guaranteeCase{
case Outcome.Succeeded(_) => successCounter.inc
case _ => failureCounter.inc
}
out <- pr.write004
} yield out
}
// noLabelsExample: IO[String] = FlatMap(
// ioe = Delay(
// thunk = io.chrisdavenport.epimetheus.PrometheusRegistry$$$Lambda$11197/0x00007fa08dea8210@144f6d35,
// event = cats.effect.tracing.TracingEvent$StackTrace
// ),
// f = <function1>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
noLabelsExample.unsafeRunSync()
// Action Here
// res0: String = """# HELP example_failure_total Example Counter of Failure
// # TYPE example_failure_total counter
// example_failure_total 0.0
// # HELP example_success_total Example Counter of Success
// # TYPE example_success_total counter
// example_success_total 1.0
// """
An Example of a Counter with Labels:
val labelledExample = {
for {
pr <- PrometheusRegistry.build[IO]
counter <- Counter.labelled(
pr,
Name("example"),
"Example Counter",
Sized(Label("foo")),
{s: String => Sized(s)}
)
_ <- counter.label("bar").inc
_ <- counter.label("baz").inc
out <- pr.write004
} yield out
}
// labelledExample: IO[String] = FlatMap(
// ioe = Delay(
// thunk = io.chrisdavenport.epimetheus.PrometheusRegistry$$$Lambda$11197/0x00007fa08dea8210@73a88a1b,
// event = cats.effect.tracing.TracingEvent$StackTrace
// ),
// f = <function1>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
labelledExample.unsafeRunSync()
// res1: String = """# HELP example_total Example Counter
// # TYPE example_total counter
// example_total{foo="bar"} 1.0
// example_total{foo="baz"} 1.0
// """
An Example of a Counter backed algebra.
sealed trait Foo; case object Bar extends Foo; case object Baz extends Foo;; case object Bar extends Foo; case object Baz extends Foo;; case object Baz extends Foo;;
def fooLabel(f: Foo) = {
f match {
case Bar => Sized("bar")
case Baz => Sized("baz")
}
}
trait FooAlg[F[_]]{
def bar: F[Unit]
def baz: F[Unit]
}; object FooAlg {; object FooAlg {
def impl[F[_]](c: Counter.UnlabelledCounter[F, Foo]) = new FooAlg[F]{
def bar: F[Unit] = c.label(Bar).inc
def baz: F[Unit] = c.label(Baz).inc
}
}
val fooAgebraExample = {
for {
pr <- PrometheusRegistry.build[IO]
counter <- Counter.labelled(
pr,
Name("example"),
"Example Counter",
Sized(Label("foo")),
fooLabel
)
foo = FooAlg.impl(counter)
_ <- foo.bar
_ <- foo.bar
_ <- foo.baz
out <- pr.write004
} yield out
}
// fooAgebraExample: IO[String] = FlatMap(
// ioe = Delay(
// thunk = io.chrisdavenport.epimetheus.PrometheusRegistry$$$Lambda$11197/0x00007fa08dea8210@4268b833,
// event = cats.effect.tracing.TracingEvent$StackTrace
// ),
// f = <function1>,
// event = cats.effect.tracing.TracingEvent$StackTrace
// )
fooAgebraExample.unsafeRunSync()
// res2: String = """# HELP example_total Example Counter
// # TYPE example_total counter
// example_total{foo="bar"} 2.0
// example_total{foo="baz"} 1.0
// """
We force labels to always match the same size. This will fail to compile.
def incorrectlySized[F[_]: Sync](pr: PrometheusRegistry[F]) = {
Counter.labelled(pr, Name("fail"), "Example Failure", Sized(Label("color"), Name("method")), {s: String => Sized(s)})
}