summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rwxr-xr-xbin/smokeinfo115
-rw-r--r--lib/Smokeping/Info.pm204
3 files changed, 322 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index dc6f28b..d93772b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+* smokeinfo: new tool to extract numeric data from a smokeping installation
+ creation sponsored by Swisscom Hospitality -- tobi
+
* new matcher: ExpLoss.pm matcher.
It produces an exponential weighted average and supports RMON-like
thresholds to obtain stable node status detection. -- Veniamin Konoplev V.Konoplev rssi.ru
diff --git a/bin/smokeinfo b/bin/smokeinfo
new file mode 100755
index 0000000..a143abc
--- /dev/null
+++ b/bin/smokeinfo
@@ -0,0 +1,115 @@
+#!/usr/bin/perl -w
+use strict;
+
+use lib qw(/usr/pack/rrdtool-1.3.2-to/lib/perl);
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Smokeping::Info;
+use Getopt::Long 2.25 qw(:config no_ignore_case);
+use Pod::Usage 1.14;
+
+'$Revision: 3879 $ ' =~ /Revision: (\S*)/;
+my $Revision = $1;
+
+sub main()
+{
+ # parse options
+ my %opt = (mode=>'plain',pattern=>undef,separator=>';',format=>'%le');
+
+ GetOptions(\%opt, 'help|h', 'man', 'version', 'noaction|no-action|n',
+ 'start=s','end=s','pattern=s','mode=s','separator=s','format=s') or exit(1);
+ if($opt{help}) { pod2usage(1) }
+ if($opt{man}) { pod2usage(-exitstatus => 0, -verbose => 2) }
+ if($opt{version}) { print "smokeinfo $Revision\n"; exit(0) }
+ if($opt{noaction}) { die "ERROR: don't know how to \"no-action\".\n" }
+ my $config = shift @ARGV;
+
+ my $si = Smokeping::Info->new($config);
+ my $nodes = $si->fetch_nodes(pattern=>$opt{pattern},mode=>$opt{mode});
+ my @rows = qw(med_avg med_min med_max med_now loss_avg loss_max loss_now);
+ print '# ',join $opt{separator}, 'node_path',@rows;
+ print "\n";
+ for my $node (@$nodes) {
+ my $data = $si->stat_node($node,'end-24h','now');
+ print join $opt{separator},$node->{path},map {sprintf($opt{format},$data->{$_})} @rows;
+ print "\n";
+ }
+}
+
+main;
+
+__END__
+
+=head1 NAME
+
+smokeinfo - poll smokeping site for numeric information
+
+=head1 SYNOPSIS
+
+B<smokeinfo> path/to/config.cfg [I<options>]
+
+ --start x rrd graph start time
+
+ --end y rrd graph end time
+
+ --filter filter_pattern search pattern for node selection
+
+ --mode plain (default) how to use the pattern
+ - plain
+ - recursive
+ - regexp
+
+ --separator ; (default)
+
+ --format %le (default)
+
+ --man show man-page and exit
+ -h, --help display this help and exit
+ --version output version information and exit
+
+=head1 DESCRIPTION
+
+SmokeInfo is a simple frontend to the L<Smokeping::Info> module. It provides
+access to numeric data stored in the rrd files.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009 by OETIKER+PARTNER AG. All rights reserved.
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=head1 AUTHOR
+
+S<Tobi Oetiker E<lt>tobi@oetiker.chE<gt>>
+
+=head1 HISTORY
+
+ 2009-01-05 to Initial Version
+
+=cut
+
+# Emacs Configuration
+#
+# Local Variables:
+# mode: cperl
+# eval: (cperl-set-style "PerlStyle")
+# mode: flyspell
+# mode: flyspell-prog
+# End:
+#
+# vi: sw=4 et
+
diff --git a/lib/Smokeping/Info.pm b/lib/Smokeping/Info.pm
new file mode 100644
index 0000000..00ce096
--- /dev/null
+++ b/lib/Smokeping/Info.pm
@@ -0,0 +1,204 @@
+# -*- perl -*-
+package Smokeping::Info;
+use warnings;
+use strict;
+use RRDs;
+use Smokeping;
+use Carp;
+use Data::Dumper;
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my $self = { cfg_file => shift };
+ bless $self, $class;
+ my $parser = Smokeping::get_parser();
+ $self->{cfg_hash} = $parser->parse( $self->{cfg_file} )
+ or croak "ERROR reading config file $parser->{err}";
+ $self->{probe_hash} = Smokeping::load_probes $self->{cfg_hash};
+ return $self;
+}
+
+# get a list of all rrd files in the config file
+
+sub __flatten_targets;
+sub __flatten_targets {
+ my $probes = shift;
+ my $root = shift;
+ my $prefix = shift;
+ my @paths;
+ for my $target ( sort {$root->{$a}{_order} <=> $root->{$b}{_order}}
+ grep { ref $root->{$_} eq 'HASH' } keys %$root ) {
+ push @paths, __flatten_targets($probes,$root->{$target},$prefix.'/'.$target);
+ };
+ if (exists $root->{host} and not $root->{host} =~ m|/|){
+ my $probe = $probes->{$root->{probe}};
+ my $pings = $probe->_pings($root);
+ if (not $root->{nomasterpoll}) {
+ push @paths, { path => $prefix, pings=>$pings };
+ };
+ if ($root->{slaves}) {
+ for my $slave (split /\s+/,$root->{slaves}){
+ push @paths, { path => $prefix.'~'.$slave, pings=>$pings };
+ }
+ }
+ };
+ return @paths;
+}
+
+sub fetch_nodes {
+ my $self = shift;
+ my %args = ( 'mode' => 'plain', @_); # no mode is default
+ my %valid = ( pattern=>1, mode => 1 );
+ my %valid_modes = ( plain=>1, recursive=>1, regexp=>1);
+ map {
+ croak "Invalid fetch nodes argument '$_'"
+ if not $valid{$_};
+ } keys %args;
+
+ croak "Invalid fetch mode $args{mode}"
+ if not $valid_modes{$args{mode}};
+
+ my $cfg = $self->{cfg_hash};
+ my @flat = __flatten_targets($self->{probe_hash},$cfg->{Targets},'');
+
+ my $rx = qr{.*};
+ if ( defined $args{pattern} ) {
+ if ( $args{mode} eq 'recursive' ) {
+ $rx = qr{^\Q$args{pattern}\E};
+ }
+ elsif ( $args{mode} eq 'regexp' ) {
+ $rx = qr{$args{pattern}};
+ }
+ else {
+ $rx = qr{^\Q$args{pattern}\E[^/]*$};
+ }
+ }
+ return [ grep { $_->{path} =~ /${rx}/ } @flat ];
+}
+
+
+sub stat_node {
+ my $self = shift;
+ my $path = shift;
+ my $start = shift;
+ my $end = shift;
+ my $cfg = $self->{cfg_hash};
+ my ($graphret,$xs,$ys) = RRDs::graph (
+ '/tmp/dummy',
+ '--start'=>$start,
+ '--end'=>$end,
+ 'DEF:loss_avg_r='.$cfg->{General}{datadir}.$path->{path}.'.rrd:loss:AVERAGE',
+ 'CDEF:loss_avg=loss_avg_r,'.$path->{pings}.',/',
+ 'VDEF:loss_avg_tot=loss_avg,AVERAGE',
+ 'PRINT:loss_avg_tot:%.8le',
+ 'DEF:loss_max_r='.$cfg->{General}{datadir}.$path->{path}.'.rrd:loss:MAX',
+ 'CDEF:loss_max=loss_max_r,'.$path->{pings}.',/',
+ 'VDEF:loss_max_tot=loss_max,MAXIMUM',
+ 'PRINT:loss_max_tot:%.8le',
+ 'VDEF:loss_now=loss_avg,LAST',
+ 'PRINT:loss_now:%.8le',
+ 'DEF:median_avg='.$cfg->{General}{datadir}.$path->{path}.'.rrd:median:AVERAGE',
+ 'VDEF:median_avg_tot=median_avg,AVERAGE',
+ 'PRINT:median_avg_tot:%.8le',
+ 'DEF:median_min='.$cfg->{General}{datadir}.$path->{path}.'.rrd:median:MIN',
+ 'VDEF:median_min_tot=median_min,MINIMUM',
+ 'PRINT:median_min_tot:%.8le',
+ 'DEF:median_max='.$cfg->{General}{datadir}.$path->{path}.'.rrd:median:MAX',
+ 'VDEF:median_max_tot=median_max,MAXIMUM',
+ 'PRINT:median_max_tot:%.8le',
+ 'VDEF:median_now=median_avg,LAST',
+ 'PRINT:median_now:%.8le'
+ );
+ if (my $ERROR = RRDs::error()){
+ croak "$path->{$path}: $ERROR";
+ }
+ my %data;
+ @data{qw(loss_avg loss_max loss_now med_avg med_min med_max med_now)} = @$graphret;
+ return \%data;
+};
+1;
+
+__END__
+
+=head1 NAME
+
+Smokeping::Info - Pull numerical info out of the rrd databases
+
+=head1 OVERVIEW
+
+This module provides methods to further process information contained in
+smokeping rrd files. The smokeinfo tool is a simple wrapper around the
+functionality containd in here.
+
+ my $si = Smokeping::Info->new("config/file/path");
+
+ my $array_ref = $si->fetch_nodes(pattern=>'/node/path',
+ mode=>'recursive');
+
+ my $hash_ref = $si->stat_node(path,start,end);
+
+=head2 IMPLEMENTATION
+
+=head3 new(path)
+
+Create a new Smokeping::Info instance. Instantiating Smokeping::Info entails
+reading the configuration file. This is a compte heavy procedure. So you may
+want to use a single info object to handle multiple requests.
+
+=head3 fetch_nodes(pattern=>'/...',mode=>{recursive|regexp})
+
+The fetch_nodes method will find all nodes sitting in the given pattern
+(absolute path) including the path itself. By setting the recursive mode,
+all rrd files in paths below will be returned as well. In regexp mode, all
+rrd paths matching the given expression will be returned.
+
+=head3 stat_node(node,start,end)
+
+Return a hash pointer to statistics based on the data stored in the given
+rrd path.
+
+ med_avg - average median
+ med_min - minimal median
+ med_max - maximal median
+ med_now - current median
+ loss_avg - average loss
+ loss_max - maximum loss
+ loss_now - current loss
+
+=head1 COPYRIGHT
+
+Copyright 2009 by OETIKER+PARTNER AG
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+
+=head1 AUTHOR
+
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>, development sponsored by Swisscom Hospitality
+
+=cut
+
+# Emacs Configuration
+#
+# Local Variables:
+# mode: cperl
+# eval: (cperl-set-style "PerlStyle")
+# mode: flyspell
+# mode: flyspell-prog
+# End:
+#
+# vi: sw=4