mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-21 18:41:03 +00:00
More housecleaning.
Collapse some categories; remove duplicates; move plugins in where they belong, remove files that are not really plugins at all.
This commit is contained in:
parent
4e3ef5b93e
commit
0a1524f27f
45 changed files with 0 additions and 1337 deletions
|
@ -1,2 +0,0 @@
|
||||||
Check http://aouyar.github.com/PyMunin/ to get the most recent versionof the
|
|
||||||
PyMunin Multi graph Munin Plugins and documentation.
|
|
|
@ -1,702 +0,0 @@
|
||||||
#!/usr/bin/perl -w
|
|
||||||
# vim: sts=4 sw=4 ts=8
|
|
||||||
|
|
||||||
# Munin markers:
|
|
||||||
#%# family=auto
|
|
||||||
#%# capabilities=autoconf suggest
|
|
||||||
|
|
||||||
# Author: Michael Renner <michael.renner@amd.co.at>
|
|
||||||
|
|
||||||
# Version: 0.0.5, 2009-05-22
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
linux_diskstat_ - Munin plugin to monitor various values provided
|
|
||||||
via C</proc/diskstats>
|
|
||||||
|
|
||||||
=head1 APPLICABLE SYSTEMS
|
|
||||||
|
|
||||||
Linux 2.6 systems with extended block device statistics enabled.
|
|
||||||
|
|
||||||
|
|
||||||
=head1 INTERPRETATION
|
|
||||||
|
|
||||||
Among the more self-describing or well-known values like C<throughput>
|
|
||||||
(Bytes per second) there are a few which might need further introduction.
|
|
||||||
|
|
||||||
|
|
||||||
=head2 Device Utilization
|
|
||||||
|
|
||||||
Linux provides a counter which increments in a millisecond-interval for as long
|
|
||||||
as there are outstanding I/O requests. If this counter is close to 1000msec
|
|
||||||
in a given 1 second timeframe the device is nearly 100% saturated. This plugin
|
|
||||||
provides values averaged over a 5 minute time frame per default, so it can't
|
|
||||||
catch short-lived saturations, but it'll give a nice trend for semi-uniform
|
|
||||||
load patterns as they're expected in most server or multi-user environments.
|
|
||||||
|
|
||||||
|
|
||||||
=head2 Device IO Time
|
|
||||||
|
|
||||||
The C<Device IO Time> takes the counter described under C<Device Utilization>
|
|
||||||
and divides it by the number of I/Os that happened in the given time frame,
|
|
||||||
resulting in an average time per I/O on the block-device level.
|
|
||||||
|
|
||||||
This value can give you a good comparison base amongst different controllers,
|
|
||||||
storage subsystems and disks for similiar workloads.
|
|
||||||
|
|
||||||
|
|
||||||
=head2 Syscall Wait Time
|
|
||||||
|
|
||||||
These values describe the average time it takes between an application issuing
|
|
||||||
a syscall resulting in a hit to a blockdevice to the syscall returning to the
|
|
||||||
application.
|
|
||||||
|
|
||||||
The values are bound to be higher (at least for read requests) than the time
|
|
||||||
it takes the device itself to fulfill the requests, since calling overhead,
|
|
||||||
queuing times and probably a dozen other things are included in those times.
|
|
||||||
|
|
||||||
These are the values to watch out for when an user complains that C<the disks
|
|
||||||
are too slow!>.
|
|
||||||
|
|
||||||
|
|
||||||
=head3 What causes a block device hit?
|
|
||||||
|
|
||||||
A non-exhaustive list:
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item * Reads from files when the given range is not in the page cache or the O_DIRECT
|
|
||||||
flag is set.
|
|
||||||
|
|
||||||
=item * Writes to files if O_DIRECT or O_SYNC is set or sys.vm.dirty_(background_)ratio
|
|
||||||
is exceeded.
|
|
||||||
|
|
||||||
=item * Filesystem metadata operations (stat(2), getdents(2), file creation,
|
|
||||||
modification of any of the values returned by stat(2), etc.)
|
|
||||||
|
|
||||||
=item * The pdflush daemon writing out dirtied pages
|
|
||||||
|
|
||||||
=item * (f)sync
|
|
||||||
|
|
||||||
=item * Swapping
|
|
||||||
|
|
||||||
=item * raw device I/O (mkfs, dd, etc.)
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 ACKNOWLEDGEMENTS
|
|
||||||
|
|
||||||
The core logic of this script is based on the B<iostat> tool of the B<sysstat>
|
|
||||||
package written and maintained by Sebastien Godard.
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
See C<Documentation/iostats.txt> in your Linux source tree for further information
|
|
||||||
about the C<numbers> involved in this module.
|
|
||||||
|
|
||||||
L<http://www.westnet.com/~gsmith/content/linux-pdflush.htm> has a nice writeup
|
|
||||||
about the pdflush daemon.
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Michael Renner <michael.renner@amd.co.at>
|
|
||||||
|
|
||||||
=head1 LICENSE
|
|
||||||
|
|
||||||
GPLv2
|
|
||||||
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
|
|
||||||
use File::Basename;
|
|
||||||
use Carp;
|
|
||||||
use POSIX;
|
|
||||||
|
|
||||||
# We load our own version of save/restore_state if Munin::Plugin is unavailable.
|
|
||||||
# Don't try this at home
|
|
||||||
eval { require Munin::Plugin; Munin::Plugin->import; };
|
|
||||||
|
|
||||||
if ($@) {
|
|
||||||
fake_munin_plugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Sanity check to ensure that the script is called the correct name.
|
|
||||||
|
|
||||||
if (basename($0) !~ /^linux_diskstat_/) {
|
|
||||||
die qq(Please ensure that the name of the script and it's symlinks starts with "linux_diskstat_"\n);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
############
|
|
||||||
# autoconf #
|
|
||||||
############
|
|
||||||
|
|
||||||
if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
|
|
||||||
my %stats;
|
|
||||||
|
|
||||||
# Capture any croaks on the way
|
|
||||||
eval { %stats = parse_diskstats() };
|
|
||||||
|
|
||||||
if ( !$@ && keys %stats ) {
|
|
||||||
|
|
||||||
print "yes\n";
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "no\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
###########
|
|
||||||
# suggest #
|
|
||||||
###########
|
|
||||||
|
|
||||||
if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
|
|
||||||
|
|
||||||
my %diskstats = parse_diskstats();
|
|
||||||
|
|
||||||
my %suggested_devices;
|
|
||||||
|
|
||||||
DEVICE:
|
|
||||||
for my $devname ( sort keys %diskstats ) {
|
|
||||||
|
|
||||||
# Skip devices without traffic
|
|
||||||
next
|
|
||||||
if ( $diskstats{$devname}->{'rd_ios'} == 0
|
|
||||||
&& $diskstats{$devname}->{'wr_ios'} == 0 );
|
|
||||||
|
|
||||||
for my $existing_device ( @{ $suggested_devices{'iops'} } ) {
|
|
||||||
|
|
||||||
# Filter out devices (partitions) which are matched by existing ones
|
|
||||||
# e.g. sda1 -> sda, c0d0p1 -> c0d0
|
|
||||||
next DEVICE if ( $devname =~ m/$existing_device/ );
|
|
||||||
}
|
|
||||||
|
|
||||||
push @{ $suggested_devices{'iops'} }, $devname;
|
|
||||||
push @{ $suggested_devices{'throughput'} }, $devname;
|
|
||||||
|
|
||||||
# Only suggest latency graphs if the device supports it
|
|
||||||
if ( $diskstats{$devname}->{'rd_ticks'} > 0
|
|
||||||
|| $diskstats{$devname}->{'wr_ticks'} > 0 )
|
|
||||||
{
|
|
||||||
push @{ $suggested_devices{'latency'} }, $devname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $mode ( keys %suggested_devices ) {
|
|
||||||
for my $device ( sort @{ $suggested_devices{$mode} } ) {
|
|
||||||
|
|
||||||
my $printdev = translate_device_name($device, 'TO_FS');
|
|
||||||
print "${mode}_$printdev\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Reading the scripts invocation name and setting some parameters,
|
|
||||||
# needed from here on
|
|
||||||
|
|
||||||
my $basename = basename($0);
|
|
||||||
my ( $mode, $device ) = $basename =~ m/linux_diskstat_(\w+)_([-+\w]+)$/;
|
|
||||||
|
|
||||||
if ( not defined $device ) {
|
|
||||||
croak "Didn't get a device name. Aborting\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$device = translate_device_name($device, 'FROM_FS');
|
|
||||||
|
|
||||||
##########
|
|
||||||
# config #
|
|
||||||
##########
|
|
||||||
|
|
||||||
if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
|
|
||||||
|
|
||||||
my $pretty_device = $device;
|
|
||||||
|
|
||||||
if ($device =~ /^dm-\d+$/) {
|
|
||||||
$pretty_device = translate_devicemapper_name($device);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $mode eq 'latency' ) {
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
graph_title Disk latency for /dev/$pretty_device
|
|
||||||
graph_args --base 1000
|
|
||||||
graph_category disk
|
|
||||||
|
|
||||||
util.label Device utilization (percent)
|
|
||||||
util.type GAUGE
|
|
||||||
util.info Utilization of the device. If the time spent for I/O is close to 1000msec for a given second, the device is nearly 100% saturated.
|
|
||||||
util.min 0
|
|
||||||
svctm.label Average device IO time (ms)
|
|
||||||
svctm.type GAUGE
|
|
||||||
svctm.info Average time an I/O takes on the block device
|
|
||||||
svctm.min 0
|
|
||||||
avgwait.label Average IO Wait time (ms)
|
|
||||||
avgwait.type GAUGE
|
|
||||||
avgwait.info Average wait time for an I/O from request start to finish (includes queue times et al)
|
|
||||||
avgwait.min 0
|
|
||||||
avgrdwait.label Average Read IO Wait time (ms)
|
|
||||||
avgrdwait.type GAUGE
|
|
||||||
avgrdwait.info Average wait time for a read I/O from request start to finish (includes queue times et al)
|
|
||||||
avgrdwait.min 0
|
|
||||||
avgwrwait.label Average Write IO Wait time (ms)
|
|
||||||
avgwrwait.type GAUGE
|
|
||||||
avgwrwait.info Average wait time for a write I/O from request start to finish (includes queue times et al)
|
|
||||||
avgwrwait.min 0
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
|
||||||
elsif ( $mode eq 'throughput' ) {
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
graph_title Disk throughput for /dev/$pretty_device
|
|
||||||
graph_args --base 1024
|
|
||||||
graph_vlabel Bytes/second
|
|
||||||
graph_category disk
|
|
||||||
|
|
||||||
rdbytes.label Read Bytes
|
|
||||||
rdbytes.type GAUGE
|
|
||||||
rdbytes.min 0
|
|
||||||
wrbytes.label Write Bytes
|
|
||||||
wrbytes.type GAUGE
|
|
||||||
wrbytes.min 0
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
elsif ( $mode eq 'iops' ) {
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
graph_title Disk IOs for /dev/$pretty_device
|
|
||||||
graph_args --base 1000
|
|
||||||
graph_vlabel Units/second
|
|
||||||
graph_category disk
|
|
||||||
|
|
||||||
rdio.label Read IO/sec
|
|
||||||
rdio.type GAUGE
|
|
||||||
rdio.min 0
|
|
||||||
wrio.label Write IO/sec
|
|
||||||
wrio.type GAUGE
|
|
||||||
wrio.min 0
|
|
||||||
avgrqsz.label Average Request Size (KiB)
|
|
||||||
avgrqsz.type GAUGE
|
|
||||||
avgrqsz.min 0
|
|
||||||
avgrdrqsz.label Average Read Request Size (KiB)
|
|
||||||
avgrdrqsz.type GAUGE
|
|
||||||
avgrdrqsz.min 0
|
|
||||||
avgwrrqsz.label Average Write Request Size (KiB)
|
|
||||||
avgwrrqsz.type GAUGE
|
|
||||||
avgwrrqsz.min 0
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
croak "Unknown mode $mode\n";
|
|
||||||
}
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
########
|
|
||||||
# MAIN #
|
|
||||||
########
|
|
||||||
|
|
||||||
|
|
||||||
my %cur_diskstat = fetch_device_counters($device);
|
|
||||||
|
|
||||||
|
|
||||||
my ( $prev_time, %prev_diskstat ) = restore_state();
|
|
||||||
|
|
||||||
save_state( time(), %cur_diskstat );
|
|
||||||
|
|
||||||
# Probably the first run for the given device, we need state to do our job,
|
|
||||||
# so let's wait for the next run.
|
|
||||||
exit if ( not defined $prev_time or not %prev_diskstat );
|
|
||||||
|
|
||||||
calculate_and_print_values( $prev_time, \%prev_diskstat, \%cur_diskstat );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########
|
|
||||||
# SUBS #
|
|
||||||
########
|
|
||||||
|
|
||||||
sub calculate_and_print_values {
|
|
||||||
my ( $prev_time, $prev_stats, $cur_stats ) = @_;
|
|
||||||
|
|
||||||
my $bytes_per_sector = 512;
|
|
||||||
|
|
||||||
my $interval = time() - $prev_time;
|
|
||||||
|
|
||||||
my $read_ios = $cur_stats->{'rd_ios'} - $prev_stats->{'rd_ios'};
|
|
||||||
my $write_ios = $cur_stats->{'wr_ios'} - $prev_stats->{'wr_ios'};
|
|
||||||
|
|
||||||
my $rd_ticks = $cur_stats->{'rd_ticks'} - $prev_stats->{'rd_ticks'};
|
|
||||||
my $wr_ticks = $cur_stats->{'wr_ticks'} - $prev_stats->{'wr_ticks'};
|
|
||||||
|
|
||||||
my $rd_sectors = $cur_stats->{'rd_sectors'} - $prev_stats->{'rd_sectors'};
|
|
||||||
my $wr_sectors = $cur_stats->{'wr_sectors'} - $prev_stats->{'wr_sectors'};
|
|
||||||
|
|
||||||
my $tot_ticks = $cur_stats->{'tot_ticks'} - $prev_stats->{'tot_ticks'};
|
|
||||||
|
|
||||||
|
|
||||||
my $read_io_per_sec = $read_ios / $interval;
|
|
||||||
my $write_io_per_sec = $write_ios / $interval;
|
|
||||||
|
|
||||||
my $read_bytes_per_sec = $rd_sectors / $interval * $bytes_per_sector;
|
|
||||||
my $write_bytes_per_sec = $wr_sectors / $interval * $bytes_per_sector;
|
|
||||||
|
|
||||||
|
|
||||||
my $total_ios = $read_ios + $write_ios;
|
|
||||||
my $total_ios_per_sec = $total_ios / $interval;
|
|
||||||
|
|
||||||
# Utilization - or "how busy is the device"?
|
|
||||||
# If the time spent for I/O was close to 1000msec for
|
|
||||||
# a given second, the device is nearly 100% saturated.
|
|
||||||
my $utilization = $tot_ticks / $interval;
|
|
||||||
|
|
||||||
# Average time an I/O takes on the block device
|
|
||||||
my $servicetime =
|
|
||||||
$total_ios_per_sec ? $utilization / $total_ios_per_sec : 0;
|
|
||||||
|
|
||||||
# Average wait time for an I/O from start to finish
|
|
||||||
# (includes queue times et al)
|
|
||||||
my $average_wait = $total_ios ? ( $rd_ticks + $wr_ticks ) / $total_ios : 0;
|
|
||||||
my $average_rd_wait = $read_ios ? $rd_ticks / $read_ios : 0;
|
|
||||||
my $average_wr_wait = $write_ios ? $wr_ticks / $write_ios : 0;
|
|
||||||
|
|
||||||
my $average_rq_size_in_kb =
|
|
||||||
$total_ios
|
|
||||||
? ( $rd_sectors + $wr_sectors ) * $bytes_per_sector / 1024 / $total_ios
|
|
||||||
: 0;
|
|
||||||
my $average_rd_rq_size_in_kb =
|
|
||||||
$read_ios ? $rd_sectors * $bytes_per_sector / 1024 / $read_ios : 0;
|
|
||||||
my $average_wr_rq_size_in_kb =
|
|
||||||
$write_ios ? $wr_sectors * $bytes_per_sector / 1024 / $write_ios : 0;
|
|
||||||
|
|
||||||
my $util_print = $utilization / 10;
|
|
||||||
|
|
||||||
|
|
||||||
if ( $mode eq 'latency' ) {
|
|
||||||
print <<EOF;
|
|
||||||
|
|
||||||
util.value $util_print
|
|
||||||
svctm.value $servicetime
|
|
||||||
avgwait.value $average_wait
|
|
||||||
avgrdwait.value $average_rd_wait
|
|
||||||
avgwrwait.value $average_wr_wait
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
elsif ( $mode eq 'throughput' ) {
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
|
|
||||||
rdbytes.value $read_bytes_per_sec
|
|
||||||
wrbytes.value $write_bytes_per_sec
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
elsif ( $mode eq 'iops' ) {
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
|
|
||||||
rdio.value $read_io_per_sec
|
|
||||||
wrio.value $write_io_per_sec
|
|
||||||
avgrqsz.value $average_rq_size_in_kb
|
|
||||||
avgrdrqsz.value $average_rd_rq_size_in_kb
|
|
||||||
avgwrrqsz.value $average_wr_rq_size_in_kb
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
croak "Unknown mode $mode\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub read_diskstats {
|
|
||||||
|
|
||||||
open STAT, '< /proc/diskstats'
|
|
||||||
or croak "Failed to open '/proc/diskstats': $!\n";
|
|
||||||
|
|
||||||
my @lines;
|
|
||||||
|
|
||||||
for my $line (<STAT>) {
|
|
||||||
|
|
||||||
# Strip trailing newline and leading whitespace
|
|
||||||
chomp $line;
|
|
||||||
$line =~ s/^\s+//;
|
|
||||||
|
|
||||||
my @elems = split /\s+/, $line;
|
|
||||||
|
|
||||||
# We explicitly don't support old-style diskstats
|
|
||||||
# There are situations where only _some_ lines (e.g.
|
|
||||||
# partitions on older 2.6 kernels) have fewer stats
|
|
||||||
# numbers, therefore we'll skip them silently
|
|
||||||
if ( @elems != 14 ) {
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
push @lines, \@elems;
|
|
||||||
}
|
|
||||||
|
|
||||||
close STAT or croak "Failed to close '/proc/diskstats': $!";
|
|
||||||
return @lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub read_sysfs {
|
|
||||||
|
|
||||||
my ($want_device) = @_;
|
|
||||||
|
|
||||||
my @devices;
|
|
||||||
my @lines;
|
|
||||||
|
|
||||||
if ( defined $want_device ) {
|
|
||||||
|
|
||||||
# sysfs uses '!' as replacement for '/', e.g. cciss!c0d0
|
|
||||||
$want_device =~ tr#/#!#;
|
|
||||||
@devices = $want_device;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
@devices = glob "/sys/block/*/stat";
|
|
||||||
@devices = map { m!/sys/block/([^/]+)/stat! } @devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for my $cur_device (@devices) {
|
|
||||||
my $stats_file = "/sys/block/$cur_device/stat";
|
|
||||||
|
|
||||||
open STAT, "< $stats_file"
|
|
||||||
or croak "Failed to open '$stats_file': $!\n";
|
|
||||||
|
|
||||||
my $line = <STAT>;
|
|
||||||
|
|
||||||
# Trimming whitespace
|
|
||||||
$line =~ s/^\s+//;
|
|
||||||
chomp $line;
|
|
||||||
|
|
||||||
my @elems = split /\s+/, $line;
|
|
||||||
|
|
||||||
croak "'$stats_file' doesn't contain exactly 11 values. Aborting"
|
|
||||||
if ( @elems != 11 );
|
|
||||||
|
|
||||||
# Translate the devicename back before storing the information
|
|
||||||
$cur_device =~ tr#!#/#;
|
|
||||||
|
|
||||||
# Faking missing diskstats values
|
|
||||||
unshift @elems, ( '', '', $cur_device );
|
|
||||||
|
|
||||||
push @lines, \@elems;
|
|
||||||
|
|
||||||
close STAT or croak "Failed to close '$stats_file': $!\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return @lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub parse_diskstats {
|
|
||||||
|
|
||||||
my ($want_device) = @_;
|
|
||||||
|
|
||||||
my @stats;
|
|
||||||
|
|
||||||
if ( glob "/sys/block/*/stat" ) {
|
|
||||||
|
|
||||||
@stats = read_sysfs($want_device);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
@stats = read_diskstats();
|
|
||||||
}
|
|
||||||
|
|
||||||
my %diskstats;
|
|
||||||
|
|
||||||
for my $entry (@stats) {
|
|
||||||
|
|
||||||
my %devstat;
|
|
||||||
|
|
||||||
# Hash-Slicing for fun and profit
|
|
||||||
@devstat{
|
|
||||||
qw(major minor devname
|
|
||||||
rd_ios rd_merges rd_sectors rd_ticks
|
|
||||||
wr_ios wr_merges wr_sectors wr_ticks
|
|
||||||
ios_in_prog tot_ticks rq_ticks)
|
|
||||||
}
|
|
||||||
= @{$entry};
|
|
||||||
|
|
||||||
$diskstats{ $devstat{'devname'} } = \%devstat;
|
|
||||||
}
|
|
||||||
|
|
||||||
return %diskstats;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub fetch_device_counters {
|
|
||||||
|
|
||||||
my ($want_device) = @_;
|
|
||||||
|
|
||||||
my %diskstats = parse_diskstats($want_device);
|
|
||||||
|
|
||||||
for my $devname ( keys %diskstats ) {
|
|
||||||
|
|
||||||
if ( $want_device eq $devname ) {
|
|
||||||
return %{ $diskstats{$devname} };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# We use '+' (and formerly '-') as placeholder for '/' in device-names
|
|
||||||
# used as calling name for the script.
|
|
||||||
sub translate_device_name {
|
|
||||||
|
|
||||||
my ($device, $mode) = @_;
|
|
||||||
|
|
||||||
if ($mode eq 'FROM_FS') {
|
|
||||||
|
|
||||||
# Hackaround to mitigate issues with unwisely chosen former separator
|
|
||||||
if ( not ($device =~ m/dm-\d+/)) {
|
|
||||||
$device =~ tr#-+#//#;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
elsif ($mode eq 'TO_FS') {
|
|
||||||
|
|
||||||
$device =~ tr#/#+#;
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
croak "translate_device_name: Unknown mode\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $device;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub fake_munin_plugin {
|
|
||||||
my $eval_code = <<'EOF';
|
|
||||||
|
|
||||||
use Storable;
|
|
||||||
my $storable_filename = basename($0);
|
|
||||||
$storable_filename = "/tmp/munin-state-$storable_filename";
|
|
||||||
|
|
||||||
sub save_state {
|
|
||||||
my @state = @_;
|
|
||||||
|
|
||||||
if ( not -e $storable_filename or -f $storable_filename ) {
|
|
||||||
store \@state, $storable_filename or croak "Failed to persist state to '$storable_filename': $!\n";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
croak "$storable_filename is probably not a regular file. Please delete it.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub restore_state {
|
|
||||||
|
|
||||||
if (-f $storable_filename) {
|
|
||||||
my $state = retrieve($storable_filename);
|
|
||||||
return @{$state};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
eval($eval_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub translate_devicemapper_name {
|
|
||||||
my ($device) = @_;
|
|
||||||
|
|
||||||
my ($want_minor) = $device =~ m/^dm-(\d+)$/;
|
|
||||||
|
|
||||||
croak "Failed to extract devicemapper id" unless defined ($want_minor);
|
|
||||||
|
|
||||||
my $dm_major = find_devicemapper_major();
|
|
||||||
croak "Failed to get device-mapper major number\n" unless defined $dm_major;
|
|
||||||
|
|
||||||
for my $entry (glob "/dev/mapper/\*") {
|
|
||||||
|
|
||||||
my $rdev = (stat($entry))[6];
|
|
||||||
my $major = floor($rdev / 256);
|
|
||||||
my $minor = $rdev % 256;
|
|
||||||
|
|
||||||
if ($major == $dm_major && $minor == $want_minor) {
|
|
||||||
|
|
||||||
my $pretty_name = translate_lvm_name($entry);
|
|
||||||
|
|
||||||
return defined $pretty_name ? $pretty_name : $entry;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Return original string if the device can't be found.
|
|
||||||
return $device;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub translate_lvm_name {
|
|
||||||
|
|
||||||
my ($entry) = @_;
|
|
||||||
|
|
||||||
my $device_name = basename($entry);
|
|
||||||
|
|
||||||
# Check for single-dash-occurence to see if this could be a lvm devicemapper device.
|
|
||||||
if ($device_name =~ m/(?<!-)-(?!-)/) {
|
|
||||||
|
|
||||||
# split device name into vg and lv parts
|
|
||||||
my ($vg, $lv) = split /(?<!-)-(?!-)/, $device_name, 2;
|
|
||||||
return undef unless ( defined($vg) && defined($lv) );
|
|
||||||
|
|
||||||
# remove extraneous dashes from vg and lv names
|
|
||||||
$vg =~ s/--/-/g;
|
|
||||||
$lv =~ s/--/-/g;
|
|
||||||
|
|
||||||
$device_name = "$vg/$lv";
|
|
||||||
|
|
||||||
# Sanity check - does the constructed device name exist?
|
|
||||||
if (stat("/dev/$device_name")) {
|
|
||||||
return "$device_name";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub find_devicemapper_major {
|
|
||||||
|
|
||||||
open (FH, '< /proc/devices') or croak "Failed to open '/proc/devices': $!";
|
|
||||||
|
|
||||||
my $dm_major;
|
|
||||||
|
|
||||||
for my $line (<FH>) {
|
|
||||||
chomp $line;
|
|
||||||
|
|
||||||
my ($major, $name) = split /\s+/, $line, 2;
|
|
||||||
|
|
||||||
next unless defined $name;
|
|
||||||
|
|
||||||
if ($name eq 'device-mapper') {
|
|
||||||
$dm_major = $major;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(FH);
|
|
||||||
|
|
||||||
return $dm_major;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
Check http://aouyar.github.com/PyMunin/
|
|
||||||
to get the most recent versionof the PyMunin Multi graph Munin Plugins and documentation.
|
|
|
@ -1,106 +0,0 @@
|
||||||
#!/usr/bin/perl -w
|
|
||||||
#
|
|
||||||
# Plugin to monitor BGP table summary statistics on a cisco router.
|
|
||||||
#
|
|
||||||
# Original Author: Peter Holzleitner
|
|
||||||
#
|
|
||||||
# Revision 1.1 2010/10/14 19:19
|
|
||||||
#
|
|
||||||
# Configuration variables:
|
|
||||||
#
|
|
||||||
# iosuser - username (default "")
|
|
||||||
# iospass - password (default "")
|
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
#
|
|
||||||
# config (required)
|
|
||||||
#
|
|
||||||
# Magic markers (optional - only used by munin-config and some
|
|
||||||
# installation scripts):
|
|
||||||
#%# family=auto
|
|
||||||
|
|
||||||
|
|
||||||
use Net::Telnet::Cisco;
|
|
||||||
use Sys::Syslog;
|
|
||||||
|
|
||||||
|
|
||||||
if ($0 =~ /^(?:|.*\/)cisco_bgp_([^_]+)$/) {
|
|
||||||
$host = $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
($^O eq "linux" || $^O eq "openbsd") && Sys::Syslog::setlogsock('unix');
|
|
||||||
openlog('munin.bgp', 'cons,pid', 'daemon');
|
|
||||||
|
|
||||||
|
|
||||||
my @BGP_nbr;
|
|
||||||
my @BGP_pfx;
|
|
||||||
my $tot_pfx;
|
|
||||||
my $iosuser = $ENV{iosuser} || "";
|
|
||||||
my $iospass = $ENV{iospass} || "";
|
|
||||||
|
|
||||||
&fetch_bgpstats($host, $iosuser, $iospass);
|
|
||||||
|
|
||||||
|
|
||||||
if ($ARGV[0] and $ARGV[0] eq "config") {
|
|
||||||
print "host_name $host\n";
|
|
||||||
print "graph_args --base 1024 -l 0 --vertical-label Prefixes\n";
|
|
||||||
print "graph_title BGP Neighbour Statistics\n";
|
|
||||||
print "graph_category network\n";
|
|
||||||
print "graph_info This graph shows the number of BGP prefixes received by neighbour.\n";
|
|
||||||
|
|
||||||
my($n, $i); $n = scalar @BGP_nbr; $i = 0;
|
|
||||||
while($n--) {
|
|
||||||
my $neigh = $BGP_nbr[$i++];
|
|
||||||
print "n$i.label $neigh\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# print "total.label Total\n";
|
|
||||||
# print "total.info Total number of prefixes in the BGP table\n";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
my($n, $i); $n = scalar @BGP_nbr; $i = 0;
|
|
||||||
while($n--) {
|
|
||||||
my $pfx = $BGP_pfx[$i++];
|
|
||||||
print "n$i.value $pfx\n";
|
|
||||||
}
|
|
||||||
# print "total.value $tot_pfx\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub fetch_bgpstats
|
|
||||||
{
|
|
||||||
my $hostname = shift;
|
|
||||||
my $username = shift;
|
|
||||||
my $password = shift;
|
|
||||||
my $session = Net::Telnet::Cisco->new(Host => $host);
|
|
||||||
|
|
||||||
$session->login($username, $password);
|
|
||||||
$session->cmd('terminal length 200');
|
|
||||||
$session->cmd('terminal width 200');
|
|
||||||
my @output = $session->cmd('show ip bgp summary');
|
|
||||||
|
|
||||||
# example output of router
|
|
||||||
# ------------------------
|
|
||||||
# [...]
|
|
||||||
# Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
|
|
||||||
# 11.111.11.111 4 98765 12403694 509571 308911893 0 0 1d23h 329193
|
|
||||||
# 122.122.122.122 4 1234 13242856 383827 308911879 0 0 00:08:22 330761
|
|
||||||
|
|
||||||
foreach(@output) {
|
|
||||||
chomp; s/\r//g;
|
|
||||||
$tot_pfx = $1 if /^BGP activity (\d+)\/(\d+) prefixes/;
|
|
||||||
syslog('debug', "$hostname: $_\n");
|
|
||||||
|
|
||||||
next unless /^(\d+\.\d+\.\d+\.\d+)\s+\d+\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+[0-9a-z:]+\s+(\d+)/;
|
|
||||||
my ($neigh, $as, $pfx) = ($1, $2, $3);
|
|
||||||
syslog('debug', "$neigh (AS $as)");
|
|
||||||
push @BGP_nbr, "$neigh (AS $as)";
|
|
||||||
push @BGP_pfx, $pfx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# vim:syntax=perl:ts=8
|
|
|
@ -1,378 +0,0 @@
|
||||||
#!/usr/bin/perl
|
|
||||||
#
|
|
||||||
=head1 OPENTRACKER PLUGIN
|
|
||||||
|
|
||||||
A Plugin to monitor OpenTracker Servers and their Performance
|
|
||||||
|
|
||||||
=head1 MUNIN CONFIGURATION
|
|
||||||
|
|
||||||
[opentracker*]
|
|
||||||
env.host 127.0.0.1 *default*
|
|
||||||
env.port 6969 *default*
|
|
||||||
env.uri /stats *default*
|
|
||||||
|
|
||||||
=head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
|
|
||||||
|
|
||||||
host = opentracker host to connect to
|
|
||||||
port = opentracker http port to connect to
|
|
||||||
uri = stats uri for appending requests for data
|
|
||||||
|
|
||||||
I need this information so I can later build the full url which normally
|
|
||||||
looks like the following example when put together:
|
|
||||||
http://127.0.0.1:6969/stats?mode=conn
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Matt West < https://github.com/mhwest13/OpenTracker-Munin-Plugin >
|
|
||||||
|
|
||||||
=head1 LICENSE
|
|
||||||
|
|
||||||
GPLv2
|
|
||||||
|
|
||||||
=head1 MAGIC MARKERS
|
|
||||||
|
|
||||||
#%# family=auto
|
|
||||||
#%# capabilities=autoconf suggest
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use File::Basename;
|
|
||||||
use LWP::UserAgent;
|
|
||||||
|
|
||||||
if (basename($0) !~ /^opentracker_/) {
|
|
||||||
print "This script needs to be named opentracker_ and have symlinks which start the same.\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $host = $ENV{host} || '127.0.0.1';
|
|
||||||
my $port = $ENV{port} || 6969;
|
|
||||||
my $uri = $ENV{uri} || '/stats';
|
|
||||||
|
|
||||||
=head1 Graph Declarations
|
|
||||||
|
|
||||||
This block of code builds up all of the graph info for all root / sub graphs.
|
|
||||||
|
|
||||||
%graphs is a container for all of the graph definition information. In here is where you'll
|
|
||||||
find the configuration information for munin's graphing procedure.
|
|
||||||
Format:
|
|
||||||
|
|
||||||
$graph{graph_name} => {
|
|
||||||
config => {
|
|
||||||
{ key => value }, You'll find the main graph config stored here.
|
|
||||||
{ ... },
|
|
||||||
},
|
|
||||||
keys => [ 'Name', 'Name', 'Name', ... ], Used for building results set.
|
|
||||||
datasrc => [
|
|
||||||
# Name: name given to data value
|
|
||||||
# Attr: Attribute for given value, attribute must be valid plugin argument
|
|
||||||
{ name => 'Name', info => 'info about graph' },
|
|
||||||
{ ... },
|
|
||||||
],
|
|
||||||
results => {
|
|
||||||
{ key => value }, You'll find the results info from fetch_stats call stored here.
|
|
||||||
{ ... },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
my %graphs;
|
|
||||||
|
|
||||||
# graph for connections
|
|
||||||
$graphs{conn} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'Connections',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'Current Connections',
|
|
||||||
info => 'Current Connections to OpenTracker',
|
|
||||||
},
|
|
||||||
keys => [ 'Requests', 'Announces' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Requests', label => 'Requests', min => '0', type => 'COUNTER', info => 'number of Requests', draw => 'AREA' },
|
|
||||||
{ name => 'Announces', label => 'Announces', min => '0', type => 'COUNTER', info => 'number of Announces', draw => 'LINE2' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for peers
|
|
||||||
$graphs{peer} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'Peers',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'Peers and Seeders',
|
|
||||||
info => 'Current Peer and Seeder Connections',
|
|
||||||
},
|
|
||||||
keys => [ 'Peers', 'Seeders' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Peers', label => 'Peers', min => '0', type => 'GAUGE', info => 'current number of leechers & seeders (peers)', draw => 'AREA' },
|
|
||||||
{ name => 'Seeders', label => 'Seeders', min => '0', type => 'GAUGE', info => 'current number of seeders', draw => 'LINE2' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for scrapes
|
|
||||||
$graphs{scrp} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'Scrapes',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'Scrapes',
|
|
||||||
info => 'Number of Scrapes (TCP/UDP)',
|
|
||||||
},
|
|
||||||
keys => [ 'TCP', 'UDP' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'TCP', label => 'TCP Requests', min => '0', type => 'COUNTER', info => 'number of scrapes requested via tcp', draw => 'AREASTACK' },
|
|
||||||
{ name => 'UDP', label => 'UDP Requests', min => '0', type => 'COUNTER', info => 'number of scrapes requested via udp', draw => 'AREA' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for livesyncs
|
|
||||||
$graphs{syncs} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'Syncs',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'LiveSyncs',
|
|
||||||
info => 'OpenTracker LiveSync Requests',
|
|
||||||
},
|
|
||||||
keys => [ 'Incoming', 'Outgoing' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Incoming', label => 'Incoming Syncs', min => '0', type => 'COUNTER', info => 'number of Incoming Syncs', draw => 'AREA' },
|
|
||||||
{ name => 'Outgoing', label => 'Outgoing Syncs', min => '0', type => 'COUNTER', info => 'number of Outgoing Syncs', draw => 'LINE2' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for tcp4 connections
|
|
||||||
$graphs{tcp4} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'TCP4 Requests',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'TCP4 Requests',
|
|
||||||
info => 'Current TCP4 Requests / Announces',
|
|
||||||
},
|
|
||||||
keys => [ 'Requests', 'Announces' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Requests', label => 'Requests', min => '0', type => 'COUNTER', info => 'number of tcp4 Requests', draw => 'AREA' },
|
|
||||||
{ name => 'Announces', label => 'Announces', min => '0', type => 'COUNTER', info => 'number of tcp4 Announces', draw => 'LINE2' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for torrents
|
|
||||||
$graphs{torr} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => '# of Torrents',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'Torrents',
|
|
||||||
info => 'Current number of Torrents',
|
|
||||||
},
|
|
||||||
keys => [ 'Torrents' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Torrents', label => 'Torrents', min => '0', type => 'GAUGE', info => 'number of torrents', draw => 'AREA' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
# graph for udp4 connections
|
|
||||||
$graphs{udp4} = {
|
|
||||||
config => {
|
|
||||||
args => '--lower-limit 0',
|
|
||||||
vlabel => 'UDP4 Requests',
|
|
||||||
category => 'opentracker',
|
|
||||||
title => 'UDP4 Requests',
|
|
||||||
info => 'Current UDP4 Requests / Announces',
|
|
||||||
},
|
|
||||||
keys => [ 'Requests', 'Announces' ],
|
|
||||||
datasrc => [
|
|
||||||
{ name => 'Requests', label => 'Requests', min => '0', type => 'COUNTER', info => 'number of udp4 Requests', draw => 'AREA' },
|
|
||||||
{ name => 'Announces', label => 'Announces', min => '0', type => 'COUNTER', info => 'number of udp4 Announces', draw => 'LINE2' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
=head1 Munin Checks
|
|
||||||
|
|
||||||
These checks look for config / autoconf / suggest params
|
|
||||||
|
|
||||||
=head2 Config Check
|
|
||||||
|
|
||||||
This block of code looks at the argument that is possibly supplied,
|
|
||||||
should it be config, it then checks to make sure the plugin
|
|
||||||
specified exists, assuming it does, it will run the do_config
|
|
||||||
subroutine for the plugin specified, otherwise it dies complaining
|
|
||||||
about an unknown plugin.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
if (defined $ARGV[0] && $ARGV[0] eq 'config') {
|
|
||||||
# Lets take the plugin from the execution name.
|
|
||||||
$0 =~ /opentracker_(.+)*/;
|
|
||||||
my $plugin = $1;
|
|
||||||
# And lets make sure we have a plugin called that.
|
|
||||||
die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
|
|
||||||
# Now lets go ahead and print out our config.
|
|
||||||
print_config($plugin);
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 Autoconf Check
|
|
||||||
|
|
||||||
This block of code looks at the argument that is possibly supplied,
|
|
||||||
should it be autoconf, we are going to print yes at this point since
|
|
||||||
we've already tested for our binary to exist and be executable, the
|
|
||||||
process will then exit.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
if (defined $ARGV[0] && $ARGV[0] eq 'autoconf') {
|
|
||||||
# well we can execute the binary, so lets make sure we can curl opentracker
|
|
||||||
my $url = "http://".$host.":".$port.$uri."\?mode=version";
|
|
||||||
my $ua = LWP::UserAgent->new;
|
|
||||||
$ua->timeout(15);
|
|
||||||
my $response = $ua->get($url);
|
|
||||||
if ($response->is_success) {
|
|
||||||
print "yes\n";
|
|
||||||
exit 0;
|
|
||||||
} else {
|
|
||||||
print "no: unable to connect to url: $url\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 Suggest Check
|
|
||||||
|
|
||||||
This block of code looks at the argument that is possibly supplied,
|
|
||||||
should it be suggest, we are going to print the possible plugins
|
|
||||||
which can be specified.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
if (defined $ARGV[0] && $ARGV[0] eq 'suggest') {
|
|
||||||
# well we can execute the binary, so print possible plugin names
|
|
||||||
my @rootplugins = ('conn','peer','scrp','syncs','tcp4','torr','udp4');
|
|
||||||
foreach my $plugin (@rootplugins) {
|
|
||||||
print "$plugin\n";
|
|
||||||
}
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head1 Subroutines
|
|
||||||
|
|
||||||
Begin Subroutine calls to output data / config information
|
|
||||||
|
|
||||||
=head2 fetch_output
|
|
||||||
|
|
||||||
This subroutine is the main call for printing data for the plugin.
|
|
||||||
No parameters are taken as this is the default call if no arguments
|
|
||||||
are supplied from the command line.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
fetch_output();
|
|
||||||
|
|
||||||
sub fetch_output {
|
|
||||||
# Lets figure out what plugin they want to run, and check that it exists
|
|
||||||
$0 =~ /opentracker_(.+)*/;
|
|
||||||
my $plugin = $1;
|
|
||||||
die 'Unknown Plugin Specified: ' . ($plugin ? $plugin : '') unless $graphs{$plugin};
|
|
||||||
# Lets print out the data for our plugin
|
|
||||||
print_output($plugin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 print_output
|
|
||||||
|
|
||||||
This block of code prints out the return values for our graphs. It takes
|
|
||||||
one parameter $plugin. Returns when completed
|
|
||||||
|
|
||||||
$plugin; graph we are calling up to print data values for
|
|
||||||
|
|
||||||
Example: print_output($plugin);
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub print_output {
|
|
||||||
# Lets get our plugin, set our graph information, and print for Munin to process
|
|
||||||
my ($plugin) = (@_);
|
|
||||||
my $graph = $graphs{$plugin};
|
|
||||||
print "graph opentracker_$plugin\n";
|
|
||||||
# Getting keys to pass to fetch_stats for data retrieval
|
|
||||||
# call up fetch_stats with the keys we just got.
|
|
||||||
my @keys = @{$graph->{keys}};
|
|
||||||
fetch_stats($plugin,@keys);
|
|
||||||
# print the results for the keys with the name for Munin to process
|
|
||||||
foreach my $dsrc (@{$graph->{datasrc}}) {
|
|
||||||
my $output = 0;
|
|
||||||
my %datasrc = %$dsrc;
|
|
||||||
while ( my ($key, $value) = each(%datasrc)) {
|
|
||||||
next if ($key ne 'name');
|
|
||||||
print "$dsrc->{name}.value $graph->{results}->{$value}\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 print_config
|
|
||||||
|
|
||||||
This subroutine prints out the main config information for all of the graphs.
|
|
||||||
It takes one parameters, $plugin
|
|
||||||
|
|
||||||
$plugin; graph being called up to print config for
|
|
||||||
|
|
||||||
Example: print_config($plugin);
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub print_config {
|
|
||||||
# Lets get our plugin and graph, after that print for Munin to process it.
|
|
||||||
my ($plugin) = (@_);
|
|
||||||
my $graph = $graphs{$plugin};
|
|
||||||
print "graph opentracker_$plugin\n";
|
|
||||||
# Lets print out graph's main config info.
|
|
||||||
my %graphconf = %{$graph->{config}};
|
|
||||||
while ( my ($key, $value) = each(%graphconf)) {
|
|
||||||
print "graph_$key $value\n";
|
|
||||||
}
|
|
||||||
# Lets print our graphs per graph config info.
|
|
||||||
foreach my $dsrc (@{$graph->{datasrc}}) {
|
|
||||||
my %datasrc = %$dsrc;
|
|
||||||
while ( my ($key, $value) = each(%datasrc)) {
|
|
||||||
next if ($key eq 'name');
|
|
||||||
print "$dsrc->{name}.$key $value\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 fetch_stats
|
|
||||||
|
|
||||||
This subroutine actually fetches data from opentracker with the plugin specified
|
|
||||||
It will then parse the data using the keys assigned in an array.
|
|
||||||
Two parameters are passed, $plugin and @keys, and it will return when complete.
|
|
||||||
|
|
||||||
$plugin; graph we are calling up, we use this to store the results in the hash
|
|
||||||
for easy recall later.
|
|
||||||
@keys; keys we want the values for from opentracker stats url.
|
|
||||||
|
|
||||||
Example: fetch_stats($plugin,@keys);
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub fetch_stats {
|
|
||||||
# Lets get our current plugin and list of keys we want info for, as well as reference our graph
|
|
||||||
my ($plugin,@keys) = (@_);
|
|
||||||
my $graph = $graphs{$plugin};
|
|
||||||
# Lets create our url to fetch
|
|
||||||
my $url = "http://".$host.":".$port.$uri."\?mode=".$plugin;
|
|
||||||
my $ua = LWP::UserAgent->new;
|
|
||||||
$ua->timeout(15);
|
|
||||||
my $response = $ua->get($url);
|
|
||||||
# Lets print some info since we got back some info
|
|
||||||
if ($response->is_success) {
|
|
||||||
my @tmparray = split("\n",$response->content);
|
|
||||||
foreach my $key (@keys) {
|
|
||||||
my $value = shift(@tmparray);
|
|
||||||
$graph->{results}->{$key} = $value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print "Unable to Fetch data from URL: $url\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
Check http://aouyar.github.com/PyMunin/ to get the most recent versionof the
|
|
||||||
PyMunin Multi graph Munin Plugins and documentation.
|
|
|
@ -1,2 +0,0 @@
|
||||||
Check http://aouyar.github.com/PyMunin/
|
|
||||||
to get the most recent versionof the PyMunin Multi graph Munin Plugins and documentation.
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/usr/bin/perl -w
|
|
||||||
#
|
|
||||||
|
|
||||||
require LWP::UserAgent;
|
|
||||||
|
|
||||||
########################################################################################
|
|
||||||
#
|
|
||||||
# Installation / Configuration
|
|
||||||
#
|
|
||||||
# - place munin_xcache.php in a directory on your webserver
|
|
||||||
# - add the url config to plugin-conf.d/munin-node
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# for more info see http://www.ohardt.net/dev/munin/
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
chomp(my $fqdn=`hostname -f`);
|
|
||||||
|
|
||||||
|
|
||||||
my $URL = exists $ENV{'url'} ? $ENV{'url'} : "http://user:pwd\@$fqdn/munin_xcache_new.php";
|
|
||||||
|
|
||||||
$URL = $URL . "?what=mem";
|
|
||||||
|
|
||||||
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
||||||
|
|
||||||
|
|
||||||
if ( exists $ARGV[0] and $ARGV[0] eq "config" )
|
|
||||||
{
|
|
||||||
|
|
||||||
$URL = $URL . '&config';
|
|
||||||
|
|
||||||
my $response = $ua->request(HTTP::Request->new('GET',$URL . '&config' ));
|
|
||||||
|
|
||||||
print $response->content;
|
|
||||||
|
|
||||||
|
|
||||||
exit( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my $response = $ua->request(HTTP::Request->new('GET',$URL));
|
|
||||||
|
|
||||||
|
|
||||||
print $response->content;
|
|
||||||
|
|
||||||
|
|
||||||
exit( 0 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
Check http://aouyar.github.com/PyMunin/ to get the most recent versionof the
|
|
||||||
PyMunin Multi graph Munin Plugins and documentation.
|
|
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# toshiba_5520c_print_ munin grabber script
|
|
||||||
# 2009.01 by steve@kosada.com
|
|
||||||
|
|
||||||
destination=`basename $0 | sed 's/^toshiba_5520c_print_//g'`
|
|
||||||
|
|
||||||
if [ "$1" = "config" ]; then
|
|
||||||
echo "graph_title Toshiba 5520C: Pages Printed"
|
|
||||||
echo 'graph_vlabel Pages'
|
|
||||||
echo 'graph_args --lower-limit 0'
|
|
||||||
echo 'graph_category printer'
|
|
||||||
|
|
||||||
echo "printBlack.label Black"
|
|
||||||
echo "printBlack.draw AREA"
|
|
||||||
|
|
||||||
echo "printFullColor.label Full Color"
|
|
||||||
echo "printFullColor.draw STACK"
|
|
||||||
|
|
||||||
echo "printTwinColor.label Twin Color"
|
|
||||||
echo "printTwinColor.draw STACK"
|
|
||||||
else
|
|
||||||
infopage=`wget -q -O - http://$destination:8080/TopAccess/Counter/TotalCount/List.htm | dos2unix | perl -p -e 's/\n/ /m'`
|
|
||||||
|
|
||||||
echo printFullColor.value `echo $infopage | perl -p -e 's/^.+\<B\>Print Counter\<\/B\>.+?\{Full\ Color[^}]+\,([0-9]+)\}.+$/$1/'`
|
|
||||||
echo printTwinColor.value `echo $infopage | perl -p -e 's/^.+\<B\>Print Counter\<\/B\>.+?\{Twin\ Color[^}]+\,([0-9]+)\}.+$/$1/'`
|
|
||||||
echo printBlack.value `echo $infopage | perl -p -e 's/^.+\<B\>Print Counter\<\/B\>.+?\{Black[^}]+\,([0-9]+)\}.+$/$1/'`
|
|
||||||
fi
|
|
|
@ -1,59 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
HOST=${host:-"127.0.0.1"}
|
|
||||||
|
|
||||||
: << =cut
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
snmp_HPLJ2015 - Consumables level on HP LaserJet 2015n reported over SNMP
|
|
||||||
|
|
||||||
=head1 CONFIGURATION
|
|
||||||
|
|
||||||
HOST
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Oleksiy Kochkin
|
|
||||||
|
|
||||||
=head1 LICENSE
|
|
||||||
|
|
||||||
As is.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 MAGIC MARKERS
|
|
||||||
|
|
||||||
#%# family=contrib
|
|
||||||
#%# capabilities=autoconf
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
config)
|
|
||||||
|
|
||||||
echo "graph_title Consumables level @ $HOST"
|
|
||||||
echo 'graph_args --upper-limit 100 -l 0'
|
|
||||||
echo 'graph_vlabel %'
|
|
||||||
echo 'graph_category printers'
|
|
||||||
echo 'graph_scale no'
|
|
||||||
echo 'black.label Black toner level'
|
|
||||||
echo 'black.draw LINE2'
|
|
||||||
echo 'black.type GAUGE'
|
|
||||||
echo 'black.colour 000000'
|
|
||||||
echo 'black.warning 5:'
|
|
||||||
echo 'black.critical 1:'
|
|
||||||
echo 'black.min 0'
|
|
||||||
echo 'black.max 100'
|
|
||||||
exit 0;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
BLACK_MAX_OID=".1.3.6.1.2.1.43.11.1.1.8.1.1"
|
|
||||||
BLACK_LVL_OID=".1.3.6.1.2.1.43.11.1.1.9.1.1"
|
|
||||||
|
|
||||||
BLACK_MAX=`snmpget -v 1 -c public -Ov -Oq $HOST $BLACK_MAX_OID`
|
|
||||||
BLACK_LVL=`snmpget -v 1 -c public -Ov -Oq $HOST $BLACK_LVL_OID`
|
|
||||||
BLACK_LVL_PERCENTS=$(($BLACK_LVL*100/$BLACK_MAX))
|
|
||||||
|
|
||||||
echo -n "black.value "
|
|
||||||
echo $BLACK_LVL_PERCENTS
|
|
Loading…
Add table
Add a link
Reference in a new issue