1 #! /usr/sepp/bin/perl
2 #
3 # Log 2 RRD. This script translates a MRTG 2.x log file
4 # into a RRD archive. The original version was written by
5 # Wrolf Courtney <wrolf@concentric.net> and
6 # Russ Wright <wright@LBL.Gov> with an early test version
7 # of RRDTOOL (mrtg-19980526.08) and has been modified to match
8 # the parameters of rrdtool version 99.23 by Alan Lichty at
9 # Electric Lightwave, Inc. <alichty@eli.net>.
10 #
11 # this script optimized for being called up by another script
12 # that cycles through a list of routers and invokes this for each
13 # interface. It can be run just as easily from a command line for
14 # small numbers of logfiles.
15 #
16 # The RRD we create looks like the following: Note
17 # that we have to use type GAUGE in order to have RRDTOOL
18 # populate the new rr archive correctly. Otherwise RRDTOOL will try
19 # to interpet the data as new octet counts instead of existing
20 # data rate averages.
21 #
22 # DS:GAUGE:86400:U:U # in counter
23 # DS:GAUGE:86400:U:U # out counter
24 # RRA:AVERAGE:0.5:1:600 # 5 minute samples
25 # RRA:MAX:0.5:1:600 # 5 minute samples
26 # RRA:AVERAGE:0.5:6:600 # 30 minute samples
27 # RRA:MAX:0.5:6:600 # 30 minute samples
28 # RRA:AVERAGE:0.5:24:600 # 2 hour samples
29 # RRA:MAX:0.5:24:600 # 2 hour samples
30 # RRA:AVERAGE:0.5:288:732 # 1 day samples
31 # RRA:MAX:0.5:288:732 # 1 day samples
32 #
33 #
35 use English;
36 use strict;
38 require "ctime.pl";
40 use RRDs;
42 my $DEBUG=0;
44 &main;
46 sub main {
48 my($inBytes, $outBytes);
49 my($lastRunDate, $firstRunDate);
50 my($i, $dataFile, $firstRun);
51 my($oldestRun, $lastRun);
52 my($curTime, $oldestTime, $totRec);
53 my($avgIn, $avgOut, $maxIn, $maxOut);
54 my(@lines, @finalRecs);
55 my($RRD, $START, $destDir, $dsType);
57 #
58 # get the logfile name to process
59 # the default is to strip out the .log extension and create
60 # a new file with the extension .rrd
61 #
63 $dataFile=$ARGV[0];
65 $destDir = $ARGV[1];
67 #
68 # strip off .log from file name - complain and die if no .log
69 # in the filename
70 #
72 if ($dataFile =~ /(.*)\.log$/) {
73 $RRD = "$1";
74 }
76 if ($RRD eq "") {
77 printf("Usage: log2rrd [log file] [destination dir]\n");
78 exit;
79 }
81 #
82 # strip out path info (if present) to get at just the filename
83 #
85 if ($RRD =~ /(.*)\/(.*)$/){
86 $RRD = "$2";
87 }
89 #
90 # add the destination path (if present) and .rrd suffix
91 #
93 if ($destDir){
94 $RRD = "$destDir/$RRD.rrd";
96 }else{
97 $RRD = "$RRD.rrd";
98 }
100 open(IN,"$dataFile") || die ("Couldn't open $dataFile");
102 #
103 # Get first line - has most current sample
104 #
106 $_ = <IN>;
107 chop;
108 ($lastRun, $inBytes, $outBytes) = split;
109 $lastRunDate = &ctime($lastRun);
110 chop $lastRunDate;
112 $firstRun = $lastRun;
113 $i=2;
115 #
116 # start w/line 2 and read them into the lines array
117 # (2nd line is in position 2)
118 #
119 while (<IN>) {
120 chop;
121 $lines[$i++] = $_;
122 ($curTime) = split;
123 if ($curTime < $firstRun) {
124 $firstRun = $curTime;
125 }
126 }
127 close(IN);
129 #
130 # Let's say source start time is 5 minutes before 1st sample
131 #
133 $START=$firstRun - 300;
134 print STDERR "\$START = $START\n" if $DEBUG>1;
136 $firstRunDate = &ctime($firstRun);
137 chop $firstRunDate;
139 printf("Data from $firstRunDate\n to $lastRunDate\n") if $DEBUG>0;
141 $oldestTime=$lastRun;
142 #
143 # OK- sort through the data and put it in a new array.
144 # This gives us a chance to find errors in the log files and
145 # handles any overlap of data (there shouldn't be any)
146 #
147 # NOTE: We start w/ record # 3, not #2 since #2 could be partial
148 #
150 for ($i=3; $i <= 2533; $i++) {
152 ($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, $lines[$i]);
154 if ($curTime < $oldestTime) {
156 #
157 # only add data if older than anything already in array
158 # this should always be true, just checking
159 #
161 $oldestTime = $curTime;
162 $finalRecs[$totRec++]=$lines[$i];
163 }
164 }
167 PopulateRRD($totRec, $RRD, $START, \@finalRecs);
169 #
170 # if you know that most of your MRTG logfiles are using
171 # counter data, uncomment the following lines to automatically
172 # run rrdtune and change the data type.
173 #
174 # my(@tuneparams) = ("$RRD", "-d", "ds0:COUNTER", "-d", "ds1:COUNTER");
175 # RRDs::tune(@tuneparams);
178 }
180 sub PopulateRRD {
182 my($totRec, $RRD, $START, $finalRecs) = @_;
183 my($i, $curTime, $avgIn, $avgOut, $maxIn, $maxOut);
184 my($saveReal, $line);
185 my($createret, $updret);
187 print "* Creating RRD $RRD\n\n" if $DEBUG>0;
189 #
190 # We'll create RRAs for both AVG and MAX. MAX isn't currently filled but
191 # may be later
192 #
194 RRDs::create ("$RRD", "-b", $START, "-s", 300,
195 "DS:ds0:GAUGE:86400:U:U",
196 "DS:ds1:GAUGE:86400:U:U",
197 "RRA:AVERAGE:0.5:1:600",
198 "RRA:MAX:0.5:1:600",
199 "RRA:AVERAGE:0.5:6:600",
200 "RRA:MAX:0.5:6:600",
201 "RRA:AVERAGE:0.5:24:600",
202 "RRA:MAX:0.5:24:600",
203 "RRA:AVERAGE:0.5:288:600",
204 "RRA:MAX:0.5:288:600");
206 if (my $error = RRDs::error()) {
207 print "Cannot create $RRD: $error\n";
208 }
211 print "* Adding entries to $RRD\n\n" if $DEBUG>0;
213 for ($i=$totRec - 1; $i >= 0; $i--) {
215 ($curTime, $avgIn, $avgOut, $maxIn, $maxOut) = split(/\s+/, @$finalRecs[$i]);
217 RRDs::update ("$RRD", "$curTime:$avgIn:$avgOut");
219 if (my $error = RRDs::error()) {
220 print "Cannot update $RRD: $error\n";
221 }
224 # NOTE: Need to add checking on RRDread and include the Max values
225 # print status every now and then
226 # print $i if $i % 25 && $DEBUG>0;
227 # print "$i\n";
229 }
231 }