Metric Factory
The MetricFactory
creates an entrypoint to the Metric DSL from an instance of
MetricRegistry
, with the option of also creating from a CallbackRegistry
.
The following examples assume that you have the following imports in scope and that you have constructed a
MetricRegistry
and CallbackRegistry
.
import cats.effect._
import prometheus4cats._
val metricRegistry: MetricRegistry[IO] = MetricRegistry.noop[IO]
val callbackRegistry: CallbackRegistry[IO] = CallbackRegistry.noop[IO]
val registry: MetricRegistry[IO] with CallbackRegistry[IO] = null
MetricFactory
or MetricFactory.WithCallbacks
There are two variants of Metric Factory: MetricFactory
and MetricFactory.WithCallbacks
, the latter extending and
providing the same functionality as the former but with the ability to pass callbacks to the
DSL.
Whether you are able to obtain a MetricFactory.WithCallbacks
depends on two things:
- Whether you have an implementation
CallbackRegistry
available - How you may have transformed the effect type of
MetricsFactory.WithCallbacks
Constructing a No-op MetricFactory
For testing purposes it is possible to construct a MetricFactory
that create metrics who perform no operations.
To obtain a no-op instance use the snippet below:
MetricFactory.noop[IO]
A no-op MetricsFactory.WithCallabacks
can be obtained via either of the methods shown below:
MetricFactory.WithCallbacks.noop[IO]
MetricFactory.builder.noop[IO]
Constructing from a MetricRegistry
MetricRegistry
provides a builder with a fluent API that allows you to create an instance that adds an optional
prefix and/or common label set to all metrics.
MetricFactory
.builder
.build(metricRegistry)
Literal prefixes are checked at compile time to ensure they conform to the OpenMetrics format. Alternatively you may
provide an instance of Metric.Prefix
that has been refined at runtime.
MetricFactory
.builder
.withPrefix("app_name")
.build(metricRegistry)
Common labels are a set of labels that are checked at runtime so that the label names conform to the OpenMetrics
format and no more than ten are defined at any one time, which helps to reduce cardinality.
There is no compile time checking of these labels as it is assumed they will come from the runtime environment.
val commonLabels: Either[String, Metric.CommonLabels] =
Metric.CommonLabels.ofStrings("name" -> "value")
commonLabels.map { labels =>
MetricFactory
.builder
.withCommonLabels(labels)
.build(metricRegistry)
}
Constructing from a CallbackRegistry
To construct with a CallbackRegistry
you also need a MetricRegistry
, these may be separate or the same class.
The same builder is used as above, but the type of metrics factory built will be a MetricsFactory.WithCallbacks
if
you provide a CallbackRegistry
:
MetricFactory
.builder
.build(metricRegistry, callbackRegistry)
Alternatively:
MetricFactory
.builder
.build(registry)
As above, you may add CommonLabels
and a Prefix
as you see fit.
Changing a MetricFactory
It is possible to obtain a new instance of a MetricFactory
from an existing one with a different/no prefix or
common labels.
The snippet below showcases all the syntax for modifying MetricFactory
:
val newCommonLabels: Either[String, Metric.CommonLabels] =
Metric.CommonLabels.ofStrings("name2" -> "value2")
newCommonLabels.map { labels =>
MetricFactory
.builder
.build(metricRegistry)
.dropPrefix
.withPrefix("different_prefix")
.dropCommonLabels
.withCommonLabels(labels)
}
Transforming the Effect Type (mapK
)
You may transform the effect type (F
) of a MetricsFactory
with a
Cats natural transformation (~>
).
MetricsFactory
provides a mapK
method to do this, while MetricsFactory.WithCallbacks
provides an imapK
method,
mapK
is also available on MetricsFactory.WithCallbacks
as it extends MetricsFactory
, but you will only ever get a
MetricsFactory
when calling mapK
, whereas imapK
will yield MetricsFactory.WithCallbacks
. This is due to the
nature of a callback needing to be run in the original effect to retrieve the metric value.
import cats.~>
import cats.data.EitherT
type F[A] = IO[A]
type G[A] = EitherT[IO, Throwable, A]
val fk: F ~> G = EitherT.liftK[F, Throwable]
val gk: G ~> F = new (G ~> F) {
def apply[A](fa: G[A]): F[A] = fa.rethrowT
}
val factoryWithCallbacksF = MetricFactory.builder.build(metricRegistry, callbackRegistry)
val factoryG = factoryWithCallbacksF.mapK(fk)
val factoryWithCallbacksG = factoryWithCallbacksF.imapK(fk, gk)
It is also possible to construct a MetricsFactory.WithCallbacks
from a MetricsFactory
and CallbackRegistry
:
val callbackRegistryG: CallbackRegistry[G] = CallbackRegistry.noop[G]
MetricFactory.builder.build(factoryG, callbackRegistryG)