[Nagiosplug-devel] unsubscribe

Roy Hogervorst joop3 at gmx.net
Fri Sep 4 16:46:41 CEST 2009


On 4 sep 2009, at 16:41, Jose Luis Martinez wrote:

> Hi,
>
>   I wrote a mini-module for doing the same in Perl plugins. Haven't
> CPANned it yet, so take this as a call for community revision.
>
>   It's called Nagios::Plugin::Differences, and I'll discuss the design
> so that maybe you can lift some ideas for the C API, or that my module
> gets benefitted from the discussion in place.
>
>  - Each plugin is responsable for it's storage. I don't like FD  
> passing
> either.
>
>  - The serializer is the Perl Storable class. Well-proven, and core
> module. I use the lock_store method to serialize data to the files (so
> appropiate locks get placed). There are not methods in place to change
> storage type, but it can be done via subclassing (overriding persist  
> and
> load_last).
>
>  - The temporary file is defaulted to '/tmp/_nagios_plugin_%s.tmp',
> where %s is the filename name of the plugin when the object gets
> constructed.
>
>  - It's plugins responsibility to choose a different temp file if it's
> anticipated there will be temporary file collisions. For example:
>
> "check_disk_io --dev sda" and "check_disk_io --dev sdb", being  
> executed
> on the same machine will pick up one anothers temp file. They would  
> have
> to construct the Nagios::Plugin::Differences object requesting a
> tempfile like /tmp/_nagios_plugin_check_disk_io_sda.tmp and
> /tmp/_nagios_plugin_check_disk_io_sdb.tmp.
>
>  - The method for persisting data automatically adds the timestamp to
> the reading, you can override it if you want.
>
>  - There are helper methods for doing the "dirty" work of calculating
> differences and rates between now and the last reading.
>
>  - Plugins with incompatible datastructures in different versions can
> be detected with the plugin just storing 'struct_version' as one of  
> the
> values to be persisted and taking appropiate action (up to the  
> plugin).
>
>  I attach the pm file so you can inspect it (also, if you wan't I can
> attach test files too). I'm open to feedback, corrections and
> discussion. Please don't use or publish a plugin that uses this module
> until it's CPANned, as the API is open to change.
>
> Just my 2 cents,
>
> Jose Luis Martinez
> jlmartinez at capside.com
>
> package Nagios::Plugin::Differences;
>
> use strict;
> no warnings;
>
> use Carp;
> use File::Basename qw//;
> use Storable qw//;
>
> =head1 NAME
>
> Nagios::Plugin::Differences - Module to streamline Nagios plugins
> that need to store temporary data and calculate the differences
> between the readings.
>
> =head1 VERSION
>
> Version 0.01
>
> =cut
>
> our $VERSION = '0.01';
>
> =head1 SYNOPSIS
>
> This module is useful for when there is need to store a set of values
> that need to be reread at the next invocation of the plugin. It  
> provides
> a set of functions to calculate the differences between the readings.
>
>    use Nagios::Plugin::Differences;
>
>    my $npd = Nagios::Plugin::Differences->new();
>    $npd->load_last;
>    # suppose last reading was
>    # { 'bytes' => 200, 'packets' => 3 }
>    # at time 1234567890
>    $npd->new_reading({
>        'bytes' => 500
>        'packets' => 6
>    });
>    # new reading is at time 123456900
>    $npd->persist;
>    my $rate = $npd->rate('difference');
>    # rate returns the bytes/s and the packets/s that had to be
>    # attained to get from the last reading to the new reading
>    # in the time passed between readings
>    # { 'bytes' => 30,
>    #   'packets' => 0.3 }
>
> =head1 FUNCTIONS
>
> =head2 new(%options)
>
> Constructor for the Nagios::Plugin::Differences object. You
> can pass 'file' => '/tmp/xxx' to override the default file
> ('/tmp/_nagios_plugin_$0.tmp').
>
> =cut
>
> sub new {
>    my ($class, %options) = @_;
>
>    my $self = { 'file' => sprintf("/tmp/_nagios_plugin_%s.tmp",
>                                   File::Basename::basename($0)),
>                 %options };
>    bless $self, $class;
> }
>
> =head2 new_reading($data, [$ts])
>
> Report a new reading. The reading has to be a hashref. You can  
> optionally
> pass the timestamp for the reading. If you don't pass $ts, the  
> timestamp
> of the invocation of the method will be used.
>
> =cut
>
> sub new_reading {
>    my ($self, $data, $ts) = @_;
>    croak "cannot store non-hashref data" if (ref($data) ne 'HASH');
>    $ts = time() if (not defined $ts);
>
>    $self->{'last'} = $self->{'current'} if (defined $self- 
> >{'current'});
>    $self->{'current'} = { 'ts' => $ts, 'data' => $data };
> }
>
> =head2 persist([$file])
>
> Write the stored data to the temporary file
>
> =cut
>
> sub persist {
>    my ($self, $file) = @_;
>    $file ||= $self->{'file'};
>    Storable::lock_store($self->{'current'}, $file);
> }
>
> =head2 load_last([$file])
>
> Load the last reading from the temporary file.
>
> =cut
>
> sub load_last {
>    my ($self, $file) = @_;
>    $file ||= $self->{'file'};
>    $self->{'last'} = $self->{'current'} if (defined $self- 
> >{'current'});
>    $self->{'current'} = Storable::retrieve($file);
> }
>
>
> #head2 difference_from_zero
> #
> #Calculate the difference between current and zero.
> #
> #cut
> #
> #sub difference_from_zero {
> #    my ($self) = @_;
> #    return ($self->{'current'}->{'data'});
> #}
>
> =head1 CALCULATING DIFFERENCES
>
> =head2 difference
>
> Calculates the difference between current reading and last reading.
>
> =cut
>
> sub difference {
>    my ($self) = @_;
>
>    die 'no new_reading' if (not defined $self->{'current'});
>    die 'no last' if (not defined $self->{'last'});
>
>    my $current_data = $self->{'current'}->{'data'};
>    my $last_data    = $self->{'last'}->{'data'};
>    my $delta = {};
>
>    foreach my $item (keys %$last_data){
>        # if we don't have item, $data_last->{ xxx } will be undef.  
> The correct reading would be zero
>        $delta->{ $item } = $current_data->{ $item } - ($last_data- 
> >{ $item } || 0);
>    }
>    return ($delta);
> }
>
> =head2 forward_difference($wrap_at)
>
> =cut
>
> sub forward_difference {
>    my ($self, $wrap_at) = @_;
>
>    die 'no new_reading' if (not defined $self->{'current'});
>    die 'no last' if (not defined $self->{'last'});
>
>    my $current_data = $self->{'current'}->{'data'};
>    my $last_data    = $self->{'last'}->{'data'};
>    my $delta = {};
>
>    foreach my $item (keys %$last_data){
>        if ($current_data->{ $item } >= $last_data->{ $item }){
>            $delta->{ $item } = $current_data->{ $item } -  
> ($last_data->{ $item } || 0);
>        } else {
>            # If the current reading is smaller than the last time we  
> saw it, then we have to
>            # take into account the wrap value.
>            # time |=======|------------|===========|
>            #      0      current       last        wrap
>            $delta->{ $item } = ($wrap_at - $last_data->{ $item }) +  
> $current_data->{ $item };
>        }
>    }
>    return ($delta);
> }
>
> =head2 forward_difference_unknown_wrap
>
> If the value of a key from the current reading is less than the last  
> reading, the
> difference will be taken from zero. This is handy when you are  
> storing counters
> that increment, but can be reset to zero.
>
> =cut
>
> sub forward_difference_unknown_wrap {
>    my ($self) = @_;
>
>    die 'no new_reading' if (not defined $self->{'current'});
>    die 'no last' if (not defined $self->{'last'});
>
>    my $current_data = $self->{'current'}->{'data'};
>    my $last_data    = $self->{'last'}->{'data'};
>    my $delta = {};
>
>    foreach my $item (keys %$last_data){
>        if ($current_data->{ $item } >= $last_data->{ $item }){
>            $delta->{ $item } = $current_data->{ $item } -  
> ($last_data->{ $item } || 0);
>        } else {
>            # If the current reading is smaller than the last time we  
> saw it, then we have to
>            # discard the last reading. The counter has been reset,  
> and we cannot know what
>            # happened between the last reading and the current one.
>            # time |=======|------------|???????....
>            #             current       last
>            $delta->{ $item } = $current_data->{ $item };
>        }
>    }
>    return ($delta);
> }
>
> =head2 rate($method, [params_to_method])
>
> Calculate the rate of change (derive) between the current reading  
> and the last reading.
> To calculate rate of change, you need to calculate the change. The  
> change gets calculated
> with any of the "difference" methods
>
>  $npd->rate('difference');
>
>  $npd->rate('forward_difference', 1000);
>
>  $npd->rate('forward_difference_unknown_wrap');
>
> =cut
>
> sub rate {
>    my ($self, $method, @params_to_method) = @_;
>
>    my $delta = $self->$method(@params_to_method);
>    my $time = $self->{'current'}->{'ts'} - $self->{'last'}->{'ts'};
>
>    my $rates = {};
>    foreach my $item (keys %$delta){
>        $rates->{$item} = $delta->{$item} / $time;
>    }
>
>    return $rates;
> }
>
> =head2 proportion(
>
> Calculate the proportions of the values of one key respect to the  
> total sum of all the values.
>
>  proportion({ 'red' => 5, 'green' => 15 });
>  # returns: { 'red' => 0.25, 'green' => 0.75 }
>
> =cut
>
> sub proportion {
>    my ($self, $hashref) = @_;
>
>    my $total = 0;
>    map { $total += $_ } values %$hashref;
>
>    my $proportion = {};
>    foreach my $item (keys %$hashref){
>        $proportion->{$item} = $hashref->{$item} / $total;
>    }
>    return($proportion);
> }
>
> 1;
>
>
> =head1 AUTHOR
>
> JLMARTIN, C<< <jlmartinez at capside.com> >>
>
> =head1 BUGS
>
> Please report any bugs or feature requests to C<bug-nagios-plugin- 
> differences at rt.cpan.org>, or through
> the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Nagios-Plugin-Differences 
> >.  I will be notified, and then you'll automatically be notified of  
> progress on your bug as I make changes.
>
> =head1 SUPPORT
>
> You can find documentation for this module with the perldoc command.
>
>    perldoc Nagios::Plugin::Differences
>
> You can also look for information at:
>
> =over 4
>
> =item * RT: CPAN's request tracker
>
> L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Nagios-Plugin-Differences>
>
> =item * AnnoCPAN: Annotated CPAN documentation
>
> L<http://annocpan.org/dist/Nagios-Plugin-Differences>
>
> =item * CPAN Ratings
>
> L<http://cpanratings.perl.org/d/Nagios-Plugin-Differences>
>
> =item * Search CPAN
>
> L<http://search.cpan.org/dist/Nagios-Plugin-Differences>
>
> =back
>
> =head1 ACKNOWLEDGEMENTS
>
> =head1 COPYRIGHT & LICENSE
>
> Copyright 2009 Jose Luis Martinez Torres, all rights reserved.
>
> This program is free software; you can redistribute it and/or modify  
> it
> under the same terms as Perl itself.
>
>
> =cut
>
> 1; # End of Nagios::Plugin::Differences
>
> ------------------------------------------------------------------------------
> Let Crystal Reports handle the reporting - Free Crystal Reports 2008  
> 30-Day
> trial. Simplify your report design, integration and deployment - and  
> focus on
> what you do best, core application coding. Discover what's new with
> Crystal Reports now.  http://p.sf.net/sfu/bobj-july_______________________________________________________
> Nagios Plugin Development Mailing List Nagiosplug-devel at lists.sourceforge.net
> Unsubscribe at https://lists.sourceforge.net/lists/listinfo/nagiosplug-devel
> ::: Please include plugins version (-v) and OS when reporting any  
> issue.
> ::: Messages without supporting info will risk being sent to /dev/null





More information about the Devel mailing list