#! /usr/bin/perl
#
# mrtg2cricket
#
# This script translates a MRTG 2.x log file into a RRD archive
# suitable for use in Cricket. You can drop the resulting .rrd file(s)
# into the appropriate cricket-logs subdirectory.
#
# The original version, log2rrd was written by
# Wrolf Courtney <wrolf@concentric.net> and
# Russ Wright <wright@LBL.Gov> with an early test version
# of RRDTOOL (mrtg-19980526.08) and has been modified to match
# the parameters of rrdtool version 99.23 by Alan Lichty at
# Electric Lightwave, Inc. <alichty@eli.net>. This version,
# mrtg2cricket was updated by David Croft <david at davidc.net>
# on Jul 3, 2002 to convert to cricket RRD format, and has been renamed
# to better distinguish the programs it converts between.
#
# this script optimized for being called up by another script
# that cycles through a list of routers and invokes this for each
# interface.  It can be run just as easily from a command line for
# small numbers of logfiles.
#
# The RRD we create looks like the following:  Note
# that we have to use type GAUGE in order to have RRDTOOL
# populate the new rr archive correctly.  Otherwise RRDTOOL will try 
# to interpet the data as new octet counts instead of existing
# data rate averages.
#
# updated by davidc: After conversion, the GAUGE is changed back
# to DERIVE so that cricket can update it correctly in future. Also,
# I have added DSs for packets per second and errors per second, per
# the default cricket config. Finally, the heartbeat has been increased
# during creation to allow MRTG values greater than 10 days old
# to be imported (which would otherwise fail due to the heartbeat).
#
# The final RRD archive looks like:
# 
#    DS:ds0:DERIVE:1800:0:U
#    DS:ds1:DERIVE:1800:0:U
#    DS:ds2:DERIVE:1800:0:U
#    DS:ds3:DERIVE:1800:0:U
#    DS:ds4:DERIVE:1800:0:U
#    DS:ds5:DERIVE:1800:0:U
#    RRA:AVERAGE:0.5:1:600
#    RRA:AVERAGE:0.5:6:600
#    RRA:AVERAGE:0.5:24:600
#    RRA:MAX:0.5:24:600
#    RRA:AVERAGE:0.5:288:600
#    RRA:MAX:0.5:288:600

use English;
use strict;

require "ctime.pl";
use lib qw(/usr/local/rrdtool/lib/perl);

use RRDs;

my $DEBUG=0;

&main;

sub main {

    my($inBytes, $outBytes);
    my($lastRunDate, $firstRunDate);
    my($i, $dataFile, $firstRun);
    my($oldestRun, $lastRun);
    my($curTime, $oldestTime, $totRec);
    my($avgIn, $avgOut, $maxIn, $maxOut);
    my(@lines, @finalRecs);
    my($RRD, $START, $destDir, $dsType);

#
# get the logfile name to process
# the default is to strip out the .log extension and create
# a new file with the extension .rrd
#

    $dataFile=$ARGV[0];

    $destDir = $ARGV[1];

#
# strip off .log from file name - complain and die if no .log
# in the filename
#

    if ($dataFile =~ /(.*)\.log$/) {
	$RRD = "$1";
    }

    if ($RRD eq "") {
	printf("Usage: mrtg2cricket [log file] [destination dir]\n");
	exit;
    }

#
# strip out path info (if present) to get at just the filename
#

    if ($RRD =~ /(.*)\/(.*)$/){
	$RRD = "$2";
    }

#
# add the destination path (if present) and .rrd suffix
#

    if ($destDir){
	$RRD = "$destDir/$RRD.rrd";

    }else{
	$RRD = "$RRD.rrd";
    }

    open(IN,"$dataFile") || die ("Couldn't open $dataFile");

#
# Get first line - has most current sample
#

    $_ = <IN>;
    chop;
    ($lastRun, $inBytes, $outBytes) = split;
    $lastRunDate = &ctime($lastRun);
    chop $lastRunDate;

    $firstRun = $lastRun;
    $i=2;

#
# start w/line 2 and read them into the lines array
# (2nd line is in position 2)
#
    while (<IN>) {
	chop;
	$lines[$i++] = $_;
	($curTime) = split;
	if ($curTime < $firstRun) {
	    $firstRun = $curTime;
	}
    }
    close(IN);

#
#  Let's say source start time is 5 minutes before 1st sample
#

    $START=$firstRun - 300;
    print STDERR "\$START = $START\n" if $DEBUG>0;

    $firstRunDate = &ctime($firstRun);
    chop $firstRunDate;

    printf("Data from $firstRunDate\n       to $lastRunDate\n") if $DEBUG>0;

    $oldestTime=$lastRun;
#
# OK- sort through the data and put it in a new array.
# This gives us a chance to find errors in the log files and
# handles any overlap of data (there shouldn't be any)
#
# NOTE: We start w/ record # 3, not #2 since #2 could be partial
#

    for ($i=3; $i <= 2533; $i++) {

	($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, $lines[$i]);

	if ($curTime < $oldestTime) {

#
# only add data if older than anything already in array
# this should always be true, just checking
#

	    $oldestTime = $curTime;
	    $finalRecs[$totRec++]=$lines[$i];
	}
	else {
	    die("eep");
	}
    }

    printf("Olders run $oldestTime, totRec $totRec\n") if $DEBUG>0;


    PopulateRRD($totRec, $RRD, $START, \@finalRecs);

#
# if you know that most of your MRTG logfiles are using
# counter data, uncomment the following lines to automatically
# run rrdtune and change the data type.
#
#    my(@tuneparams) = ("$RRD", "-d", "ds0:COUNTER", "-d", "ds1:COUNTER");
#    RRDs::tune(@tuneparams);


}

sub PopulateRRD {

    my($totRec, $RRD, $START, $finalRecs) = @_;
    my($i, $curTime, $avgIn, $avgOut, $maxIn, $maxOut);
    my($saveReal, $line);
    my($createret, $updret);

    print "* Creating RRD $RRD\n\n" if $DEBUG>0;

#
# We'll create RRAs for both AVG and MAX. MAX isn't currently filled but 
# may be later
#

# Make the heartbeat > 1day to be able to accept data from
# old mrtg logs -- davidc

    RRDs::create ("$RRD", "-b", $START, "-s", 300,
    "DS:ds0:GAUGE:180000:0:U",
    "DS:ds1:GAUGE:180000:0:U",
    "DS:ds2:DERIVE:1800:0:U",
    "DS:ds3:DERIVE:1800:0:U",
    "DS:ds4:DERIVE:1800:0:U",
    "DS:ds5:DERIVE:1800:0:U",
    "RRA:AVERAGE:0.5:1:600",
    "RRA:AVERAGE:0.5:6:600",
    "RRA:AVERAGE:0.5:24:600",
    "RRA:MAX:0.5:24:600",
    "RRA:AVERAGE:0.5:288:600",
    "RRA:MAX:0.5:288:600");

    if (my $error = RRDs::error()) {
	print "Cannot create $RRD: $error\n";
    }


    print "* Adding entries to $RRD\n\n" if $DEBUG>0;

    for ($i=$totRec - 1; $i >= 0; $i--) {

	($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, @$finalRecs[$i]);

#	$avgIn *= 1024;
#	$avgOut *= 1024;

#	print "$curTime:$avgIn:$avgOut:NaN:NaN:NaN:NaN\n";

        RRDs::update ("$RRD", "$curTime:$avgIn:$avgOut:U:U:U:U");

	if (my $error = RRDs::error()) {
	    print "Cannot update $RRD: $error\n";
	}

  
# NOTE: Need to add checking on RRDread and include the Max values
# print status every now and then
#	print $i if $i % 25 && $DEBUG>0;
#	print "$i\n";

    }

# Now we need to change the heartbeat back to 1800
# and the type back to DERIVE --davidc

#rrdtune -h ds0:1800 -h ds1:1800 -d ds0:DERIVE -d ds1:DERIVE

  RRDs::tune ("$RRD", "-h", "ds0:1800", "-h", "ds1:1800", "-d", "ds0:DERIVE", "-d", "ds1:DERIVE");


}
