=pod =encoding utf-8 =head1 Measure::Everything =head2 META =head3 Author Thomas Klausner =head3 Email domm AT plix.at =head3 URL http://domm.plix.at =head3 URL_slides http://domm.plix.at/talks/2015_vienna_pm__measure_everything =head3 Date 2015-11-23 =head3 Location Vienna =head3 Event Vienna.pm TechMeet =head2 Measure Anything, Measure Everything I guess everybody knows this great blog post by the etsy team about StatsD etc =for newslide =for img codeascraft.png =for newslide https://codeascraft.com/2011/02/15/measure-anything-measure-everything/ =for newslide If not, read it! tl;dr: You want to know a lot about your systems to make proper decisions. And we're talking about not only CPU load, memory usage etc. We're talking about hits, conversions, bookings, sells, whatever it is you're doing. And even more important: hits, conversions, sells, etc you are B making! So you can figure out B you're not making them... =for newslide You want to create a lot of measurements all throughout your code. C make this easy. =head3 Measure::Everything - Log::Any for Stats https://metacpan.org/pod/Measure::Everything https://github.com/domm/Measure-Everything It's a heavyly inspired by the great C. Everybody knows C? =head3 Log::Any When you B have to work with more than a few processes running on the linux machine in your pocket... =for newslide In a CPAN or other module: package Foo; use Log::Any qw($log); # log a string $log->error("an error occurred"); # log a string and data using a formatting filter $log->debugf("arguments are: %s", \@_); =for newslide In your application: use Foo; use Log::Any::Adapter; # Send all logs to Log::Log4perl Log::Any::Adapter->set('Log4perl'); # Send all logs to Log::Dispatch my $log = Log::Dispatch->new(outputs => [[ ... ]]); Log::Any::Adapter->set( 'Dispatch', dispatcher => $log ); =for newslide Take a look at it, it takes a lot of hassle away from logging. =head3 Measure::Everything wants to do the same for generating stats. =for newslide package YourApp::Schema::Result::Product; # .. # DBIC code # .. sub view { my $self = shift; } =for newslide package YourApp::Schema::Result::Product; # .. # DBIC code # .. sub view { my $self = shift; # I wonder how often each product is viewed? } =for newslide package YourApp::Schema::Result::Product; # .. # DBIC code # .. use **Measure::Everything** qw(@@$stats@@); sub view { my $self = shift; # I wonder how often each product is viewed? } =for newslide package YourApp::Schema::Result::Product; # .. # DBIC code # .. use Measure::Everything qw($stats); sub view { my $self = shift; @@$stats@@->**write**( 'product_view', 1 ); } =for newslide You maybe want to add some more information to each measurement: sub view { my $self = shift; $stats->write( 'product_view', 1, { **id** => $self->id, **category** => $self->category } ); } Using Tags =for newslide sub **buy** { my $self = shift; $stats->write( '@@product_sell@@', { count => 1, price => $self->price, }, { id => $self->id, category => $self->category } ); } Here I want to store several data points. =for newslide sub buy { my $self = shift; $stats->write( 'product_sell', { **count** => 1, **price** => $self->price, }, { id => $self->id, category => $self->category } ); } C allows me to later get the total sum of money spent in a given time interval. or average, min/max, percentiles, etc =for newslide But the nice thing (again stolen from C) is that you can use it everywhere: =for newslide package YourApp::**Schema::ResultSet**::Product; use Measure::Everything qw($stats); sub some_method { my $self = shift; ... $stats->write( ... ); } =for newslide package YourApp::Web::**Controller**::Product; use Measure::Everything qw($stats); sub an_action { my ( $self, $c ) = @_; ... $stats->write( ... ); } =for newslide package YourApp::**SomeCronJob**; use Measure::Everything qw($stats); sub do_something { my $self = shift; ... $stats->write( ... ); } =for newslide There is no need to pass C<$stats> around to every method you call, 20 levels deep There is no need for a god-object (like Catalyst's C<$c>) into which you can stuff C<$stats> You just use Measure::Everything qw($stats); and have it! =head3 So what does do? For now, B We first need to set up a C =head3 Adapter All of the modules where you use Measure::Everything qw($stats); are in the end loaded by B PSGI file, cron script, a daemon, ... In that piece of code you have to define which C you want to use Just like you would do with a C =for newslide Per default, you use C which does nothing. As of now, there is one other C: =head3 Measure::Everything::Adapter::InfluxDB::File =for newslide #!/usr/bin/env perl use strict; use warnings; use YourApp; use **Measure::Everything::Adapter**; Measure::Everything::Adapter->set( 'InfluxDB::File', file => '/var/stats/myproject.stats', ); YourApp->run; =for newslide #!/usr/bin/env perl use strict; use warnings; use YourApp; use Measure::Everything::Adapter; Measure::Everything::Adapter->**set**( 'InfluxDB::File', file => '/var/stats/myproject.stats', ); YourApp->run; =for newslide #!/usr/bin/env perl use strict; use warnings; use YourApp; use Measure::Everything::Adapter; Measure::Everything::Adapter->set( **'InfluxDB::File'**, file => '/var/stats/myproject.stats', ); YourApp->run; =for newslide #!/usr/bin/env perl use strict; use warnings; use YourApp; use Measure::Everything::Adapter; Measure::Everything::Adapter->set( 'InfluxDB::File', **file => '/var/stats/myproject.stats'**, ); YourApp->run; =for newslide Now all calls to C<< $stats->write >> will be stored into a file using the InfluxDB line protocol =head3 InfluxDB? "An open-source distributed time series database with no external dependencies." Written in Go https://influxdb.com/ =for newslide B