Metrics computed from :telemetry events and kept in memory, for
export in the Prometheus text format with Sovite.Metrics.Prometheus.
children = [
{Sovite.Metrics,
name: MyApp.Metrics,
metrics: [
Sovite.Metrics.counter("smtp_commands_total",
event: [:sovite, :smtp, :server, :command, :stop],
tags: [:command],
help: "SMTP commands received."
),
Sovite.Metrics.distribution("smtp_command_duration_seconds",
event: [:sovite, :smtp, :server, :command, :stop],
measurement: :duration,
unit: {:native, :second},
buckets: [0.01, 0.1, 1, 10],
tags: [:command]
)
]}
]
MyApp.Metrics |> Sovite.Metrics.collect() |> Sovite.Metrics.Prometheus.format()There are four kinds of metric:
counter/2- the number of events. A Prometheus counter.sum/2- the sum of a measurement. A Prometheus counter.last_value/2- the latest value of a measurement. A Prometheus gauge.distribution/2- a measurement counted into buckets. A Prometheus histogram.
The process attaches a telemetry handler for each event the metrics name, and owns an ETS table with the values. Handlers run in the process that emits the event and update the table directly, so recording never waits on the process. An event a metric cannot use, such as one with its measurement missing or not a number, is skipped by that metric: the handler never raises, so telemetry never detaches it. Values are in memory: a restart starts from zero.
Each distinct combination of tag values is a series. A metric keeps at
most :max_series of them, so tag values from untrusted input cannot
grow memory without bound. Events for further combinations are not
recorded, and are counted in a sovite_metrics_dropped_series_total
counter with a metric label naming the metric. That family is only
reported once an event was dropped.
Collectors add families computed at collection time, such as the size of a queue:
collectors: [
fn ->
[%{name: "queue_messages", type: :gauge, help: "Queued messages.",
samples: [{%{"queue" => "deferred"}, MyApp.Queue.size(:deferred)}]}]
end
]Options
:name- an atom naming the process and its ETS table. Required.:metrics- metric definitions. Defaults to[].:collectors- 0-arity functions returning a list offamily/0, called bycollect/1in the calling process. A collector that raises or exits is skipped. Defaults to[].
Metric options
:event- the telemetry event name. Required.:measurement- the measurement key, or a 2-arity function given the measurements and metadata and returning a number ornil. Required, except for counters, which take none and count events.:tags- metadata keys whose values become labels, named after the key. Defaults to[].:tag_values- a 1-arity function given the metadata and returning the map tags are taken from, to derive labels. Defaults to the metadata itself.:keep- a 1-arity function given the metadata; events for which it does not returntrueare ignored. Defaults to keeping all.:help- the help text. Defaults tonil.:unit-{:native, unit}converts a measurement in:nativetime units, as telemetry spans report durations, to:second,:millisecondor:microsecond. Defaults tonil, no conversion.:buckets- for distributions, the ascending bucket upper bounds, in the converted unit. Required for distributions.:max_series- distinct label combinations kept. Defaults to 1000.
Label values are strings: binaries as they are (inspected if not
UTF-8), atoms and integers converted, nil empty, IP addresses in
their text form, and anything else inspected.
Summary
Types
A metric family. Counters and gauges have {labels, value} samples,
histograms {labels, histogram} ones.
A histogram sample: cumulative counts for each finite upper bound, the sum of the values, and their count.
Label names to label values.
A sample value. Collectors can also use the special values.
Functions
Returns the families of the metrics, in definition order, then the dropped series family if any, then the collectors' families.
Defines a counter of events. See the module docs for options.
Defines a histogram of a measurement. See the module docs for options.
Defines a gauge with the latest value of a measurement. See the module docs for options.
Clears all values, including dropped series counts.
Starts the metrics process. See the module docs for options.
Defines a counter summing a measurement. See the module docs for options.
Types
@type family() :: %{ name: String.t(), type: :counter | :gauge | :histogram, help: String.t() | nil, samples: [{labels(), value() | histogram()}] }
A metric family. Counters and gauges have {labels, value} samples,
histograms {labels, histogram} ones.
@type histogram() :: %{ buckets: [{number(), non_neg_integer()}], sum: value(), count: non_neg_integer() }
A histogram sample: cumulative counts for each finite upper bound, the sum of the values, and their count.
Label names to label values.
@type value() :: number() | :infinity | :neg_infinity | :nan
A sample value. Collectors can also use the special values.
Functions
Returns the families of the metrics, in definition order, then the dropped series family if any, then the collectors' families.
@spec counter(String.t(), keyword()) :: Sovite.Metrics.Metric.t()
Defines a counter of events. See the module docs for options.
@spec distribution(String.t(), keyword()) :: Sovite.Metrics.Metric.t()
Defines a histogram of a measurement. See the module docs for options.
@spec last_value(String.t(), keyword()) :: Sovite.Metrics.Metric.t()
Defines a gauge with the latest value of a measurement. See the module docs for options.
@spec reset(atom()) :: :ok
Clears all values, including dropped series counts.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the metrics process. See the module docs for options.
@spec sum(String.t(), keyword()) :: Sovite.Metrics.Metric.t()
Defines a counter summing a measurement. See the module docs for options.