SENDLINE open source
open source / metrics4s / recording

Recording

Metrics[F].register(definition) gives an instrument, and registerAll gives a tuple of them. If one registration in the tuple fails, the ones already done are unregistered. Failures are a MetricException carrying a MetricError, raised in F.

scala
counter.inc(Outcome.Ok)                    // F[Unit]
counter.add(Outcome.Skipped, 5)
total.inc()                                // a metric without labels
gauge.set(Outcome.Ok, 42)
inFlight.inc(Outcome.Ok); inFlight.dec(Outcome.Ok)
gauge.replace(Map(Outcome.Ok -> 3))        // the rest goes to 0, or is removed when the label is bounded
histogram.observe(Outcome.Ok, 250.millis)
histogram.timed(Outcome.Ok)(fa)            // a success and a failure are recorded, a cancellation is not
histogram.timedBy(fa)(result => if result.isRight then Outcome.Ok else Outcome.Error)
counter.unsafe.inc(Outcome.Ok)             // Unit, for code outside F: driver listeners, interceptors
counter.unregister

registerAs registers a named tuple of definitions into a case class, so the instruments travel by name, not by position. Each name must be a field of the class, in its order, and each field must have the type of the instrument its definition registers as. Anything else does not compile:

scala
final case class Processing(processed: CounterOf[IO, Long, Outcome], processTime: HistogramOf[IO, FiniteDuration, NoLabels])

Metrics[IO].registerAs[Processing]((processed = ProcessorMetrics.processed, processTime = ProcessorMetrics.processTime))

Measured times an operation and counts it by outcome in one call, the RED pattern. The histogram carries the operation's labels, the counter carries those labels and the outcome, and the last argument builds the counter's labels from both:

scala
val fetch = Measured(fetchTime, fetches, FetchOutcome.Failed)((labels, outcome) => (source = labels.source, outcome = outcome))

fetch.measure((source = Source.Kafka))(repository.find(id))(found => if found.isDefined then FetchOutcome.Found else FetchOutcome.Missing)

The outcome of a value comes from the function. An error is counted as Failed and re-raised as it was, the same instance, so the metric cannot turn a failure into a value. A cancellation records nothing. If the recording itself fails while the operation failed, the operation's error is still the one raised, with the other suppressed in it.

An info carries facts rather than a number: the build's version, the stage, a configuration. Its series is always 1, and its labels are what the dashboard shows. set replaces the previous labels, so a copy shows one series:

scala
val build = Info("processor_build", "The build that runs").labelled[(version: Version, stage: Stage)]

Metrics[IO].register(build).flatMap(_.set((version = Version(BuildInfo.version), stage = Stage.Prod)))

A version is not enumerable, so it is LabelValue.bounded. Stat.info(build)(_.version) shows it on a dashboard.

For an enumerated label an update is an array read: faster than the raw client, see BENCHMARKS.md.

built from README.md at v0.2.0 edit this page on GitHub