Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

comment on

( [id://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":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (7)
As of 2024-03-28 08:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found