Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??
#!/usr/bin/perl -w # snmpiio.pl # pod at tail $|++; use strict; use Net::SNMP; use Tie::IxHash; use constant SECS_PER_MIN => 60; use constant SECS_PER_HR => 3600; use constant SECS_PER_DAY => 86400; use constant SECS_PER_WEEK => 604800; ###################################################################### +#### # Edit defaults, options, and binaries to suit your environment: ###################################################################### +#### my $target = shift or Usage(); my $ifIndex = shift or Usage(); my $iters = (shift or 4); my $delay = (shift or 30); my $outdir = (shift or '.'); my %opt =( community => 'public', tmpdir => '/tmp', timeout => 15, port => 161, p2p => '-compression 9', ); # Chart::Graph uses system(gnuplot). I borrowed some ideas from it. # Maybe can use GD (no system calls) when Debian 3.0 releases. my %bin = ( gnp => '/usr/bin/gnuplot', p2p => '/usr/bin/pnmtopng', prt => '/usr/local/bin/pdq', ); ###################################################################### +#### # Muck over the input: ###################################################################### +#### # These are standard OIDs, so should work 'most anywhere. tie my %oid, "Tie::IxHash"; %oid = ( ifName => ".1.3.6.1.2.1.31.1.1.1.1.$ifIndex", ifSpeed => ".1.3.6.1.2.1.2.2.1.5.$ifIndex", ifInOctets => ".1.3.6.1.2.1.2.2.1.10.$ifIndex", ifOutOctets => ".1.3.6.1.2.1.2.2.1.16.$ifIndex", ); # date-stamped filenames for uniquity. my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); my %stamp; $stamp{start} = DateTime(); $stamp{ymd} = sprintf("%04d%02d%02d",$year+1900,$mon+1,$mday); tie my %file, "Tie::IxHash"; %file = ( gnpOpt => "$opt{tmpdir}/$target-$ifIndex-$stamp{ymd}.gnpOpt", tmp => "$outdir/$target-$ifIndex-$stamp{ymd}.tmp", csv => "$outdir/$target-$ifIndex-$stamp{ymd}.csv", xls => "$outdir/$target-$ifIndex-$stamp{ymd}.xls", tab => "$outdir/$target-$ifIndex-$stamp{ymd}.tab", ps => "$outdir/$target-$ifIndex-$stamp{ymd}.ps", pnm => "$outdir/$target-$ifIndex-$stamp{ymd}.pnm", png => "$outdir/$target-$ifIndex-$stamp{ymd}.png", ); # Sanity-checks, not untainting: Usage() unless ( $target =~ (/\w+/) and $ifIndex =~ (/\d+/) and $iters =~ (/\d+/) and $delay =~ (/\d+/) and $outdir =~ (/.*/) ); unless($iters >= 3) { print "\n\nSorry, minimum iterations allowed is 3.\n\n"; exit 1; } unless($delay >= 10) { print "\n\nSorry, minimum delay allowed is 10.\n\n"; exit 1; } unless(-d $outdir) { print "\n\nSorry, $outdir isn't an existing directory.\n\n"; exit 1; } unless(-w $outdir) { print "\n\nSorry, you don't have write perms for $outdir.\n\n"; exit 1; } # Provide estimate of total runtime: my %run; $run{secs} = $iters * $delay; $run{est} = $run{secs}; $run{unit} = 'seconds'; if($run{secs} > SECS_PER_MIN) { $run{est} = $run{secs}/SECS_PER_MIN; $run{est} = sprintf("%.0f",$run{est}); if($run{est} == 1.0) { $run{est} = 1; $run{unit} = 'minute'; } else { $run{unit} = 'minutes'; } } if($run{secs} > SECS_PER_HR) { $run{est} = $run{secs}/SECS_PER_HR; $run{est} = sprintf("%.1f",$run{est}); if($run{est} == 1.0) { $run{est} = 1; $run{unit} = 'hour'; } else { $run{unit} = 'hours'; } } if($run{secs} > SECS_PER_DAY) { $run{est} = $run{secs}/SECS_PER_DAY; $run{est} = sprintf("%.1f",$run{est}); if($run{est} == 1.0) { $run{est} = 1; $run{unit} = 'day'; } else { $run{unit} = 'days'; } } if($run{secs} > SECS_PER_WEEK) { $run{est} = $run{secs}/SECS_PER_WEEK; $run{est} = sprintf("%.1f",$run{est}); if($run{est} == 1.0) { $run{est} = 1; $run{unit} = 'week'; } else { $run{unit} = 'weeks'; } } # Files writable only by this user for security purposes: # Delete pre-existing out file because subsequent writes append: print "\nStart run of $0\n", " $stamp{start}\n", " $target ifIndex $ifIndex\n", " $iters runs at ${delay} second intervals\n", " $run{est} $run{unit} estimated runtime\n", ; umask oct 133; print " Clean up old file(s)...\n"; for(keys %file){ Unlink($file{$_}, 'verbose'); } # Leading '#' so gnuplot will ignore non-data header: print " Print csv header..."; open (CSV, ">$file{csv}") or die "Error opening $file{csv}: $!"; print (CSV "# EpochSec,\%rcvUtil,\%xmitUtil,\n") or die "Error printing to $file{csv}: $!"; close CSV or die "Error closing $file{csv}: $!"; print " done!\n"; ###################################################################### +#### # Get down to business: ###################################################################### +#### print " Query target device... "; my $i = 1; for(1..$iters) { open (TMP, ">>$file{tmp}") or die "Error opening $file{tmp}: $!"; # Prepend epoch seconds to each csv line: $stamp{epoch} = time; print(TMP "$stamp{epoch},") or die "Error printing to $file{tmp}: $ +!"; # Here's where da *real* stuf happens: my $session = Net::SNMP->session( -hostname => $target, -community => $opt{community}, -port => $opt{port}, -timeout => $opt{timeout}, ); unless (defined($session)) { print TMP ("SNMP SESSION ERROR,") or die "Error printing to $file{tmp}: $!"; } for my $value(keys %oid) { if (defined(my $response = $session->get_request($oid{$value}))) + { print(TMP $response->{$oid{$value}}) or die "Error printing to $file{tmp}: $!"; } else { print (TMP '0') or die "Error printing to $file{tmp}: $!" +; } print (TMP ',') or die "Error printing to $file{tmp}: $!"; } $session->close(); # Activity indicator: # One line per iteration: # End of iteration: # Delay between iterations, but not after last iteration: ## print '.'; print (TMP "\n") or die "Error printing to $file{tmp}: $!"; close TMP or die "Error closing $file{tmp}: $!"; sleep $delay unless($i==$iters); $i++; } print " done!\n"; # $ifName is global so available later, outside of this block. my $ifName; print " Calculate receive and transmit %utilization..."; { # Contained block to limit 'print csv with $,': # Initialize prior array to 0 to avoid annoying 'not numeric' error +: local $, = ','; my @prior = (0) x 5; open (TMP, "<$file{tmp}") or die "Error opening $file{tmp}: $!"; open (CSV, ">>$file{csv}") or die "Error opening $file{csv}: $!"; while(<TMP>) { chomp; my @data = split ','; # Subtract epochSecs for deltaTime: # Protect against 'divide by zero' error: my $time = $data[0]; my $priortime = $prior[0]; my $dtime = $time - $priortime; next unless $dtime; $ifName = $data[1]; my $ifSpeed = $data[2]; my $inBytes = $data[3]; my $outBytes = $data[4]; my $priorInBytes = $prior[3]; my $priorOutBytes = $prior[4]; # Handle counter-roll-over-to-zero in approximate fashion, # and prevent 'divide by zero' error if no OID response: $priorInBytes = 1 if( ($inBytes < $priorInBytes) or ($priorInBytes == 0) ); $priorOutBytes = 1 if( ($outBytes < $priorOutBytes) or ($priorOutBytes == 0) ); $ifSpeed = 1 if($ifSpeed == 0); my $rBytes = $inBytes - $priorInBytes; my $xBytes = $outBytes - $priorOutBytes; my $rutil = CalcUtil($rBytes,$dtime,$ifSpeed); my $xutil = CalcUtil($xBytes,$dtime,$ifSpeed); # No valid data (delta) on first iteration, so skip it. if($prior[2] > 0) { print CSV "$time,$rutil,$xutil,\n" or die "Error printing to $file{csv}: $!"; } # Set current values for 'prior' on next iteration: @prior = @data; } close (TMP) or die "Error closing $file{tmp}: $!"; close (CSV) or die "Error closing $file{csv}: $!"; } ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); $stamp{done} = DateTime(); print " done!\n"; ###################################################################### +#### # Output formatting: ###################################################################### +#### if(-x $bin{gnp} && -B _) { # Tab-delimited for feeding to gnuplot: print " Create tab-delimited outfile from csv..."; open (CSV, "<$file{csv}") or die "Error opening $file{csv}: $!"; open (TAB, ">>$file{tab}") or die "Error opening $file{tab}: $!"; while(<CSV>) { s/,/ /g; print TAB or die "Error printing to $file{tab}: $!"; } close (CSV) or die "Error closing $file{csv}: $!"; close (TAB) or die "Error closing $file{tab}: $!"; print " done!\n"; # Create option file for gnuplot: # "plot \"$file{tab}\" using 1:2, \"$file{tab}\" using 1:3, \"$fi +le{tab}\" using 1:4", print " Create gnuplot option file..."; my @gnpOpt = ( 'set data style lines', "set title \"$target port $ifName ifIndex $ifIndex - $iters ru +ns at $delay second intervals\"", "set key title \"Receive, Transmit\"", "set xlabel \"$stamp{start} through $stamp{done}\"", 'set ylabel "%bandwidth"', 'set grid', 'set noxtics', 'set terminal postscript', "set output \"$file{ps}\"", "plot \"$file{tab}\" using 1:2, \"$file{tab}\" using 1:3", 'set terminal pbm', "set output \"$file{pnm}\"", 'replot', 'set terminal postscript', "set output \"|$bin{prt}\"", 'replot', ); open (GNPOPT, ">$file{gnpOpt}") or die "Error opening $file{gnpOpt} +: $!"; for(@gnpOpt){ print (GNPOPT "$_\n") or die "Error printing to $file{gnuOpt}: $ +!"; } close GNPOPT or die "Error closing $file{gnpOpt}: $!"; print " done!\n"; # Create chartfiles from tab-delim data with gnuplot: if ((-r $file{gnpOpt} && -T _) and (-x $bin{gnp})) { print " Create PNM+PS graphs from tab-delimited..."; system("$bin{gnp} $file{gnpOpt}") and die "Error running $bin{gnp}: $?"; print " done!\n"; } # Create PNG from PNM with pnmtopng: if ((-r $file{pnm} && -B _) and (-x $bin{p2p})) { print " Create PNG graph from PNM..."; system("$bin{p2p} $opt{p2p} $file{pnm} > $file{png}") and die " Error running $bin{p2p}: $?"; print " done!\n"; } } # Create xls from csv *if* Spreadsheet::WriteExcel module installed. my $have_SWE; BEGIN { $have_SWE = 0; eval { require Spreadsheet::WriteExcel }; unless ($@) { Spreadsheet::WriteExcel->import(); $have_SWE = 1; } } if ($have_SWE == 1) { print " Create xls outfile from csv..."; open (CSVFILE, $file{csv}) or die "Error opening $file{csv}: $!"; my $workbook = Spreadsheet::WriteExcel -> new($file{xls}); my $worksheet = $workbook -> addworksheet(); my $row = 0; while (<CSVFILE>) { chomp; my @field = split(',', $_); my $column = 0; foreach my $token (@field) { $worksheet -> write($row, $column, $token); $column++; } $row++; } my $format1 = $workbook -> addformat(); $format1 -> set_bold(); $format1 -> set_align('center'); $format1 -> set_bg_color('tan'); $worksheet -> set_row(0, undef, $format1); $workbook -> close() or die "Error closing $workbook: $!"; print " done!\n"; } ###################################################################### +#### # Conditional cleanup of temp files: ###################################################################### +#### print " Clean up temp file(s)...\n"; if(-e $file{csv} && -B_){ Unlink($file{gnpOpt}, 'verbose'); Unlink($file{tmp}, 'verbose'); } if(-e $file{xls} && -B_){ Unlink($file{csv}, 'verbose'); } if(-e $file{ps} && -T_){ Unlink($file{xls}, 'verbose'); Unlink($file{tab}, 'verbose'); Unlink($file{pnm}, 'verbose'); } if(-e $file{png} && -B_){ Unlink($file{ps}, 'verbose'); } # Bring it on home: print "Run complete of $0.\n", " $stamp{done}\n"; for(keys %file){ print " $file{$_}\n" if(-e $file{$_}); } print "\n\n"; exit 0; ###################################################################### +##### # Subroutines: ###################################################################### +##### # for Start/Done times sub DateTime { my $DateTime = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec ); } ###################################################################### +##### # Octets to %bandwidth calculations: sub CalcUtil { my $Bytes = $_[0]; my $secs = $_[1]; my $speed = $_[2]; my $MBytes = $Bytes / 1048576; my $Mbits = $MBytes * 8; my $Mbps = $Mbits / $secs; # * 100 convert decimal to percent # * 1000000 move decimal point to match $speed # * 1.048576 bits per Megabit my $util = ($Mbps * 100 * 1000000) / ($speed * 1.048576); # Avoid reported util > %100 after 1 or more no response: $util /= 2 while $util > 100; # Round output, but not @data(next iteration's @prior): my $utilRound = sprintf("%.3f",$util); } ###################################################################### +##### # Delete outfiles from prior run (if same name as this run): sub Unlink { my $file = $_[0]; my $echo = $_[1]; if (-e $file && -w _) { print " unlink $file" if ($echo eq 'verbose'); unlink $file or die "Error unlinking $file: $!"; print " -- *poof*\n" if ($echo eq 'verbose'); } } ###################################################################### +##### sub Usage { print " Ooot! You forgot to enter necessary information, or entered bad information! Usage: snmpiio.pl target iterations delay ifIndex outdir target: an IPaddress, DNS name, or FQDN. ifIndex: SNMP parameter specifying port or interface. iterations: how many queries you wish to run. (minimum 3, default + 4) delay: seconds to wait between iterations. (minimum 10, default +30) outdir: destination dir for outfile. No trailing '/'. (default ' +.') Example: snmpiio.pl routerC 7 600 30 /datadir This script $0 Net::Snmp $Net::SNMP::VERSION Tie::IxHash $Tie::IxHash::VERSION Spreadsheet::WriteExcel $Spreadsheet::WriteExcel::VERSION Perl $] Local OS $^O "; exit 1; } ###################################################################### +##### =head1 NAME snmpiio.pl =head1 SYNOPSIS Query SNMP-enabled devices for interface (in|out)put octets. Output files in csv, tab-delimited, pnm, and png formats. Intended for spotchecks or periodic monitoring of individual interfac +es. Tools like MRTG, MCSview, SNMPc, CWSI do well for large number of por +ts. snmpiio.pl target iterations delay ifIndex outdir target: an IPaddress, DNS name, or FQDN. ifIndex: SNMP parameter specifying port or interface. iterations: how many queries you wish to run. (minimum 3, defaul +t 4) delay: seconds to wait between iterations. (minimum 10, default + 30) outdir: destination dir for outfile. No trailing '/'. (default +'.') Example: snmpiio.pl routerC 7 600 30 MyString /datadir Assorted conversions: 2880 iterations 30 sec delay = 24 hours 8640 iterations 30 sec delay = 3 days 20160 iterations 30 sec delay = 7 days 40320 iterations 30 sec delay = 14 days 100Mbps = 12.5MBps 1GB = 8,589,934,592 bits (1,073,741,824 * 8) 1MB = 8,388,608 bits (1,048,576 * 8) 1KB = 8,192 bits (1024 * 8) 1Gb = 1,073,741,824 bits (1024-e3) 1Mb = 1,048,576 bits (1024-e2) 1Kb = 1,024 bits (1024-e1) ifInOctets+ifOutOctets = Bytes ((Bytes*8)/1024)/seconds = Kbps ((Bytes*8)/1048576)/seconds = Mbps =head1 TESTED Perl 5.00503 Debian 2.2r3 Net::SNMP 3.6 Tie::IxHash 1.21 Spreadsheet::WriteExcel 0.31 Gnuplot 3.71 pnmtopng 2.37.4-1 Excel 2000 9.0.3821 SR-1 =head1 UPDATED 2001-10-29 11:00 CDT Post to PerlMonks. Fix time est errs - include $run{est} = $run{secs} in each if loop. Remove default value (2) for ifIndex, update Usage()+pod. Include ifIndex in gnuplot title. 2001-10-26 16:40 CDT Hashimafy passel o'scalars so fewer global vars. Add "or die" where missing on couple print(FILE) lines. Easy-to-read estimate of run duration. Suggested by Zaxo: (cleaner syntax, but not quite the output wanted) print int($run-secs / SECS_PER_WEEK), ' week(s), '; print int($run-secs / SECS_PER_DAY), ' day(s), '; print int($run-secs / SECS_PER_HR), ' hour(s), '; print int($run-secs / SECS_PER_MIN), ' minute(s), '; Minimum iterations of 3, to provide 2 data-points. Minimum delay of 10 seconds, to prevent target CPU saturation. Use named scalar instead of $data[0], $prior[0]. Prevent %util > 100 (if no response 1 or more times). Calc + display HDX utilization (rcv + xmit). Retest Excel file. %files for all file handling to eliminate redundent data of arrays. Eliminate duplicate (start|done)stamp snippets with DateTime(). Print Perl+module+OS versions at Usage(). Replace @unlinkStart with keys of %file. Add $ifName so can print module/port in outfile header. STDOUT hot so messages appear promptly. Conditional Unlink of tempfiles at wrap-up. Round %util to 3 decimal points. Subamify duplicate bw calculations. Gnuplot key title. Additional filechecks in PNM, PNG creation. Process receive/transmit data separately. Print PostScript outfile with pdq. Automate output graph with gnuplot+pnmtopng. 2001-10-18 16:45 CDT Separate $outdir -d and -w filechecks and messages. Use hash instead of array for OIDs: OID key=name, value=numeric OID +. Prep for future gnuplot outfile: Add human-readable $startstamp and $donestamp. Change outfile to tab-delimited (was csv). Debug unwanted column 7 in outfile - epochsecs of endtime. Indenting to PerlStyle recommendation. Fix minor tyops. Rename to "snmpiio.pl" from "netsnmpiio.pl". Unlink .tmp at end of run. Confirm counter-roll-over-to-zero Does The Right Thing. No xls outfile if Spreadsheet::WriteExcel module not installed. Fix broken %util calculation. Correct minor tyops. Display MBytes transferred. Gracefully handle non-responsive (host|OID): (MBytes|Mbps|%Util) = -0.000 Snmp query syntax cleaner. Don't print snmp query or session errors. Fix incorrect Bps calculations. Create xls outfile from csv. Correct error in Usage and pod. 2001-08-13 10:35 CDT Gracefully handle counter-roll-over-to-zero; ~4,000,000,000 on CatOS 5. Cisco CatOS 5 Report 'blade #/port #' instead of '10/100 utp ethernet (cat 3/5) +'. Test with ActivePerl on Win2k. Fix sundry tyops. Post to PerlMonks networking code (requesting critique). Net::SNMP instead of UCD-SNMP system call: Initialize 'prior' array at '0' to eliminate annoying 'not numeric' message. Fix bad conversion math in pod. 2001-08-11 22:50 CDT Add example temp+csv output to pod. Round Bps to 0 decimal places. Round %util to 4 decimal places (100ths of %). Utilization percentage calculations, corrected for MegaBytes. Bypass bogus first Bps output since no prior epochSec. Bps calculations from raw SNMP data. Query ifSpeed for %util calculations. Defaults for all input values except target. Sanity-check $outdir: letters, numbers, dots, dashes, underscores. Filetest for write in outdir and outdir *is* directory. Simplify iteration localtime syntax. Cleaner syntax for no sleep after last iteration. Debug errant commas in csv. Unsubify snmp query localtime+time since only called once. @raw array instead of initial temp file. Filename of target-ifIndex-yyyymmdd.csv. Add hostname,oid,ifIndex to csv output. Use PcTime return values (print the values in main). Add $outdir. Sanity-check input for (wordchars|numbers) as appropriate. More informative Usage(). Input from commandline instead of hardcoded. Efforts to improve data structure. No sleep after last iteration. Leading-zero padded time/date in outfiles. yyyymmdd filenames w/sprintf. 2001-08-08 16:00 CDT Initial working code. =head1 TODOS Query + separate report: ifInDiscards, ifInErrors, icmpOutErrors, tcpInErrors, udpInErrors Query switch for host MAC+IP for outfile(s) header (SNMP::BridgeQuery +). then Query DNS for host name for outfile(s) header (Net::DNS). Retest with Win2k + ActivePerl. Retest with Win2k + Cygwin + Perl5.6. Pod:Usage to automagically synchronize pod with Usage(). available for < 5.6 ? Read params from external config file. =head1 AUTHOR ybiC =head1 CREDITS Thanks to: masem, merlyn, tachyon, HamNRye, tilly, lemming, wog, crazyinsomniac. Oh yeah, and to some guy named vroom. ;^) =cut

In reply to (code) Net::SNMP, Bandwidth, GnuPlot, PNG, PostScript, Excel by ybiC

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others lurking in the Monastery: (10)
    As of 2015-07-31 08:25 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









      Results (276 votes), past polls