Overview

The extruder metrics modules provide support for encoding case classes as name-spaced or dimensional metrics.

Metric Encoding

Exturder supports two types of metric encoding schemes, name-spaced and dimensional. Both are described below:

Name-spaced Metrics

Name-spaced metrics are most commonly associated with Graphite, where they are simple key values arranged in a hierarchy of common dot-seprated key elements.

Metrics are encoded using the path to the value in the case class structure e.g.

case class Test1(value: Int = 1000)
case class Test2(metrics: Test1)

Will be encoded as test2.metrics.test1.value = 1000.

Dimensional metrics

Dimensional metrics are most commonly associated with Prometheus where a metric has multiple labels which then may be queried in aggregate with other metrics which share the same dimensions.

Metrics in a case class can be encoded as follows, providing there is enough depth in the case class structure to be able to create dimensions:

case class StatusCode(`200`: Int = 2043, `500`: Int = 3, other: Int = 653)
case class RequestCount(httpRequests: StatusCode)

Will be encoded as:

{name=http_requests,status_code=200} = 2043
{name=http_requests,status_code=500} = 3
{name=http_requests,status_code=other} = 653

This allows you to aggregate all http_requests values by not including the status_code dimension in a query.

Alternatively if there is not enough depth in the case class structure then names will be encoded as the parameter names of the case class:

case class HttpResponses(`200Responses`: Int = 2043, `500Responses`: Int = 3, otherResponses: Int = 653)

Will be encoded as:

{name=200_responses,status_code=200} = 2043
{name=500_responses,status_code=500} = 3
{name=other_responses,status_code=other} = 653

If you don’t know the possible label values ahead of time it is possible to encode a map of string to number which represents each dimension value and its corresponding reading:

case class HttpRequests(statusCode: Map[String, Int] = Map("200" -> 2043, "500" -> 3, "401" -> 7643, "other" -> 12))

Will be encoded as:

{name=http_requests,status_code=200} = 2043
{name=http_requests,status_code=500} = 3
{name=http_requests,status_code=400} = 7643
{name=http_requests,status_code=other} = 12

Lack of depth

If your case class heirarchy is not deep enough, then extruder will encode the case class’s field names as metrics. For example:

case class StatusCode(`200`: Int = 2043, `500`: Int = 3, other: Int = 653)

Will be encoded as:

{name=200} = 2043
{name=500} = 3
{name=other} = 653

Additional dimensions

When instantiating an implementation of a dimensional metric encoder you may provide optional additional dimensions as a string map (Map[String, String]). This allows you to specify extra metadata such as hostname or job instance to every metric recorded.

Encoding and compilation

Note that dimensional metric encoders will fail to compile case classes which cannot be properly represented as dimensional metrics, i.e. any case class whose fields would be encoded as separate labels would not compile if those fields are not all the same type.

Metric Types

In order to encode a type of metric extruder includes a trait called MetricValue. Provided implementations include Counter, Gauge and Timer, each being a value class. A case class which uses these allows for fine grained control over the type of metric for each value.

To encode multiple dimensions in a Map, as covered above, the type MetricValues is provided, which is a value class class wrapper around Map[String, MetricValue[V]] where V has an implicit Numeric instance. An implicit monoid instance is also providied for this type.

For example it is possible to

import extruder.metrics.data.CounterValue
import extruder.metrics.conversions.counter._ //implicitly converts numbers to CounterValue

case class StatusCode(`200`: CounterValue[Int] = 2043, `500`: CounterValue[Int] = 3, other: CounterValue[Int] = 653)
case class RequestCount(httpRequests: StatusCode)

If you don’t wish to use MetricValue or MetricValues in your case classes, encoding will still work (as seen above), however the values will be encoded as the default metric type for the encoder.

Label Values

Any type which cannot be encoded as a numeric value can be encoded as a label where the value of the field will be included in the name of the metric and the metric value set to 1. For example, consider the following case class:

case class Stats(status: String = "OK")

Will be encoded as below in name-spaced metrics:

stats.status.OK = 1

Or in dimensional metrics:

{status=OK} = 1

Provided Encoders

Extruder currently provides three types of encoders, although anyone is welcome to add more:

Dropwizard

The Dropwizard package provides both name-spaced and dimensional metric encoders which records values in a Dropwizard metrics registry.

resolvers += Resolver.bintrayRepo("janstenpickle", "maven")
libraryDependencies += "io.extruder" %% "extruder-metrics-dropwizard" % "0.11.0"

Prometheus

The Prometheus package provides two dimensional metric encoders, one which records values in a Prometheus metrics registry and one which sends metrics to a Push Gateway.

resolvers += Resolver.bintrayRepo("janstenpickle", "maven")
libraryDependencies += "io.extruder" %% "extruder-metrics-prometheus" % "0.11.0"

Spectator

The Spectator package provides a dimensional metric encode which records in a Spectator metrics registry.

libraryDependencies += "io.extruder" %% "extruder-metrics-spectator" % "0.11.0"