Wiki source for MonitoringT2TrafficWithIptraf
====@@Monitoring T2 Traffic with ##iptraf## @@====
<<Traffic stats for 66.244.95.20 available [[gopher://pongonova.org/1/tier2_stats | here]].<<::c::
I wanted to monitor traffic on my Tier 2 servers visually. My requirements were something that was ASCII-based, simple, and quick to implement. There's a lot of good software out there that satisfies two of the three requirements, but not all of them, so I decided to roll my own.
Here is what the output looks like (you might want to maximize your browser window for best effect):
{{image url="http://wiki.opennic.glue/MonitoringT2TrafficWithIptraf/files.xml?action=download&file=iptraf_graph.png"}}
The topmost bar is //greater than or equal to// the row value, but //less than// the next row value. This made more sense to me due to the lack of details that's available on an ASCII-based graph.
===How to implement===
<<These instructions are for a *nix-based system<<::c::
1. Download a copy of ##iptraf## [[http://iptraf.seul.org/ | here]], compile and install (or use your favorite package manager to install it). ''Note that ##iptraf## hasn't been updated in several years, so it seems to have some troubles compiling on "modern" *nix systems. If you are trying to compile this and you get "redefined" errors, e-mail me and I'll tell you what I had to do to get this to work.''
2. Copy the following code into a new file. Be sure to make it executable, and check the ## #! /usr/bin/perl ## line as your perl interpreter might be installed in a different place.
%%(perl)
#!/usr/bin/perl
#
# parseDailyIptrafLogs.pl - Parse daily iptraf logs starting from
# 00:00 and ending 23:59 and plot on a semilog graph. This
# script is compatible with logs generated by the following
# invocation:
#
# /usr/local/bin/iptraf -s eth0 -t 1 -B
#
# Credits: Thanks to an "anonymous monk" and NateTut for a
# starting point: http://www.perlmonks.org/?node_id=336907
#
# This software is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Author: Brian Koontz <brian@opennicproject.org>
#
#####################################################################
use strict;
use warnings;
use POSIX;
### Globals ###
my $filename_prefix = "/var/log/iptraf/archives/tcp_udp_services-eth0-";
my $filename_suffix = ".log";
my $interval = 15;
my $minValue = 0.1;
my $leftMargin = 11;
my $ip = "ns2.ns.stejau.de";
# Graphing parameters...probably best to test first before
# modifying!
my $MAX = 9;
my $height = 14;
my $indent = 7;
my $periods = 96;
# Scaling factor (i.e., 1000 starts scale at 1K)
my $factor = 1;
### End globals ###
my $date;
my $filename;
if($#ARGV < 0)
{
$date = "today";
$filename = "/var/log/iptraf/tcp_udp_services-eth0.log";
}
else
{
$date = $ARGV[0];
$filename = $filename_prefix.$date.$filename_suffix;
}
if(!-f $filename)
{
die "What!? How i am supposed to read a nonexistent file? FOOL!\n";
}
open(my $file, "<", $filename) or die "Can't open $filename for reading!";
# Populate possibly sparse array with indices calculated as
# follows:
#
# $idx = hour * 60 + min
my @kbps;
while(<$file>)
{
if(!/^.*\s+(\d+:\d+:\d+)\s+.*TCP\/UDP service monitor started/)
{
next;
}
else
{
my $ts = $1;
my($hour, $min, $sec) = split(/:/, $ts);
my $throughput;
my $line = <$file>;
while(defined($line) && $line !~ /TCP\/UDP service monitor stopped/)
{
if($line =~ /^(UDP\/53|TCP\/53)(.*)/)
{
my($count, $dummy) = split(/;/, $2);
my $res = $count =~ /^.*?([\d\.]+)\s+kbits\/s/;
$throughput += $1 if($res);
}
$line = <$file>;
next;
}
$kbps[$hour*60+$min] = $throughput;
$throughput = 0;
}
}
close($file);
=pod
# Dump it all!
for(my $i=0; $i<=24*60+59; ++$i)
{
print $kbps[$i]." " if(defined($kbps[$i]));
}
=cut
# More useful: Cull the data every $interval, create a new array
# and pass it to the graphing routine
my @data;
for(my $i=0; $i<=24*60+59; ++$i)
{
if($i%$interval == 0)
{
if(defined($kbps[$i]))
{
$data[$i/$interval] = $kbps[$i];
}
else
{
$data[$i/$interval] = 0;
}
}
}
=pod
my @data;
my $Element = 0;
my $count = $height/$periods;
my @vals = (1E3, 5*1E3, 1E4, 5*1E4, 1E5, 5*1E5, 1E6, 5*1E6, 1E7,
5*1E7, 1E8, 5*1E8, 1E9, 5*1E9, 1E10);
while($Element < $periods)
{
$data[$Element] = $vals[$Element%15];
$Element++;
}
=cut
=pod
while($Element < $periods)
{
# $data[$Element] = $Element;
$data[$Element] = pow(10, (rand($MAX)));
$Element++;
}
=cut
print(ASCII_SemiLogGraph($height, $indent, $periods, @data));
######################################################################ÂÂ#
# Divide 24 hours into intervals of $period minutes. Pass in an
# array of $period elements that represents some parameter for
# each interval.
sub ASCII_SemiLogGraph
{
my ($height, $indent, $periods, @data) = @_;
# Check for zeroes
foreach my $val(@data)
{
$val = $minValue if($val <= 0);
}
my $HighestValue = 0;
my @Rows = ();
#
# Find the Top Value
#
for my $Period (0 .. $periods - 1)
{
$HighestValue = $HighestValue > ($data[$Period]) ? $HighestValue : $data[$Period];
}
#
# Calculate Scale
#
#
#my $Scale = &yCoord($HighestValue) > $height ? ( &yCoord($HighestValue) / $height ) : 1;
#
# Do Each Row
#
for(my $Row=0; $Row<=$height; ++$Row)
{
#
# Label every other row and include legend for Y-axis
#
if($Row > 0 && $Row < $height && ($Row % ($height/2) == 0))
{
$Rows[$Row] = sprintf("%-".$leftMargin."s%" . ($indent - 1) ."s ", 'kbits/s', &genPrefix(pow(10, $Row/2) * $factor)) . ' ' x $periods;
}
elsif($Row % 2)
{
$Rows[$Row] = sprintf("%".$leftMargin."s%" . ($indent - 1) ."s ", '', &genPrefix(pow(10, $Row/2) * $factor)) . ' ' x $periods;
}
else
{
$Rows[$Row] = sprintf("%".$leftMargin."s%" . ($indent - 1) ."s ", '', &genPrefix(pow(10, $Row/2) * $factor)) . '_' x $periods;
}
for my $Period (0 .. $periods - 1)
{
#
# Determine
if (&yCoord($data[$Period]) >= $Row)
{
substr($Rows[$Row], $Period + $leftMargin + $indent, 1) = '|';
}
}
}
return(join( "\n", reverse( @Rows ), sprintf("%".$leftMargin."s", '') . ' Time: ' . '|^^^' x ( $periods / 4 ), ' ' x $indent . sprintf("%".$leftMargin."s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s\n",'', '12am','2am','4am','6am','8am','10am','12pm','2pm','4pm','6pm','8pm','10pm'), ' ' x ($periods/3) . "Network traffic for $ip Date:" . $date, "\n"));
} # end sub graph
# Return SI prefixed string for $val (mantissa < $factor)
sub genPrefix
{
my ($val) = @_;
my $m = $val;
my $exp = 0;
while($m >= 1000)
{
$m /= 1000;
$exp += 3;
}
$m = floor($m);
$m = 1 if($m <= 0);
SWITCH: {
$exp == 0 && do{ return "$m"; };
$exp == 3 && do{ return $m."K"; };
$exp == 6 && do{ return $m."M"; };
$exp == 9 && do{ return $m."G"; };
}
}
# Return y-coord
sub yCoord
{
my ($val) = @_;
my $ret = floor(log10($val/$factor) * 2);
return $ret;
}
%%
3. Set up a cronjob to run iptraf on 15-minute intervals. (I also added another cronjob to archive each day's log to make it easier to parse.) You should not have to change the logfile names, but if you do, you'll need to modify the perl script above.
%%
# Run iptraf logs every 15 minutes for 1 minute
*/15 * * * * /usr/local/bin/iptraf -s eth0 -t 1 -B
# Copy iptraf log each day
58 23 * * * /bin/mv /var/log/iptraf/tcp_udp_services-eth0.log /var/log/iptraf/archives/tcp_udp_services-eth0-`/bin/date +\%Y\%m\%d`.log
%%
4. Run the perl script against your archived logs:
%%
parseDailyIptrafLogs 20110701
%%
{{files}}
<<Traffic stats for 66.244.95.20 available [[gopher://pongonova.org/1/tier2_stats | here]].<<::c::
I wanted to monitor traffic on my Tier 2 servers visually. My requirements were something that was ASCII-based, simple, and quick to implement. There's a lot of good software out there that satisfies two of the three requirements, but not all of them, so I decided to roll my own.
Here is what the output looks like (you might want to maximize your browser window for best effect):
{{image url="http://wiki.opennic.glue/MonitoringT2TrafficWithIptraf/files.xml?action=download&file=iptraf_graph.png"}}
The topmost bar is //greater than or equal to// the row value, but //less than// the next row value. This made more sense to me due to the lack of details that's available on an ASCII-based graph.
===How to implement===
<<These instructions are for a *nix-based system<<::c::
1. Download a copy of ##iptraf## [[http://iptraf.seul.org/ | here]], compile and install (or use your favorite package manager to install it). ''Note that ##iptraf## hasn't been updated in several years, so it seems to have some troubles compiling on "modern" *nix systems. If you are trying to compile this and you get "redefined" errors, e-mail me and I'll tell you what I had to do to get this to work.''
2. Copy the following code into a new file. Be sure to make it executable, and check the ## #! /usr/bin/perl ## line as your perl interpreter might be installed in a different place.
%%(perl)
#!/usr/bin/perl
#
# parseDailyIptrafLogs.pl - Parse daily iptraf logs starting from
# 00:00 and ending 23:59 and plot on a semilog graph. This
# script is compatible with logs generated by the following
# invocation:
#
# /usr/local/bin/iptraf -s eth0 -t 1 -B
#
# Credits: Thanks to an "anonymous monk" and NateTut for a
# starting point: http://www.perlmonks.org/?node_id=336907
#
# This software is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Author: Brian Koontz <brian@opennicproject.org>
#
#####################################################################
use strict;
use warnings;
use POSIX;
### Globals ###
my $filename_prefix = "/var/log/iptraf/archives/tcp_udp_services-eth0-";
my $filename_suffix = ".log";
my $interval = 15;
my $minValue = 0.1;
my $leftMargin = 11;
my $ip = "ns2.ns.stejau.de";
# Graphing parameters...probably best to test first before
# modifying!
my $MAX = 9;
my $height = 14;
my $indent = 7;
my $periods = 96;
# Scaling factor (i.e., 1000 starts scale at 1K)
my $factor = 1;
### End globals ###
my $date;
my $filename;
if($#ARGV < 0)
{
$date = "today";
$filename = "/var/log/iptraf/tcp_udp_services-eth0.log";
}
else
{
$date = $ARGV[0];
$filename = $filename_prefix.$date.$filename_suffix;
}
if(!-f $filename)
{
die "What!? How i am supposed to read a nonexistent file? FOOL!\n";
}
open(my $file, "<", $filename) or die "Can't open $filename for reading!";
# Populate possibly sparse array with indices calculated as
# follows:
#
# $idx = hour * 60 + min
my @kbps;
while(<$file>)
{
if(!/^.*\s+(\d+:\d+:\d+)\s+.*TCP\/UDP service monitor started/)
{
next;
}
else
{
my $ts = $1;
my($hour, $min, $sec) = split(/:/, $ts);
my $throughput;
my $line = <$file>;
while(defined($line) && $line !~ /TCP\/UDP service monitor stopped/)
{
if($line =~ /^(UDP\/53|TCP\/53)(.*)/)
{
my($count, $dummy) = split(/;/, $2);
my $res = $count =~ /^.*?([\d\.]+)\s+kbits\/s/;
$throughput += $1 if($res);
}
$line = <$file>;
next;
}
$kbps[$hour*60+$min] = $throughput;
$throughput = 0;
}
}
close($file);
=pod
# Dump it all!
for(my $i=0; $i<=24*60+59; ++$i)
{
print $kbps[$i]." " if(defined($kbps[$i]));
}
=cut
# More useful: Cull the data every $interval, create a new array
# and pass it to the graphing routine
my @data;
for(my $i=0; $i<=24*60+59; ++$i)
{
if($i%$interval == 0)
{
if(defined($kbps[$i]))
{
$data[$i/$interval] = $kbps[$i];
}
else
{
$data[$i/$interval] = 0;
}
}
}
=pod
my @data;
my $Element = 0;
my $count = $height/$periods;
my @vals = (1E3, 5*1E3, 1E4, 5*1E4, 1E5, 5*1E5, 1E6, 5*1E6, 1E7,
5*1E7, 1E8, 5*1E8, 1E9, 5*1E9, 1E10);
while($Element < $periods)
{
$data[$Element] = $vals[$Element%15];
$Element++;
}
=cut
=pod
while($Element < $periods)
{
# $data[$Element] = $Element;
$data[$Element] = pow(10, (rand($MAX)));
$Element++;
}
=cut
print(ASCII_SemiLogGraph($height, $indent, $periods, @data));
######################################################################ÂÂ#
# Divide 24 hours into intervals of $period minutes. Pass in an
# array of $period elements that represents some parameter for
# each interval.
sub ASCII_SemiLogGraph
{
my ($height, $indent, $periods, @data) = @_;
# Check for zeroes
foreach my $val(@data)
{
$val = $minValue if($val <= 0);
}
my $HighestValue = 0;
my @Rows = ();
#
# Find the Top Value
#
for my $Period (0 .. $periods - 1)
{
$HighestValue = $HighestValue > ($data[$Period]) ? $HighestValue : $data[$Period];
}
#
# Calculate Scale
#
#
#my $Scale = &yCoord($HighestValue) > $height ? ( &yCoord($HighestValue) / $height ) : 1;
#
# Do Each Row
#
for(my $Row=0; $Row<=$height; ++$Row)
{
#
# Label every other row and include legend for Y-axis
#
if($Row > 0 && $Row < $height && ($Row % ($height/2) == 0))
{
$Rows[$Row] = sprintf("%-".$leftMargin."s%" . ($indent - 1) ."s ", 'kbits/s', &genPrefix(pow(10, $Row/2) * $factor)) . ' ' x $periods;
}
elsif($Row % 2)
{
$Rows[$Row] = sprintf("%".$leftMargin."s%" . ($indent - 1) ."s ", '', &genPrefix(pow(10, $Row/2) * $factor)) . ' ' x $periods;
}
else
{
$Rows[$Row] = sprintf("%".$leftMargin."s%" . ($indent - 1) ."s ", '', &genPrefix(pow(10, $Row/2) * $factor)) . '_' x $periods;
}
for my $Period (0 .. $periods - 1)
{
#
# Determine
if (&yCoord($data[$Period]) >= $Row)
{
substr($Rows[$Row], $Period + $leftMargin + $indent, 1) = '|';
}
}
}
return(join( "\n", reverse( @Rows ), sprintf("%".$leftMargin."s", '') . ' Time: ' . '|^^^' x ( $periods / 4 ), ' ' x $indent . sprintf("%".$leftMargin."s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s\n",'', '12am','2am','4am','6am','8am','10am','12pm','2pm','4pm','6pm','8pm','10pm'), ' ' x ($periods/3) . "Network traffic for $ip Date:" . $date, "\n"));
} # end sub graph
# Return SI prefixed string for $val (mantissa < $factor)
sub genPrefix
{
my ($val) = @_;
my $m = $val;
my $exp = 0;
while($m >= 1000)
{
$m /= 1000;
$exp += 3;
}
$m = floor($m);
$m = 1 if($m <= 0);
SWITCH: {
$exp == 0 && do{ return "$m"; };
$exp == 3 && do{ return $m."K"; };
$exp == 6 && do{ return $m."M"; };
$exp == 9 && do{ return $m."G"; };
}
}
# Return y-coord
sub yCoord
{
my ($val) = @_;
my $ret = floor(log10($val/$factor) * 2);
return $ret;
}
%%
3. Set up a cronjob to run iptraf on 15-minute intervals. (I also added another cronjob to archive each day's log to make it easier to parse.) You should not have to change the logfile names, but if you do, you'll need to modify the perl script above.
%%
# Run iptraf logs every 15 minutes for 1 minute
*/15 * * * * /usr/local/bin/iptraf -s eth0 -t 1 -B
# Copy iptraf log each day
58 23 * * * /bin/mv /var/log/iptraf/tcp_udp_services-eth0.log /var/log/iptraf/archives/tcp_udp_services-eth0-`/bin/date +\%Y\%m\%d`.log
%%
4. Run the perl script against your archived logs:
%%
parseDailyIptrafLogs 20110701
%%
{{files}}