Metric...llector(3pm)

πŸ’– Metrics::Any::Collector(3pm) πŸ’–

okay bestie, sit down, hydrate, because today we're reading Metrics::Any::Collector(3pm) β€” from the User Contributed Perl Documentation section, no less. it's the module-side of the monitoring metrics reporting API and honestly? it's giving infrastructure queen. πŸ‘‘


✨ NAME ✨

Metrics::Any::Collector β€” the module-side of the monitoring metrics reporting API. that's it. that's the whole name. iconic.


🌸 SYNOPSIS 🌸

use Metrics::Any '$metrics',
   strict => 0,
   name_prefix => [ 'my_module_name' ];

sub do_thing {
   $metrics->inc_counter( 'things_done' );
}

like. look at it. you get yourself a $metrics handle and then you just... report stuff. it's giving effortless. πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

so instances of this class are literally the API that individual modules use to declare metadata about the metrics they're gonna report, and then to actually report individual values or observations on those metrics. you get one of these instances for your reporting module through the use Metrics::Any statement. one handle, one module, very demure.

the collector is basically a proxy for whatever Metrics::Any::Adapter instance the application has configured. it's a middleman. a liaison. a girl who knows a girl. πŸ’

here's the slay part: the proxy will lazily create an adapter only when it's actually required to report a metric value for the first time. until that moment, any metadata you've stored using the make_* methods just... sits there. it does not create an adapter. it's not rushing. it's waiting for the right moment.

and this lazy deferral is lowkey genius because it gives you flexibility with module load order and application startup. if you carefully write your module code so it doesn't report any metric values until the main activity has actually begun, you can let programs configure their metric reporting in a super flexible way during program startup. no cap. ✨

🌈 Batch-Mode Reporting 🌈

some adapters might support an optional API for doing metrics in a more high-performance manner. this is for low-level code β€” maybe even XS code β€” that gets invoked at high speed or like, a gazillion times over. ⚑

that kind of code often needs to keep simple counters of particular events that happen a lot. and rather than eating the cost of a full stack of method calls into the collector and adapter implementation on every single event (😭), the instrumented code can register a callback function that the adapter will call on some schedule, and that callback reports the actual metrics.

in the meantime? the instrumented code maintains its own counters of events, using plain Perl scalars (or native integers if you're in XS code), and reports them in bulk when required. this reduces the overall CPU cost involved in collecting metrics. efficiency era. 🧚

this is most effective with pull-based adapters like Test or Prometheus, where the callback might only need to be invoked at the end of a test run, or when the prometheus server polls the /metrics HTTP endpoint.

my $evcounter = 0;

$metrics->add_batch_mode_callback( sub {
   $metrics->inc_counter_by( events => $evcounter );
   $evcounter = 0;
} );

sub do_thing {
   $evcounter++;
   ...
}

but listen β€” because not every adapter may implement this mode, your instrumented code should be prepared to fall back on the regular API to report its counters. always have a plan B bestie.

my $evcounter = 0;

my $use_batch = $metrics->add_batch_mode_callback( sub {
   $metrics->inc_counter_by( events => $evcounter );
   $evcounter = 0;
} );

sub do_thing {
   $use_batch ? $evcounter++ : $metrics->inc_counter( events => );
   ...
}

each adapter implementation should document if and how it handles batch mode. that's on them, not on you. 🫢


πŸ’œ ENVIRONMENT πŸ’œ

METRICS_ANY_DISABLE

Since version 0.07.

gives you a list of packages and namespaces where Metrics::Any reporting is disabled entirely. like a do-not-disturb but for metrics.

this variable takes a comma-separated list of name patterns. patterns may end with ::*, and in that case they'll match any package whose name starts with that prefix. or they can just be literal package names, plain and simple. if any code in matching packages tries to use Metrics::Any::Collector to report metrics, that code gets handed a Null adapter, and no metrics will be reported from there. nothing. silence. peace. 😌

for example, to disable the metrics that Net::Async::HTTP::Server itself creates when exporting Prometheus metrics:

$ METRICS_ANY_DISABLE=Net::Async::HTTP::Server ./program.pl

πŸŽ€ ARGUMENTS πŸŽ€

name_prefix

Since version 0.05.

optional prefix to prepend to any name you provide to the make_* functions.

⚠️ and here's the catch bestie: if you set this, then this value and the registered names must be given as array references, not simple strings. no shortcuts.

use Metrics::Any '$metrics', name_prefix => [qw( my_program_name )];

$metrics->make_counter( events =>
   name => [ "events" ],
);

# Will create a counter named ["my_program_name", "events"] formed by the
# adapter.

see how the name comes out all nicely prefixed? that's the vibe. ✨

strict

Since version 0.05.

optional boolean that controls one very important question: do metrics have to be registered by a make_ method before you can use them (when true), or do we attempt to lazily register them the first time a reporting method stumbles into them (when false)?

when strict mode is off and a reporting method (e.g. inc_counter) gets invoked on an unrecognised handle, it will be lazily registered. and if the metric is reported with values, an attempt is made to figure out what the list of label names is β€” which depends on the form you gave the label values in. so:

  • labels passed by array reference, or by hash reference for a single label β€” works fine. πŸ’…
  • a hash reference passed with multiple keys β€” a warning is printed that the order may not be reliable. πŸ™ˆ
  • and finally, for the (discouraged, don't do it, i'm serious) flat lists of values given directly β€” it is not possible to recover label name information, so an exception is thrown. πŸ’€

for this reason, when you're operating with strict mode off, it is recommended to always use the array reference form of supplying labels, so they get registered correctly. just do it. it costs you nothing.

in the current version, this parameter defaults to true, which means all metrics must be registered in advance. this may change in a future version for convenience in smaller modules, so paranoid authors should set it explicitly:

use Metrics::Any::Adapter '$metrics', strict => 1;

and if strict mode is switched off, it's recommended to set a name prefix so your lazily-registered metrics at least have a useful name. otherwise they're just anonymous little guys floating around. 🌸


πŸ‘‘ BOOLEAN OVERRIDE πŸ‘‘

instances of this class override boolean truth testing. yes really. they're usually true, except in the case where an adapter has already been created and it happens to be the Null type.

this lets modules efficiently test whether to report metrics at all, using code such as:

if( $metrics ) {
   $metrics->inc_counter( name => some_expensive_function() );
}

now, the Null adapter will simply ignore any of the methods invoked on it. but without this conditional test, the caller would still have to calculate the value that isn't even going to be used. 😭 this structure lets the calculation be avoided entirely if metrics aren't in use. main character energy: don't do work nobody asked for. πŸ’…


πŸ”₯ METHODS πŸ”₯

package

$package = $metrics->package

returns the package name that created the collector β€” aka the package in which the

use Metrics::Any '$metrics';

statement was invoked. it's the origin story. the birth certificate. πŸ“œ

add_batch_mode_callback

$ok = $metrics->add_batch_mode_callback( sub { ... } )
Since version 0.09.

if batch mode is supported on the underlying adapter, this adds another callback to its list of callbacks, to be invoked when it wishes to collect more metrics. and if that's supported, then the method returns a true value. πŸŽ‰

if batch mode is not supported, it returns false. that's it. that's the whole deal. no drama, just a boolean.


✨ METRIC TYPES ✨

Okay so bestie, every metric type is born from one of the make_* methods, and they all take the same common args. Let's get into it. πŸ’–

  • name => ARRAY[ STRING ] | STRING β€” Optional. It's either an array of string parts, or a plain string name to use for reporting this metric to its upstream service.

Modules should preferably use an array of string parts to specify their metric names, because different adapter types may have different ways to represent this hierarchially. Base-level parts of the name should come first, followed by more specific parts. It is common for related metrics to be grouped by name having identical prefixes but differing only in the final part.

The name is optional; if unspecified then the handle will be used to form the name, combined with a "name_prefix" argument if one was set for the package.

  • description => STRING β€” Optional human-readable description. May be used for debugging or other purposes.
  • labels => ARRAY[ STRING ] β€” Optional reference to an array of string names to use as label names.

A labelled metric will expect to receive additional information in its reporting method to give values for these labels. This information should be in either an even-length array reference of name/value pairs, or a hash reference. E.g.

$metrics->inc_counter( handle => [ labelname => $labelvalue ] );
$metrics->inc_counter( handle => { labelname => $labelvalue } );

A legacy form where a plain list of values is passed, each corresponding to a named label in the same order, is currently accepted but discouraged in favour of the above forms.

$metrics->inc_counter( handle => $labelvalue );

Note that not all metric reporting adapters may be able to represent all of the labels. Each should document what its behaviour will be.


Counter πŸ’…

The make_counter method creates a new metric which counts occurrences of some event within the application. Its value begins at zero, and can be incremented by inc_counter whenever the event occurs.

Some counters may simply count occurrences of events, while others may count in other units, for example counts of bytes. Adapters may make use of the units parameter of the distribution to perform some kind of adapter-specific behaviour. The following units are suggested:

  • bytes β€” Observations give sizes in bytes (perhaps memory buffer or network message sizes), and should be integers.

make_counter

$collector->make_counter( $handle, %args )

Requests the creation of a new counter metric. The $handle name should be unique within the collector instance, though does not need to be unique across the entire program, as it will be namespaced by the collector instance.

The following extra arguments may be passed:

  • units => STRING β€” A hint to the adapter about what kind of measurements are being observed, so it might take specific behaviour.

inc_counter

$collector->inc_counter( $handle, $labels )

Reports that the counter metric value be incremented by one. The $handle name must match one earlier created by make_counter.

inc_counter_by

$collector->inc_counter_by( $handle, $amount, $labels )

Reports that a counter metric value be incremented by some specified value.


Distribution πŸ¦‹

The make_distribution method creates a new metric which counts individual observations of some numerical quantity (which may or may not be integral). New observations can be added by the report_distribution method.

Some adapter types may only store an aggregated total; others may store some sort of statistical breakdown, either total + count, or a bucketed histogram. The specific adapter documentation should explain how it handles distributions.

Adapters may make use of the units parameter of the distribution to perform some kind of adapter-specific behaviour. The following units are suggested:

  • bytes β€” Observations give sizes in bytes (perhaps memory buffer or network message sizes), and should be integers.
  • seconds β€” Observations give durations in seconds.

make_distribution

$collector->make_distribution( $handle, %args )

Requests the creation of a new distribution metric.

The following extra arguments may be passed:

  • units => STRING β€” A hint to the adapter about what kind of measurements are being observed, so it might take specific behaviour. If unspecified, a default of "bytes" will apply.

report_distribution

$collector->report_distribution( $handle, $amount, $labels )

Since version 0.05.

Reports a new observation for the distribution metric. The $handle name must match one earlier created by make_distribution. The $amount may be interpreted by the adapter depending on the defined "units" type for the distribution.

This method used to be called inc_distribution_by and is currently still available as an alias.


Gauge 🌈

The make_gauge method creates a new metric which reports on the instantaneous value of some measurable quantity. Unlike the other metric types this does not have to only increment forwards when certain events occur, but can measure a quantity that may both increase and decrease over time; such as the number of some kind of object in memory, or the size of some data structure.

As an alternative to incrementing or decrementing the value when particular events occur, the absolute value of the gauge can also be set directly.

make_gauge

$collector->make_gauge( $handle, %args )

Requests the creation of a new gauge metric.

inc_gauge

$collector->inc_gauge( $handle, $labels )

dec_gauge

$collector->dec_gauge( $handle, $labels )

inc_gauge_by

$collector->inc_gauge_by( $handle, $amount, $labels )

dec_gauge_by

$collector->dec_gauge_by( $handle, $amount, $labels )

Reports that the observed value of the gauge has increased or decreased by the given amount (or 1).

set_gauge_to

$collector->set_gauge_to( $handle, $amount, $labels )

Reports that the observed value of the gauge is now the given amount.

The $handle name must match one earlier created by make_gauge.


Timer ⏱️

The make_timer method creates a new metric which measures durations of time consumed by the application. New observations of durations can be added by the report_timer method.

Timer metrics may be handled by the adapter similarly to distribution metrics. Moreover, adapters may choose to implement timers as distributions with units of "seconds".

make_timer

$collector->make_timer( $handle, %args )

Requests the creation of a new timer metric.

report_timer

$collector->report_timer( $handle, $duration, $labels )

Since version 0.05.

Reports a new duration for the timer metric. The $handle name must match one earlier created by make_timer. The $duration gives a time measured in seconds, and may be fractional.

This method used to called inc_timer_by and is currently still available as an alias.


πŸ‘‘ AUTHOR πŸ‘‘

Paul Evans <leonerd@leonerd.org.uk>


And that's the whole vibe, bestie! This page came from perl v5.36.0, dated 2023-09-29, and it's the Metric...llector(3pm) manual. Slay, periodt. πŸ’…βœ¨

πŸ“¦ where this page comes from