2
0
mirror of https://github.com/munin-monitoring/contrib.git synced 2018-11-08 00:59:34 +01:00

Merge branch 'master' of github.com:munin-monitoring/contrib

This commit is contained in:
Matt West 2012-02-09 09:53:35 -08:00
commit 59f28e56ed
11 changed files with 461 additions and 27 deletions

View File

@ -1,5 +1,27 @@
This is the repository for all user contributed stuff
* contrib/tools/ is for 3rd-party tools. It usually serves as an incubator of trunk/contrib.
* contrib/plugins/ is for 3rd-party plugins. It will serve as the backend of exchange.munin-monitoring.org when it is operational again.
* contrib/templates/ is for 3rd-party templates. Feel free to update templates, or even to create new ones. Bonus points for mobile-friendly ones :)
# contrib/plugins/ - 3rd-party plugins
**This is usually where you want to begin your journey.**
Here you'll find all the plugins coming from http://exchange.munin-monitoring.org/.
It as evolved since then, but
# contrib/templates/ - 3rd-party templates
Feel free to update templates here, or even to create new ones.
Bonus points for mobile-friendly ones :)
Note that the one named `official` is a loose-synced copy of the one in SVN trunk.
It should serves as a base for small editions that can be resynced in SVN trunk, so for that :
* don't copy the whole template
* directly edit files in this directory
# contrib/tools/ - 3rd-party tools
Here, you can put just any kind of tool. Please use this directory instead of a random place on the internet.
It makes things way more easy to search for others.
And, it serves as an incubator of SVN `trunk/contrib` :-)

View File

@ -43,7 +43,6 @@ shopt -s extglob
EJCTL=$(which ejabberdctl)
EJVER=$($EJCTL status | awk '/^ejabberd / {print $2}')
MUNIN_DEBUG=${MUNIN_DEBUG:-0}
if [ "$1" == "autoconf" ]; then
if [ -x $EJCTL > /dev/null ]; then

View File

@ -5,7 +5,7 @@
# sample config in /etc/munin/plugin-conf.d/riak
#
# [riak_*]
# RIAK_URL=http://127.0.0.1:8091/stats
# env.RIAK_URL http://127.0.0.1:8091/stats
# any questions to fygrave at o0o dot nu
#
# This plugin monitors memory allocation on each node.

View File

@ -4,7 +4,7 @@
# sample config in /etc/munin/plugin-conf.d/riak
#
# [riak_*]
# RIAK_URL=http://127.0.0.1:8091/stats
# env.RIAK_URL http://127.0.0.1:8091/stats
# any questions to fygrave at o0o dot nu
#
# This plugin monitors put/get rate at each node.

View File

@ -104,7 +104,7 @@ else
// this is for munin's configuration tool
// could do something more complicated here
if(count($argv) == 2 && $arv[1] == 'authconf') {
if(count($argv) == 2 && $argv[1] == 'autoconf') {
exit('yes');
}

View File

@ -0,0 +1,325 @@
#! /usr/bin/perl
use strict;
use warnings;
use IO::File;
use Data::Dumper;
use POSIX qw(strftime);
$ENV{LANG} = "C";
my $spool_fetch_epoch = (shift || 0);
# Don't reply for too old $spool_fetch_epoch)
# Max 7 days
$spool_fetch_epoch = time - 3600 * 24 * 7 if $spool_fetch_epoch < time - 3600 * 24 * 7;
my $max_epoch = ($ENV{MAX_EPOCH} || 0);
my %fieldset;
my @files = sort glob($ENV{FILES} || "*.tsv*");
FILE: for my $file (@files) {
my $values = {};
my $nb_epochs = 0; my $first_epoch;
# Read file
{
# Skipping if the file is too old
# (more that one day older than asked)
next if file_mtime($file) < $spool_fetch_epoch - (3600 *24);
print STDERR "opening $file\n" if $ENV{DEBUG};
my $fh = new IO::File( ($file =~ m/\.gz$/) ? "gunzip < $file |" : $file);
next unless $fh;
$_ = <$fh>; chomp;
my @headers = split(/\t/);
# Ignore 3 first fields (Object Name, Epoch & Owner Array Name)
shift @headers; shift @headers; shift @headers;
my $nb_headers = $#headers;
LINE: while(<$fh>) {
chomp;
my @row = split(/\t/, $_);
my $object_name = shift @row;
my $epoch = shift @row;
my $owner_array_name = shift @row;
# Ignore if too old
next if ($epoch <= $spool_fetch_epoch);
# Don't do too much work : 4h each time is enough
$first_epoch ||= $epoch;
next if $epoch > $first_epoch + 60 * 60 * 4;
# Store Values
for (my $idx = 0; $idx < $nb_headers; $idx ++) {
my $value = $row[$idx];
my $field_name = $headers[$idx];
# Ignore empty values
next unless (defined $value && $value ne "");
# Ignore non numeric values
next unless $value =~ m/^[0-9.]+$/;
# Ignore Optimal/NonOptimal valuse
next unless ($fieldset{$field_name} || $field_name !~ /[oO]ptimal/);
$fieldset{$field_name} = 1 unless $fieldset{$field_name};
if ($ENV{DEBUG}) {
no warnings;
print "object_name:$object_name, field_name:$field_name, epoch:$epoch, value:$value\n";
}
$values->{$object_name}->{$field_name} .= "$epoch:$value ";
$nb_epochs ++;
}
}
}
# Don't emit anything if the file didn't contain any useful value
next unless $nb_epochs;
# Restitution MultiGraph
print <<EOF
multigraph san
graph_title Vue globale
graph_order \
cpu_sp_a=san.cpu.sp_a \
cpu_sp_b=san.cpu.sp_b
EOF
;
# CPU
my @object_names = keys %$values;
gen_multigraph(
$values,
"cpu",
[ grep { /^SP / } @object_names ],
);
# DISK
gen_multigraph(
$values,
"disk",
[ grep { /^Bus \d+/ } @object_names ],
);
# Port
gen_multigraph(
$values,
"port",
[ grep { /^Port / } @object_names ],
#sub { return $1 if shift =~ m/^(Port \w+)/ },
);
# Pool
gen_multigraph(
$values,
"pool",
[ grep { /^Pool / } @object_names ],
);
# LUN Global
print <<EOF
multigraph san.lun
graph_title Luns Global
graph_order \
cpu_sp_a=san.cpu.sp_a \
cpu_sp_b=san.cpu.sp_b
EOF
;
# LUN Per Host
my %host_seen;
my @hosts = grep { $_ ne "" } grep { ! $host_seen{$_}++ }
map { $1 if /^\w+ \[\d+; (\w+)/ } @object_names;
for my $host (@hosts) {
my $host_field = $host;
$host_field =~ tr/./_/;
gen_multigraph(
$values,
"lun.$host_field",
[ grep { /^\w+ \[\d+; $host/ } @object_names ],
sub { return $1 if shift =~ m/^(\w+) / },
sub { return $1 if shift =~ m/^(\w+) / },
);
}
# Never send more than 1 file
last;
}
sub gen_multigraph
{
my ($values, $category, $object_names, $convert_to_label, $convert_to_field) = @_;
# convert_to_label() reverts to identity if not defined
$convert_to_label ||= sub { return $_[0]; };
# convert_to_field() reverts to convert_to_label() if not defined
$convert_to_field ||= $convert_to_label;
# print Dumper($object_names);
# Global Graph
print <<EOF
multigraph san.$category
graph_title $category Global
graph_order \
cpu_sp_a=san.cpu.sp_a \
cpu_sp_b=san.cpu.sp_b
EOF
;
my @fields = keys %{ $values->{$object_names->[0]} };
for my $field (@fields) {
my $graph_name = hash_field_name($field);
print "multigraph san.$category.$graph_name\n";
print "graph_title $field\n";
for my $object_name (@$object_names) {
my $label = &$convert_to_label($object_name);
my $field_name = hash_field_name(&$convert_to_field($object_name));
print "$field_name.label $label\n";
print "$field_name.info $object_name\n";
for my $value (split(/ /, $values->{$object_name}->{$field})) {
print $field_name , ".value " , $value , "\n";
}
}
}
}
sub hash_field_name
{
my $name = shift;
$name = lc($name);
$name =~ s/[^a-z0-9]+/_/g;
$name =~ s/^_//;
$name =~ s/_$//;
return $name;
}
sub trim
{
my $line = shift;
$line =~ s/^ +//;
$line =~ s/ +$//;
return $line;
}
sub file_mtime
{
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat(shift);
return $mtime;
}
__DATA__
sb
multigraph san.cpu
graph_title Usage CPU
cpu_sp_a.value $epoch:$cpu_sp_a
cpu_sp_b.value $epoch:$cpu_sp_b
multigraph san.resptime
graph_title Response Time
resp_time_a.value $epoch:$resp_time_a
resp_time_b.value $epoch:$resp_time_b
multigraph san.iops
graph_title IOPS
read_io_a.value $epoch:$read_io_a
write_io_a.value $epoch:$write_io_a
read_io_b.value $epoch:$read_io_b
write_io_b.value $epoch:$write_io_b
multigraph san.io
graph_title IO
read_mb_a.value $epoch:$read_mb_a
write_mb_a.value $epoch:$write_mb_a
read_mb_b.value $epoch:$read_mb_b
write_mb_b.value $epoch:$write_mb_b
multigraph san.cache
graph_title Cache
cache_mb_flush_a.value $epoch:$cache_mb_flush_a
write_cache_mb_flush_a.value $epoch:$write_cache_mb_flush_a
cache_mb_flush_b.value $epoch:$cache_mb_flush_b
write_cache_mb_flush_b.value $epoch:$write_cache_mb_flush_b
EOF
;
}
}
print ".\n";
my %MONTHS = get_months();
sub convert_to_epoch
{
# converts "05/12/2011 03:57" to EPOCH
my ($date, $time) = split(/ /);
my ($mday, $mon, $year) = split(/\//, $date);
my ($hour, $min, $sec) = split(/:/, $time);
$sec ||= 0;
use Time::Local;
$mon = $MONTHS{lc($mon)} unless $mon =~ m/\d+/;
my $epoch = timelocal($sec,$min,$hour,$mday,$mon-1,$year);
return $epoch;
}
sub get_months {
return (
"jan" => 0,
"fev" => 1,
"mar" => 2,
"apr" => 3,
"may" => 4,
"jun" => 5,
"jul" => 6,
"aug" => 7,
"sep" => 8,
"oct" => 9,
"nov" => 10,
"dec" => 11,
);
}
sub trim {
shift;
s/^\s+//;
s/\s+$//;
return $_;
}
__DATA__
05/12/2011 03:57
print <<EOF
multigraph san
graph_title Vue globale
graph_order \
cpu_sp_a=san.cpu.cpu_sp_a \
cpu_sp_b=san.cpu.cpu_sp_b
multigraph san.cpu
graph_title Utilization (%)
cpu_sp_a.label Utilization (%) for SP A
cpu_sp_b.label Utilization (%) for SP B
cpu_sp_a.value $values->{"SP A"}->{"Utilization (%)"}
cpu_sp_b.value $values->{"SP B"}->{"Utilization (%)"}
multigraph san.bw
graph_title Total Bandwidth (MB/s)
iops_a.label Total Throughput (IO/s) for SP A
iops_b.label Total Throughput (IO/s) for SP B
iops_a.value $values->{"SP A"}->{"Total Throughput (IO/s)"}
iops_b.value $values->{"SP B"}->{"Total Throughput (IO/s)"}
multigraph san.iops
graph_title Total Throughput (IO/s)
iops_a.label Total Throughput (IO/s) for SP A
iops_b.label Total Throughput (IO/s) for SP B
iops_a.value $values->{"SP A"}->{"Total Throughput (IO/s)"}
iops_b.value $values->{"SP B"}->{"Total Throughput (IO/s)"}
EOF
;

View File

@ -10,8 +10,8 @@ stuff we do at http://hostedmunin.com/ . Use it as you feel fit :)
Current features controlled via config file:
* Respond slowly or never to queries.
* Have plugins that always are in warning or alarm.
* Extensive number of plugins.
* Have plugins that always are in warning or critical.
* Extensive number of plugins running at once.
* Run on multiple ports at the same time, to test huge amounts of clients.
@ -21,8 +21,8 @@ Usage
munin-node-from-hell takes two arguments; the mode and which config file to
use. Mode is either --run or --muninconf.
This software is meant to run as an ordinary unix user, please don't run
it as root without some thought.
This software is meant to run as an ordinary Unix user, please don't run
it as root.
You probably want:

View File

@ -0,0 +1,15 @@
#
# Initialise plugins that test the basic functions of Munin.
#
#
[instance:basic]
pluginprofile = basic
port = 4000
[pluginprofile:basic]
plugins = always_warning, always_critical, graph_area
[base]
# when building an example config with --muninconf, what hostname to output.
hostname = localhost

View File

@ -1,4 +1,5 @@
#!/usr/bin/python
# .- coding: utf-8 -.
#
# Artificial munin node that behaves in all the ways you would like
# ordinary nodes _not_ to behave.
@ -84,25 +85,90 @@ class tarpit(MuninPlugin):
modules["tarpit"] = tarpit()
class always_warning(MuninPlugin):
conftext = """graph_title Always in LEVEL
graph_vlabel Level
graph_scale no
graph_info A simple graph that is always in LEVEL
graph_category always_LEVEL
generic.label Level
generic.info Level usually above warning level
generic.warning 5
generic.critical 10"""
def fetch(self, conf):
return "generic.value 10"
def config(self, conf):
return """graph_title Always in warning
graph_vlabel Level
graph_scale no
graph_info A simple graph that is always in warning or alarm
graph_category active_notification
generic.label Level
generic.info Level usually above warning level
generic.warn 5
generic.crit 10"""
return self.conftext.replace("LEVEL","warning")
modules["always_warning"] = always_warning()
class always_alarm(always_warning):
class always_critical(always_warning):
def fetch(self, conf):
return "generic.value 20"
modules["always_alarm"] = always_alarm()
def config(self, conf):
return self.conftext.replace("LEVEL","critical")
modules["always_critical"] = always_critical()
class graph_area(MuninPlugin):
"A plugin that uses STACK and AREA. From proc_pri. Use: testing the grapher"
def fetch(self, conf):
return """high.value 3
low.value 2
locked.value 1"""
def config(self, conf):
return """graph_title AREA and STACK
graph_order low high locked
graph_category graphtest
graph_info This graph shows nuber of processes at each priority
graph_args --base 1000 -l 0
graph_vlabel Number of processes
high.label high priority
high.draw STACK
high.info The number of high-priority processes (tasks)
low.label low priority
low.draw AREA
low.info The number of low-priority processes (tasks)
locked.label locked in memory
locked.draw STACK
locked.info The number of processes that have pages locked into memory (for real-time and custom IO)
"""
modules["graph_area"] = graph_area()
class utf8_graphcat(MuninPlugin):
"A plugin with a graph category which has UTF-8 in it"
def fetch(self, conf):
load = open("/proc/loadavg", "r").read()
load, rest = load.split(" ", 1)
load = float(load)
return "apples.value %.2f" % load
def config(self, conf):
return """graph_title Example UTF-8 graph
graph_vlabel apples
graph_category foo™
apples.label apples
graph_info Apples eaten
apples.info Apples eaten"""
modules["utf8_graphcat"] = utf8_graphcat()
class utf8_graphname(MuninPlugin):
"A plugin with a UTF-8 name"
def fetch(self, conf):
load = open("/proc/loadavg", "r").read()
load, rest = load.split(" ", 1)
load = float(load)
return "apples.value %.2f" % load
def config(self, conf):
return """graph_title Example UTF-8 graph
graph_vlabel apples
graph_category system
apples.label apples
graph_info Apples eaten
apples.info Apples eaten"""
modules["utf8_™graphname"] = utf8_graphname()
class ArgumentTCPserver(SocketServer.ThreadingTCPServer):
@ -122,7 +188,7 @@ class MuninHandler(SocketServer.StreamRequestHandler):
"""
def handle(self):
print "%s: Connection from %s:%s. server args is %s" \
if self.server.args.get("verbose"): print "%s: Connection from %s:%s. server args is %s" \
% (self.server.args["name"], self.client_address[0], self.client_address[1], self.server.args)
# slow path
hostname = self.server.args["name"]
@ -198,15 +264,19 @@ def start_servers(instances):
def usage():
print "Usage: %s [--run] [--muninconf] <configfile>" % sys.argv[0]
print "Usage: %s [--run] [--verbose] [--muninconf] <configfile>" % sys.argv[0]
def main():
if len(sys.argv) <= 2:
usage()
sys.exit(1)
verbose = False
if "--verbose" in sys.argv:
verbose = True
config = ConfigParser.RawConfigParser()
config.read(sys.argv[2])
config.read(sys.argv[-1])
instancekeys = [ key for key in config.sections() if key.startswith("instance:") ]
servers = {}
@ -260,6 +330,8 @@ def main():
instanceconfig[k] = v
instanceconfig["plugins"] = plugins
if "--verbose" in sys.argv:
instanceconfig["verbose"] = True
instanceconfig["name"] = "%s-%s" % (instancename, portinstance)
instanceconfig["expanded_port"] = portinstance
@ -275,6 +347,7 @@ def main():
if "--run" in sys.argv:
if verbose: print "Starting up.."
servers = start_servers(instances)
try:

View File

@ -12,7 +12,7 @@ port = 3000
#port = 4940
#sleepyness = 30
[pluginprofile:notif]
plugins = always_warning, always_alarm
plugins = always_warning, always_critical
[base]
# when building an example config with --muninconf, what hostname to output.

View File

@ -6,7 +6,7 @@ pluginprofile = tarpit
port = 3000
[pluginprofile:tarpit]
plugins = tarpit, load, locks
plugins = load, locks, tarpit, load, locks
[pluginprofile:base]
plugins = load, locks, locks, load, load, locks, locks, load, load, load