Catalyst-Plugin-PrometheusTiny
view release on metacpan or search on metacpan
* refresh README, fixup META resources
0.005 - 2021-06-08
* add META resources
* add optional controller and action labels to the metrics
0.004 - 2021-06-06
* allow simple configuration of endpoint path
* bump deps on Prometheus::Tiny and ::Shared
* more tests
0.003 - 2021-06-05
* bump min Perl version to 5.10.1 due to upstream deps
0.002 - 2021-06-05
* remove a regexp modifier added in Perl 5.22
Changes
lib/Catalyst/Plugin/PrometheusTiny.pm
maint/Makefile.PL.include
Makefile.PL
MANIFEST This list of files
t/default_config.t
t/endpoint.t
t/include_action_labels.t
t/lib/TestApp.pm
t/lib/TestApp/Controller/Root.pm
t/lib/TestApp/Helper.pm
t/prometheus.t
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
README README file (added by Distar)
LICENSE LICENSE file (added by Distar)
Once your app has served from requests you can fetch request/response
metrics:
curl http://$myappaddress/metrics
DESCRIPTION
This plugin integrates Prometheus::Tiny::Shared with your Catalyst app,
providing some default metrics for requests and responses, with the
ability to easily add further metrics to your app. A default controller
is included which makes the metrics available via the configured
"endpoint", though this can be disabled if you prefer to add your own
controller action.
See Prometheus::Tiny for more details of the kind of metrics supported.
The following metrics are included by default:
http_request_duration_seconds => {
help => 'Request durations in seconds',
type => 'histogram',
},
prometheus
sub my_action {
my ( $self, $c ) = @_;
$c->prometheus->inc(...);
}
Returns the "Prometheus::Tiny::Shared" instance.
CONFIGURATION
endpoint
The endpoint from which metrics are served. Defaults to "/metrics".
filename
It is recommended that this is set to a directory on a memory-backed
filesystem. See "filename" in Prometheus::Tiny::Shared for details and
default value.
ignore_path_regex
ignore_path_regex => '^(healthcheck|foobar)'
A regular expression against which "$c->request->path" is checked, and
},
# more...
}
See "declare" in Prometheus::Tiny. Declare extra metrics to be added to
those included with the plugin.
no_default_controller
no_default_controller => 0 # default
If set to a true value then the default "endpoint" will not be added,
and you will need to add your own controller action for exporting the
metrics. Something like:
package MyApp::Controller::Stats;
sub begin : Private { }
sub end : Private { }
sub index : Path Args(0) {
my ( $self, $c ) = @_;
lib/Catalyst/Plugin/PrometheusTiny.pm view on Meta::CPAN
help => 'Response sizes in bytes',
type => 'histogram',
buckets => [ 1, 50, 100, 1_000, 50_000, 500_000, 1_000_000 ],
}
},
};
my ($prometheus, # instance
$ignore_path_regexp, # set from config
$include_action_labels, # set from config
$metrics_endpoint, # set from config with default
$no_default_controller, # set from config
$request_path # derived from $metrics_endpoint
);
# for testing
sub _clear_prometheus {
undef $prometheus;
}
sub prometheus {
my $c = shift;
$prometheus //= do {
my $config = Catalyst::Utils::merge_hashes(
$defaults,
$c->config->{'Plugin::PrometheusTiny'} // {}
);
$include_action_labels = $config->{include_action_labels};
$metrics_endpoint = $config->{endpoint};
if ($metrics_endpoint) {
if ( $metrics_endpoint !~ m|^/| ) {
Carp::croak
"Plugin::PrometheusTiny endpoint '$metrics_endpoint' does not begin with '/'";
}
}
else {
$metrics_endpoint = '/metrics';
}
$request_path = $metrics_endpoint;
$request_path =~ s|^/||;
$ignore_path_regexp = $config->{ignore_path_regexp};
if ($ignore_path_regexp) {
$ignore_path_regexp = qr/$ignore_path_regexp/
unless 'Regexp' eq ref $ignore_path_regexp;
}
$no_default_controller = $config->{no_default_controller};
lib/Catalyst/Plugin/PrometheusTiny.pm view on Meta::CPAN
before setup_components => sub {
my $class = shift;
# initialise prometheus instance pre-fork and setup lexicals
$class->prometheus;
return
if $class->config->{'Plugin::PrometheusTiny'}{no_default_controller};
# Paranoia, as we're going to eval $metrics_endpoint
if ( $metrics_endpoint =~ s|[^-A-Za-z0-9\._~/]||g ) {
$class->log->warn(
"Plugin::PrometheusTiny unsafe characters removed from endpoint");
}
$class->log->info(
"Plugin::PrometheusTiny metrics endpoint installed at $metrics_endpoint"
);
eval qq|
package Catalyst::Plugin::PrometheusTiny::Controller;
use base 'Catalyst::Controller';
sub begin : Private { }
sub end : Private { }
sub metrics : Path($metrics_endpoint) Args(0) {
my ( \$self, \$c ) = \@_;
my \$res = \$c->res;
\$res->content_type("text/plain");
\$res->output( \$c->prometheus->format );
}
1;
| or do {
Carp::croak("Plugin::PrometheusTiny controller eval failed: $@");
};
lib/Catalyst/Plugin/PrometheusTiny.pm view on Meta::CPAN
Once your app has served from requests you can fetch request/response metrics:
curl http://$myappaddress/metrics
=head1 DESCRIPTION
This plugin integrates L<Prometheus::Tiny::Shared> with your L<Catalyst> app,
providing some default metrics for requests and responses, with the ability
to easily add further metrics to your app. A default controller is included
which makes the metrics available via the configured L</endpoint>, though this
can be disabled if you prefer to add your own controller action.
See L<Prometheus::Tiny> for more details of the kind of metrics supported.
The following metrics are included by default:
http_request_duration_seconds => {
help => 'Request durations in seconds',
type => 'histogram',
},
lib/Catalyst/Plugin/PrometheusTiny.pm view on Meta::CPAN
sub my_action {
my ( $self, $c ) = @_;
$c->prometheus->inc(...);
}
Returns the C<Prometheus::Tiny::Shared> instance.
=head1 CONFIGURATION
=head2 endpoint
The endpoint from which metrics are served. Defaults to C</metrics>.
=head2 filename
It is recommended that this is set to a directory on a memory-backed
filesystem. See L<Prometheus::Tiny::Shared/filename> for details and default
value.
=head2 ignore_path_regex
ignore_path_regex => '^(healthcheck|foobar)'
lib/Catalyst/Plugin/PrometheusTiny.pm view on Meta::CPAN
# more...
}
See L<Prometheus::Tiny/declare>. Declare extra metrics to be added to those
included with the plugin.
=head2 no_default_controller
no_default_controller => 0 # default
If set to a true value then the default L</endpoint> will not be
added, and you will need to add your own controller action for exporting the
metrics. Something like:
package MyApp::Controller::Stats;
sub begin : Private { }
sub end : Private { }
sub index : Path Args(0) {
my ( $self, $c ) = @_;
t/endpoint.t view on Meta::CPAN
use warnings;
use strict;
use lib 'lib', 't/lib';
use Test::More;
use Test::Deep;
use TestApp::Helper;
TestApp::Helper::run(
{ endpoint => '/testme' },
'/testme',
superbagof('http_requests_total{code="200",method="GET"} 1')
);
done_testing;
t/lib/TestApp/Helper.pm view on Meta::CPAN
use strict;
use Test::More;
use Test::Deep;
use HTTP::Request::Common;
use Plack::Test;
use TestApp;
sub get_metrics {
my ( $test, $endpoint ) = @_;
my $res = $test->request( GET $endpoint );
return [ grep { $_ !~ /^#/ } split /\n/, $res->content ];
}
sub run {
my ( $config, $endpoint, $expect ) = @_;
TestApp->config( 'Plugin::PrometheusTiny' => $config );
TestApp->setup;
my $app = TestApp->psgi_app;
my $test = Plack::Test->create($app);
my $got = get_metrics( $test, $endpoint );
cmp_deeply $got, [], "We start with no metrics"
or diag explain $got;
ok my $res = $test->request( GET "/" ), "GET /";
is $res->content, "Hello World", "... and content is as expected";
$got = get_metrics( $test, $endpoint );
cmp_deeply $got,
$expect,
"... and metrics are as expected"
or diag explain $got;
}
1;
( run in 0.346 second using v1.01-cache-2.11-cpan-b61123c0432 )