Metrics

Introduction

You can think of metrics as a stream of tiny, time-stamped events, that flow into a special kind of database, organized to efficiently query such a stream, and aggregate the results in multiple useful ways. A full explanation of metrics is beyond the scope of this document, however.

Metrics are a key part of observability, the ability to see how your application, running as tens or hundreds (or thousands) of servers, is operating as a whole. Where logging can give you information about a specific request, and can somewhat grudgingly aggregate data together - metrics services such as Prometheus exist to aggregate vast amounts of data points together, and give you the ability to see what’s happening to your application now, or over time, broken up by any number of dimensions. Dimensions are used to select events by application-supplied values, that can include such things as the server’s hostname, a request’s URI, the environment (staging vs. production), or the AWS region.

At the core, your application will include extra code to emit metrics; depending on the underlying metrics service you are using, these are either stored in-memory until scraped by another collecting service, or pushed to the collecting service at intervals.

Pedestal’s default metrics library is DropWizard, and the default configuration stores the results internally in JMX.

API

The metrics functions are defined in the io.pedestal.log namespace, along with supporting protocols and utility functions.

Generally, there is no need to define a metric before using it; it will be registered or created, from its name, automatically when first used.

All of these metrics-producing functions have two forms: the canonical form accepts a recorder, the metric name, and additional arguments; the common form omits the recorder, and uses the default-recorder.

A metric name can be any object that can be converted to a string; usually a fully qualified symbol or keyword. For a keyword, the leading : stripped off.

counter

Counters are simply values that increase over time; the argument is a delta value, a long to increment the counter by.

A common counter metric might be the total number of requests processed.

gauge

Gauges are used to track a value that varies over time; a callback function is passed to the gauge function; this callback will be periodically invoked to return a value for the metric.

A common gauge metric might be the number of entries stored in a cache.

histogram

A histogram is somewhat like a gauge; it’s a value that varies over time. The difference is, you supply the values (there isn’t as callback) and the metrics that are produced are broken out in a number of ways: by min, max, mean, median, standard deviation, and by various percentiles.

A common histogram metric might be the latency of database reads or updates.

meter

Meters are used to track the rate at which operations occur.

meter is much like counter, it is invoked with a value indicating how many operations occurred (this value is typically 1). It produces moving averages for the one-, five-, and fifteen-minute rates based on sampling this value.

A common meter might be the number of total number of requests processed.

default-recorder

This is a var, not a function; it stores a recorder, an object that extends the MetricRecorder protocol; this is usually an instance of com.codahale.metrics.MetricRegistry.

By default, the registry is created via metric-registry, and uses a jmx-reporter to store metrics.

However, this can be overridden at application startup; the JVM system property io.pedestal.log.defaultMetricsRecorder or environment variable PEDESTAL_METRICS_RECORDER can specify the fully-qualified name of a function to invoke (with no arguments), that returns the default recorder.