NAME
Prometheus::Client - Prometheus instrumentation client for Perl 6
SYNOPSIS
use v6;
use Prometheus::Client :metrics, :instrument;
#| A function that takes some time.
sub process-request($t) is timed {
sleep $t;
}
my $m = METRICS {
summary
'request_processing_seconds',
'Time spent processing requests',
timed => &process-request;
}
sub MAIN() {
use Cro::HTTP::Router;
use Cro::HTTP::Server;
use Prometheus::Client::Exposition :render;
my $application = route {
get -> 'process', $t is timed($timer) {
sleep $t;
content 'text/plain', 'ok';
}
get -> 'metrics' {
content 'text/plain', render-metrics($m);
}
}
my Cro::Service $service = Cro::HTTP::Server.new:
:host<localhost>, :port<10000>, :$application;
$service.start;
react whenever signal(SIGINT) {
$service.stop;
exit;
}
}
DESCRIPTION
This is an implementation of a Prometheus client library. The intention is to adhere to the requirements given by the Prometheus project for writing clients:
As well as to provide an interface that fits Perl 6. This module provides a DSL for defining a collection of metrics as well as tools for easily using those metrics to easily instrument your code.
This particular module provides an interface aimed at instrumenting your Perl 6 program. If you need to provide instrumentation of an external program, the operating system, or something else, you will likely find the interface provided by Prometheus::Client::Collector to be more useful.
This module also provides the registry tooling, which allows you gather all the metrics of multiple collectors together into a single interface.
CLARIFICATIONS
Insofar as it is possible, I have tried to stick to the definitions and usages prefered by the Prometheus project for components. However, as a relative noob to Prometheus, I have probably gotten some of the details wrong. Please submit an issue or PR if I or this code requires correction.
There is a particular clarification that I need to make regarding the use of the work "metrics." Personally, I find the way Prometheus uses the words "metrics", "metrics family", and "samples" to be extremely confusing. (In fact, the word "metric" is being entirely misused by the Prometheus project. The word they actually mean is "measurement", but I digress.) Therefore, I want to take a moment here to clarify that "metric" can have basically two meanings within this module library depending on context.
Pod::Defn<93921565996832>
Pod::Defn<93921565994984>
Now, in the official Prometheus client libraries, the "metrics" classes refer to metrics as collectors. The "metrics family" classes refer to metrics as measurements. In this library, you will find the interface for using metrics as collectors here with the class definitions being held by Prometheus::Client::Metrics. You will find the interface for using metrics as measurements primarily within Prometheus::Client::Exporter because these are primarily used to build exporters.
The other word that can be somewhat confusing is the word "sample". However, the most common uses of this library should allow you to avoid running into this confusion. Be aware that if you run into a metric as a measurement with multiple samples, that doesn't mean the samples are necessarily a series of measurements of that measurement. Usually multipel samples are different properties of a single measurement. For example, a summary metric will always report two samples, the count of items being reported and the running sum of items that have been reported.
EXPORTED ROUTINES
This module provides no exports by default. However, if you specify the :metrics
parameter when you import it, you will receive all the exported routines mentioned here. If not expoted, they are all defined OUR
-scoped, so you can use them the Prometheus::Client::
prefix.
You can also supply the :instrument
parameter during import. This will cause the is timed
and is tracked-in-progress
traits to be exported.
sub METRICS
our sub METRICS(&block --> Prometheus::Client::CollectorRegistry:D) is export(:metrics)
Calling this subroutine will cause a dynamic variable named $*PROMETHEUS
to be defined and then the code of &block
to be called. If you use the other methods exported by this module to construct counters, gauges, summaries, histograms, info, and state-set metrics or the routine provided for collector registry within the METRICS
block, the constructed metrics will be automatically constructed and registered. The fully constructed registry is then returned by this routine.
If you have custom code to run and build your metric or collector objects, you can refer directly to $*PROMETHEUS
as needed within the block. However, this should rarely be necessary.
sub counter
our proto counter(|) is export(:metrics)
multi counter(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::Counter)
multi counter(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Str:D :@label-names,
Real:D :$value = 0,
Instant:D :$created = now,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::Counter
)
Constructs a Prometheus::Client::Metrics::Counter and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
If @label-names
are given, then a counter group is created instead. In which case, you code must provide values for the labels whenever providing a measurement for the metric:
my $c = counter(
name => 'person_ages',
documentation => 'the ages of measured people',
label-values => <personal_name>,
);
$c.labels('Bob').inc;
$c.labels(personal_name => 'Steve').inc;
See Prometheus::Client::Metrics::Group for details.
sub gauge
our proto gauge(|) is export(:metrics)
multi gauge(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::Gauge)
multi gauge(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Str:D :@label-names,
Real:D :$value = 0,
Instant:D :$created = now,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::Gauge
)
Constructs a Prometheus::Client::Metrics::Gauge and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
If @label-names
are given, then a gauge group is created instead. In which case, you code must provide values for the labels whenever providing a measurement for the metric:
my $c = gauge(
name => 'person_heights',
unit => 'inches',
documentation => 'the heights of measured people',
label-values => <personal_name>,
);
$c.labels('Bob').set(60);
$c.labels(personal_name => 'Steve').set(68);
See Prometheus::Client::Metrics::Group for details.
sub summary
our proto summary(|) is export(:metrics)
multi summary(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::Summary)
multi summary(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Str:D :@label-names,
Real:D :$count = 0,
Real:D :$sum = 0,
Instant:D :$created = now,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::Summary
)
Constructs a Prometheus::Client::Metrics::Summary and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
If @label-names
are given, then a summary group is created instead. In which case, you code must provide values for the labels whenever providing a measurement for the metric:
my $c = summary(
name => 'personal_visits_count',
documentation => 'the number of visits by particular people',
label-values => <personal_name>,
);
$c.labels('Bob').observe(6);
$c.labels(personal_name => 'Steve').observe(0);
See Prometheus::Client::Metrics::Group for details.
sub histogram
our proto histogram(|) is export(:metrics)
multi histogram(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::Histogram)
multi histogram(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Str:D :@label-names,
Real:D :@bucket-bounds,
Int:D :@buckets,
Real:D :$sum,
Instant:D :$created = now,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::Histogram
)
Constructs a Prometheus::Client::Metrics::Histogram and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
If @label-names
are given, then a histogram group is created instead. In which case, you code must provide values for the labels whenever providing a measurement for the metric:
my $c = histogram(
name => 'personal_visits_duration',
bucket-bounds => (1,2,4,8,16,32,64,128,256,512,Inf),
documentation => 'the length of visits by particular people',
label-values => <personal_name>,
);
$c.labels('Bob').observe(182);
$c.labels(personal_name => 'Steve').observe(12);
See Prometheus::Client::Metrics::Group for details.
sub info
our proto info(|) is export(:metrics)
multi info(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::Info)
multi info(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Pair:D :@info,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::Info
)
Constructs a Prometheus::Client::Metrics::Info and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
sub state-set
our proto state-set(|) is export(:metrics)
multi state-set(Str:D $name, Str:D $documentation --> Prometheus::Client::Metrics::StateSet)
multi state-set(
Str:D :$name!,
Str:D :$namespace,
Str:D :$subsystem,
Str:D :$unit,
Str:D :$documentation!,
Str:D :@states,
Int:D :$state,
Prometheus::Client::CollectorRegistry :$registry,
--> Prometheus::Client::Metrics::StateSet
)
Constructs a Prometheus::Client::Metrics::StateSet and registers with the registry in $*PROMETHEUS
or the given $registry
. The newly constructed metric collector is returned.
sub register
our sub register(
Prometheus::Client::Metrics::Collector $collector,
Prometheus::Client::CollectorRegistry :$registry,
) is export(:metrics)
This calls the .register
method of the current Prometheus::Client::Metrics::CollectorRegistry in $*PROMETHEUS
or the given $registry
.
sub unregister
our sub unregister(
Prometheus::Client::Metrics::Collector $collector,
Prometheus::Client::CollectorRegistry :$registry,
) is export(:metrics)
This calls the .unregister
method of the current Prometheus::Client::Metrics::CollectorRegistry in $*PROMETHEUS
or the given $registry
.
trait is timed
multi trait_mod:<is> (Routine $r, :$timed!) is export(:instrument)
The is timed
trait allows you to instrument a routine to time it. Each call to that method will update the attached metric collector. The change recorded depends on the type of metric:
- A gauge will be set to the Duration of the most recent call.
- A summary will add an observation for each call with the sum being increased by the time and the counter being bumpted by one.
- A histogram will add an observation to the appropriate bucket based on the duration of the call.
trait is tracked-in-progress
multi trait_mod:<is> (Routine $r, :$tracked-in-progress!) is export(:instrument)
This method will track the number of in-progress calls to the instrumented method. The gauge will be increased at the start of the call and decreased at the end.