Stats

Niall O'Reilly Niall.oReilly at ucd.ie
Fri Mar 27 14:42:02 UTC 2009


On Fri, 2009-03-27 at 09:25 -0400, John D. Vo wrote:
> What do you guys use to turn this:
> --- Statistics Dump --- (1238151600)
> +++ Statistics Dump +++ (1238155200)
> success 3280261
> referral 363
> nxrrset 745513
> nxdomain 392614
> recursion 1173408
> failure 1115632
> --- Statistics Dump --- (1238155200)

	The following works (for me!) with either this (above) format 
	of dump or the richer format used in more recent BIND releases.

	I'm not certain that the statistics selected for processing in
	each case correspond exactly.  I think they're pretty close.

#!/usr/bin/perl -w

use strict;
use Data::Dumper;

my $PROG = $0; $PROG =~ s|.*/||;

# Configuration

my $Config = {
    statpath => '/var/named/run',
    statfilename => 'named.stats',
    probe => [ qw( /usr/local/sbin/rndc stats ) ],
};

my $State = {
    skip => 0,
    time => undef,
    chain => [ { } ],
};

my $x;

# Result

my $MRTGdata = {
    in => '-1',
    out => '-1',
    uptime => '0',
    name => '0'
    };

# Check that statpath directory exists

$x = $Config->{statpath};
-d $x or die(sprintf("%s: %s: %s\n", $PROG, $!, $x));

# Check that probe binary is a file and executable

$x = $Config->{probe}->[0];
(-f $x and -x $x) or die(sprintf("%s: %s: %s\n", $PROG, $!, $x));

# Save current size of file, if it exists

my $file = join('/', map { $Config->{$_} } (qw(statpath statfilename)));
$State->{skip} = (stat($file))[7] if ( -f $file );

# Save current time

$State->{'time'} = time();

# Issue probe

open(PROBE, '-|', @{$Config->{probe}})
    or die "$PROG: $!\n";
close PROBE;

# Collect data

open(FILE, '<', $file) 
    or die(sprintf("%s: %s: %s\n", $PROG, $!, $file));
$State->{size} = (stat(FILE))[7];
seek(FILE,$State->{skip},0) if $State->{size} > $State->{skip};
my @stats = <FILE>;
close FILE;

# Process stats

# warn join('', @stats);

for ( my ($i, $j, $phase, $stamp, $bucket) = (0, 0, 'IDLE');
      $i < scalar(@stats);
      $i++ ) {

    my $line = $stats[$i];

    if ( $line =~ /^\++\s+Statistics Dump\s+\++\s+\((\d+)\)/ ) {
	$stamp = $1;
	if ($stamp >= $State->{time}) {
	    $phase = $stamp;
	    $bucket = $State->{chain}->[++$j] = [ ];
	    $State->{chain}->[0]->{$phase} = $j;
	    push @$bucket, $i;
	}
    }

    if ($phase eq 'IDLE') {
	# warn "$PROG: skipping: ", $line;
	next;
    }

    if ( $line =~ /^-+\s+Statistics Dump\s+-+\s+\((\d+)\)/ ) {
	$stamp = $1;
	if ($stamp eq $phase) {
	    push @$bucket, $i;
	    $State->{chain}->[0]->{last} = $State->{chain}->[0]->{$phase};
	    $phase = 'IDLE';
	}
    }
}

foreach my $chain ( $State->{chain} ) {
    my $last = $chain->[0]->{last};
    last unless defined $last;
    my ($lo, $hi) = @{$chain->[$last]};
    # warn sprintf("%s: scanning lines %d - %d\n", $PROG, $lo, $hi);

    my $format = ( $stats[++$lo] =~ /^\+/ ) ? 'new' : 'old';
    # warn "$PROG: format: $format\n";

# Analyze new format

    if ($format eq 'new') {
	$MRTGdata->{in} = 0;
	$MRTGdata->{out} = 0;
	my $group = '';

	foreach ( @stats[$lo .. $hi] ) {

	    $group = $1 if /^\++ (.*) \++/;
	    next unless $group eq 'Name Server Statistics';

	    $MRTGdata->{in} += $1 if /\s+(\d+) IPv4 requests received/;

	    $MRTGdata->{out} += $1 if /\s+(\d+) queries resulted in non authoritative answer/;

	}
    }

# Analyze old format

    elsif ($format eq 'old') {
	$MRTGdata->{in} = 0;
	$MRTGdata->{out} = 0;

	foreach ( @stats[$lo .. $hi] ) {

	    $MRTGdata->{in} += $1 if /^success (\d+)/;
	    $MRTGdata->{in} += $1 if /^referral (\d+)/;
	    $MRTGdata->{in} += $1 if /^nxrrset (\d+)/;
	    $MRTGdata->{in} += $1 if /^nxdomain (\d+)/;
	    $MRTGdata->{in} += $1 if /^failure (\d+)/;

	    $MRTGdata->{out} += $1 if /^recursion (\d+)/;

	}
    }
}


# Present result as expected by MRTG

map {
    printf "%s\n", $MRTGdata->{$_}
} ( qw(in out uptime name) );

print "\n";





More information about the bind-users mailing list