1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-22 02:51:03 +00:00

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

This commit is contained in:
Mike Koss 2012-02-20 01:23:31 -08:00
commit 1edc7e7dc3
10 changed files with 541 additions and 48 deletions

View file

@ -5,7 +5,9 @@
**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
That web site is for the time being disabled, new updates are done here.
If a dedicated website comes back alive, its plugin backend will be this git repo.
## contrib/templates/ - 3rd-party templates
@ -25,3 +27,9 @@ Here, you can put just any kind of tool. Please use this directory instead of a
It makes things way more easy to search for others.
And, it serves as an incubator of SVN `trunk/contrib` :-)
## Notes to contributors
We like to have ''elementary'' commits (a good rationale is : one per Changelog entry), as it is much easier to manage for reviewing. Debugging is also usually easier that way.
So please **don't** be afraid to make as many commits as needed.

View file

@ -0,0 +1,98 @@
#!/usr/bin/env python
"""
gunicorn_status - A munin plugin for Linux to monitor the memory
usage of gunicorn processes
Copyright (C) 2012 Azavea, Inc.
Author: Andrew Jennings
Like Munin, this plugin is licensed under the GNU GPL v2 license
http://www.opensource.org/licenses/GPL-2.0
If you've put your gunicorn pid somewhere other than the
default /var/run/gunicorn.pid, you can add a section like
this to your munin-node's plugin configuration:
[gunicorn_*]
env.gunicorn_pid_path [path to your gunicorn pid]
This plugin supports the following munin configuration parameters:
#%# family=auto contrib
#%# capabilities=autoconf
"""
import sys, os
from subprocess import check_output
# set path to your gunicorn pid
try:
GUNICORN_PID_PATH = os.environ['gunicorn_pid_path']
except:
GUNICORN_PID_PATH = "/var/run/gunicorn.pid"
class GunicornMemoryStatus():
master_pid = ''
"""
The Gunicorn master process pid, as a string
"""
def __init__(self):
try:
self._get_master_pid()
except:
raise Exception("Couldn't read gunicorn pid information")
def print_total_memory(self):
print ('total_memory.value %d' % self._get_total_memory())
def _get_master_pid(self):
master_pid_file = open(GUNICORN_PID_PATH)
self.master_pid = master_pid_file.read().rstrip()
master_pid_file.close()
return True
def _get_total_memory(self):
master = self._get_master_memory()
total = master +self. _get_worker_memory()
total_in_mb = total / 1024
return total_in_mb
def _get_master_memory(self):
master = int(check_output(
['ps', '--pid', self.master_pid, '-o', 'rss', '--no-headers']))
return master
def _get_worker_memory(self):
worker_processes = check_output(
['ps', '--ppid', self.master_pid, '-o', 'rss', '--no-headers'])
process_memory_usage = [int(rss) for rss in worker_processes.splitlines()]
worker_memory_usage = sum(process_memory_usage)
return worker_memory_usage
def print_config():
print "graph_title Gunicorn - Memory Usage"
print "graph_args --base 1024 -l 0"
print "graph_vlabel Megabytes"
print "graph_category gunicorn"
print "total_memory.label Total Memory"
if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1] == 'config':
print_config()
elif len(sys.argv) == 2 and sys.argv[1] == 'autoconf':
try:
open(GUNICORN_PID_PATH).close()
print "yes"
except:
print "no"
# Some docs say it'll be called with fetch, some say no arg at all
elif len(sys.argv) == 1 or (len(sys.argv) == 2 and sys.argv[1] == 'fetch'):
try:
status = GunicornMemoryStatus()
status.print_total_memory()
except:
sys.exit("Couldn't retrieve gunicorn memory usage information")

113
plugins/gunicorn/gunicorn_status Executable file
View file

@ -0,0 +1,113 @@
#!/usr/bin/env python
"""
gunicorn_status - A munin plugin for Linux to monitor gunicorn processes
Copyright (C) 2012 Azavea, Inc.
Author: Andrew Jennings
Like Munin, this plugin is licensed under the GNU GPL v2 license
http://www.opensource.org/licenses/GPL-2.0
If you've put your gunicorn pid somewhere other than the
default /var/run/gunicorn.pid, you can add a section like
this to your munin-node's plugin configuration:
[gunicorn_*]
env.gunicorn_pid_path [path to your gunicorn pid]
This plugin supports the following munin configuration parameters:
#%# family=auto contrib
#%# capabilities=autoconf
"""
import sys, os
from subprocess import check_output
from time import sleep
# set path to your gunicorn pid
try:
GUNICORN_PID_PATH = os.environ['gunicorn_pid_path']
except:
GUNICORN_PID_PATH = "/var/run/gunicorn.pid"
class GunicornStatus():
master_pid = ''
"""
The gunicorn master process pid, as a string
"""
worker_pids = ''
"""
The list of gunicorn processes as strings
"""
def __init__(self):
try:
self._get_master_pid()
self._get_worker_pids(self.master_pid)
except:
sys.exit("Couldn't read gunicorn pid")
def print_total_workers(self):
print ('total_workers.value %d' % self._worker_count())
def print_idle_workers(self):
print ('idle_workers.value %d' % self._idle_worker_count())
def _get_master_pid(self):
master_pid_file = open(GUNICORN_PID_PATH)
self.master_pid = master_pid_file.read().rstrip()
master_pid_file.close()
def _get_worker_pids(self, master_pid):
children = check_output(
['ps', '--ppid', master_pid, '-o', 'pid', '--no-headers'])
self.worker_pids = [pid.strip() for pid in children.splitlines()]
def _worker_count(self):
return len(self.worker_pids)
def _idle_worker_count(self):
idle_workers = 0
for pid in self.worker_pids:
before = self._cpu_time(pid)
sleep(0.50)
after = self._cpu_time(pid)
if before == after:
idle_workers += 1
return idle_workers
def _cpu_time(self, pid):
proc_info = open('/proc/%s/stat' % pid).read()
proc_info = [field.rstrip() for field in proc_info.split()]
user_time = int(proc_info[13].rstrip())
kernel_time = int(proc_info[14].rstrip())
return user_time + kernel_time
def print_config():
print "graph_title Gunicorn - Status"
print "graph_args -l 0"
print "graph_vlabel Number of workers"
print "graph_category gunicorn"
print "total_workers.label Total Workers"
print "idle_workers.label Idle Workers"
if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1] == 'config':
print_config()
elif len(sys.argv) == 2 and sys.argv[1] == 'autoconf':
try:
open(GUNICORN_PID_PATH).close()
print "yes"
except:
print "no"
# Some docs say it'll be called with fetch, some say no arg at all
elif len(sys.argv) == 1 or (len(sys.argv) == 2 and sys.argv[1] == 'fetch'):
status = GunicornStatus()
try:
status.print_total_workers()
status.print_idle_workers()
except:
sys.exit("Couldn't retrieve gunicorn status")

View file

@ -13,7 +13,7 @@ Requires perl and either WWW::Mechanize or Net::Telnet.
=head1 CONFIGURATION
The plugin needs HTML access to the router. If you can get to http://YOUR_ROUTER/,
and are greeting with a page titled "THOMSON TG585 v7", then you can probably use this plugin.
and are greeting with a page titled "THOMSON TG585 v7", then you can probably use this plugin.
This is a wildcard plugin, so you will need to create symlinks to this plugin (or create copies if your filesystem doesn't support linking). Links should be of the form:
@ -1112,25 +1112,45 @@ else {
sub TelnetError {
my $errmsg = shift;
my @parts;
if ( $mode eq 'bandwidth' ) {
@parts = qw(down up);
}
elsif ( $mode eq 'power' ) {
@parts = qw(downout upout downline upline downsn upsn);
}
elsif ( $mode eq 'uptime' ) {
@parts = qw(Box DSL iNet);
}
elsif ( $mode eq 'errors' ) {
@parts = qw(downFEC upFEC downCRC upCRC downHEC upHEC);
}
foreach (@parts) {
my %parts = (
'atm' => [qw(RXCells RxErrors RxOctets TxCells TxErrors TxOctets)],
'bandwidth' => [qw(down downrate up uprate)],
'conntrack' =>
[qw(Active closing expected halfopen ICMP idle loose mcast non TCP TCPclosing TCPestablished TCPopen UDP)],
'dhcpclient' =>
[qw(ACKs Corrupted DECLINEs DISCOVERs failures INFORMs NAKs OFFERs Other RELEASEs REPLIES REQUESTs)],
'dhcprelay' =>
[qw(badc bogusg bogusr clientp corrupta missinga missingc packets serverp)],
'dhcpserver' =>
[qw(ACKs BOOTP Corrupted DECLINE DISCOVER dropped failures INFORM NAKs OFFERs Other RELEASE REQUEST)],
'dns' =>
[qw(corrupted discard external forwarded negative resolved spoofed spurious unknown)],
'errors' => [qw(downCRC downFEC downHEC upCRC upFEC upHEC)],
'firewall' =>
[qw(DroppedForward DroppedInput DroppedOutput ParsedForward ParsedInput ParsedOutput)],
'ids' => [qw(Active Collisions New Recycled Searches)],
'igmphost' =>
[qw(badchecksum badqueries badttl failing invalidmembership norouter receivedforour reportsreceived reportstransmitted toolong toosmall v1membershipq v2membershipq v3membershipq v3membershipr)],
'igmpproxy' =>
[qw(badchecksum badleavereports badqueries badreports badttl election igmpleavereports mrdadvertise mrdbad mrdsolicits mrdterminate noroute queriesfail toolong tooshort v1queriesr v1queriess v1reportsr v2queriesr v2queriess v2reportsr v3queriesr v3queriess v3reportsr)],
'power' => [qw(downline downout downsn upline upout upsn)],
'protoicmp' =>
[qw(echor echorepr echoreps echos errorsr errorss maskr maskrepr maskreps masks paramr params quenchr quenchs redirectr redirects timeexceedr timeexceeds timestampr timestamprepr timestampreps timestamps unreachabler unreachables)],
'protoip' =>
[qw(droppedfrags forwarded fragerrs fragged fragments fwderrors herrors hostdrop hostfwd hostrec noroute reassembled reserrors totfrags)],
'prototcp' =>
[qw(accepts attempts drops errors established received retransmitted transmitted)],
'protoudp' => [qw(dropped errors received transmitted)],
'uptime' => [qw(Box DSL iNet)]
);
foreach ( @{$parts{$mode}} ) {
print "$_.value U\n";
print "$_.extinfo $errmsg\n";
}
print "# Sending \"exit\"\n" if $MUNIN_DEBUG;
if ( defined $telnet ) {
$telnet->errmode('return');
$telnet->print('exit');
$telnet->close;
}
@ -1141,7 +1161,8 @@ else {
$telnet = new Net::Telnet(
Host => $host,
Prompt => '/{.*}.*=>$/',
ErrMode => \&TelnetError
ErrMode => \&TelnetError,
Timeout => 10
);
print "# Logging in...\n" if $MUNIN_DEBUG;

50
plugins/php/php_apc.php Normal file
View file

@ -0,0 +1,50 @@
<?php
$ret = array();
if(function_exists("apc_cache_info") && function_exists("apc_sma_info"))
{
switch ($_GET["act"])
{
case "memory":
$tmp = apc_sma_info();
$ret["mem_used"] = $tmp["seg_size"]-$tmp["avail_mem"];
$ret["mem_avail"] = $tmp["avail_mem"];
break;
case "hits":
$tmp = apc_cache_info();
$ret["num_hits"] = $tmp["num_hits"];
$ret["num_misses"] = $tmp["num_misses"];
break;
case "percents":
$tmp = apc_sma_info();
$ret["memory"] = 100-(($tmp["avail_mem"] / $tmp["seg_size"])*100);
$tmp = apc_cache_info();
$ret["hits"] = ($tmp["num_hits"] / ( $tmp["num_hits"]+$tmp["num_misses"]) ) * 100;
$ret["misses"] = ($tmp["num_misses"] / ( $tmp["num_hits"]+$tmp["num_misses"]) ) * 100;
break;
}
} else {
switch ($_GET["act"])
{
case "memory":
$ret["mem_size"] = 0;
$ret["mem_used"] = 0;
break;
case "hits":
$ret["num_hits"] = 0;
$ret["num_misses"] = 0;
break;
case "percents":
$ret["memory"] = 0;
$ret["hits"] = 0;
$ret["misses"] = 0;
break;
}
}
foreach($ret as $key => $val) echo "$key.value $val\n";
?>

Binary file not shown.

View file

@ -96,8 +96,8 @@ $graphsRef->{listeners} = {
info => 'This graph shows us the various counts for listener states we are tracking',
},
datasrc => [
{ name => 'maxlisteners', draw => 'STACK', min => '0', label => 'Max Listeners', type => 'GAUGE' },
{ name => 'currlisteners', draw => 'AREA', min => '0', label => 'Current Listeners', type => 'GAUGE' },
{ name => 'maxlisteners', draw => 'AREA', min => '0', label => 'Max Listeners', type => 'GAUGE' },
{ name => 'currlisteners', draw => 'STACK', min => '0', label => 'Current Listeners', type => 'GAUGE' },
],
};
@ -121,8 +121,8 @@ $graphsRef->{sid_listeners} = {
info => 'This graph shows us the various counts for listener states we are tracking',
},
datasrc => [
{ name => 'maxlisteners', draw => 'STACK', min => '0', label => 'Max Listeners', type => 'GAUGE', xmlkey => 'MAXLISTENERS' },
{ name => 'currlisteners', draw => 'AREA', min => '0', label => 'Current Listeners', type => 'GAUGE', xmlkey => 'CURRENTLISTENERS' },
{ name => 'maxlisteners', draw => 'AREA', min => '0', label => 'Max Listeners', type => 'GAUGE', xmlkey => 'MAXLISTENERS' },
{ name => 'currlisteners', draw => 'STACK', min => '0', label => 'Current Listeners', type => 'GAUGE', xmlkey => 'CURRENTLISTENERS' },
{ name => 'peaklisteners', draw => 'LINE2', min => '0', label => 'Peak Listeners', type => 'GAUGE', xmlkey => 'PEAKLISTENERS' },
{ name => 'uniqlisteners', draw => 'LINE2', min => '0', label => 'Unique Listeners', type => 'GAUGE', xmlkey => 'UNIQUELISTENERS' },
],
@ -133,7 +133,7 @@ if (defined($ARGV[0]) && ($ARGV[0] eq 'config')) {
exit;
}
if (defined($ARGV[0]) && ($ARGV[0] eq 'autoconf')) {
if (defined($ARGV[0]) && (($ARGV[0] eq 'autoconf') || ($ARGV[0] eq 'suggest'))) {
check_autoconf();
exit;
}
@ -234,7 +234,7 @@ sub print_listener_data {
}
}
}
print "multigraph shoutcast2_active\n";
print "multigraph shoutcast2_listeners\n";
foreach my $dsrc (@{$graphsRef->{listeners}->{datasrc}}) {
if ($dsrc->{name} eq 'maxlisteners') {
print "$dsrc->{name}.value $maxListeners\n";

View file

@ -17,26 +17,19 @@ style="AREA"
cpus=$(grep -c ^processor /proc/cpuinfo)
run_watchdog() { # should also trap kill and term signals
while :; do
sleep ${watchdog:-600}
touch -d now-${timeout:-1200}sec $cache
[ $pidfile -nt $cache ] || break
done
[ -f $pidfile ] || exit # may have been removed by terminating daemon
kill $(cat $pidfile)
rm -f $pidfile $cache
kill -0 $(cat $pidfile) 2> /dev/null || rm -f $pidfile
}
run_acquire() {
echo "$$" > $pidfile
$pluginfull watchdog &
mpstat -P ALL $interval |
awk -v cpus=$cpus '$2>=0&&$2<10 {print $2, systime(), (100-$11)/cpus}' >> $cache
rm -f $pidfile $cache
}
run_daemon() {
run_watchdog
if [ -f $pidfile ]; then
touch $pidfile
else
@ -92,4 +85,3 @@ exit 0
# acquire which needs a different pid than watchdog, otherwise watchdog
# could/will kill itself when expiring before the watched process is killed.
# not a POSIX feature.

View file

@ -1,23 +1,26 @@
#!/usr/local/bin/perl -w
#!/usr/bin/env perl
# -*- perl -*-
# Plugin to monitor number of irqs
# Plugin to monitor the system uptime
#
#%# family=auto
#%# capabilities=autoconf
use strict;
use warnings;
my %IN;
my $sysctl = defined($ENV{sysctl}) ? $ENV{sysctl} : '/sbin/sysctl';
my $ostype = `uname -s`;
chomp ($ostype);
if (defined($ARGV[0]) and ($ARGV[0] eq 'autoconf')) {
if ( -x $sysctl ) {
print "yes\n";
}else{
print "no (sysctl binary not found)\n";
};
exit;
if ( -x $sysctl ) {
print "yes\n";
} else {
print "no (sysctl binary not found)\n";
};
exit;
};
if (defined($ARGV[0]) and ($ARGV[0] eq 'config')) {
@ -26,12 +29,12 @@ graph_title Uptime
graph_args --base 1000 -l 0
graph_vlabel days
graph_category system
compile.label kernel age
compile.label Kernel age
compile.type GAUGE
compile.min 0
compile.max 1000
compile.draw AREA
uptime.label uptime
uptime.label Uptime
uptime.type GAUGE
uptime.min 0
uptime.max 1000
@ -44,13 +47,15 @@ use Date::Parse;
my $kern=`sysctl -n kern.version`;
$kern=~ /:\s+(.*\S)\s+\w+\@/;
print "Compile: $1\n";
#print "Compile: $1\n";
$kern=str2time($1);
my $boot=`sysctl -n kern.boottime`;
$boot=~ / sec = (\d+)/;
print "Boot: $1\n";
$boot=$1;
my $boot=`sysctl -n kern.boottime`; # OpenBSD will return seconds from the epoch
if ($ostype ne "OpenBSD") {
$boot=~ / sec = (\d+)/;
#print "Boot: $1\n";
$boot=$1;
}
my $now=time;

206
tools/munin-cli/munin Executable file
View file

@ -0,0 +1,206 @@
#!/bin/bash
# Munin CLI
# Found on http://munin.scarydevilmonastery.net/
# ----- munin plugin management script -----
# munin [ restart | permissions | active | available | bak | help]
# munin [ <enable | disable | edit | purge> <plugin>]
# munin [ run <plugin [command]>]
# munin restart reloads munin config, through init.d script
# munin permissions edit /etc/munin/plugin-conf.d/munin-node
# munin active list enabled plugins
# munin available list all plugins from repositiories except the active ones
# munin run plugin execute plugin through munin-run
# munin run plugin config execute config section of plugin through munin-run
# munin run plugin autoconf execute config section of plugin through munin-run
# munin enable plugin symlink to plugin and reload munin config
# munin disable plugin remove symlink to plugin and reload munin config
# munin purge plugin remove symlin to plugin, its .rrd files and the associated .html files
# munin edit plugin open plugin in editor
# munin export plugin copy plugin to other server(s)
# munin bak remove *~ files from plugin repository directories
# munin template plugin start editing a new plugin
# munin pack create archive, containing plugins
# munin help print overview of commands
# munin print overview of commands
# multiple plugin repositories are supported.
# running without arguments shows a command overview
# depends on external programs:
# stat, sed, find, sort, uniq.
versions="yes"
plugins=(/usr/local/share/munin/plugins /usr/share/munin/plugins) # where are plugins kept? First path is local, where new plugins from template are added
munin="/etc/munin/plugins" # munin enabled plugins (symlinks to plugins) are here
trash="$HOME/.Trash" # where to move files of purged plugins to?
host="localhost"
domain="localdomain"
servers="" # list of machines to export plugins to
muninlib="/var/lib/munin/$domain" # rrd files store
muninweb="/var/www/munin/$domain" # html files store
muninhost=$host.$domain
permissions="/etc/munin/plugin-conf.d/munin-node"
archive="/var/www/plugins/munin-plugins.tgz" # munin pack updates this archive, for downloading through web server
autopack="no" # update $archive after edit
plugin="$2"
wildcard="$3"
# editor choice: if not specified in environment variable EDIT, use environment variables EDITOR, then VISUAL
# if still no success, try executable "editor", and if still no editor found, hardcode to /usr/bin/vi. I know that
# this looks funny, but these are legal bashisms.
: ${EDIT:=${EDITOR:-${VISUAL:-"$(which editor)"}}}
: ${EDIT:="/usr/bin/vi"}
# -------------------------------------------------------------------------
required="chase sort grep sed uniq find stat munin-run scp"
# chase instead of readlink -f because it can handle wildcards
for require in $required; do
type -t $require > /dev/null ||
echo "warning: required program $require not found"
done
checkin() {
[[ $versions == yes ]] && mkdir -p $(dirname $1)/RCS && ci -l -mautocheckin $1
}
munin_active() { stat -c%N $munin/* ;} # show enabled plugins
munin_run() { munin-run $plugin $wildcard ;} # run a plugin with munin-run
munin_restart() { # restart munin-node
echo -n restarting munin node...
/etc/init.d/munin-node restart &> /dev/null
echo done
}
munin_available() { # show available, inactive plugins
(find ${plugins[*]} -maxdepth 1 -type f ;
chase $munin/*) |
sort | uniq -u
}
munin_disable() { # removes plugin or link from $munin
if [[ -z "$plugin" ]] ; then munin_active ; exit 1 ; fi
if [[ ! -z "$wildcard" ]] ; then plugin+="_$wildcard" ; fi
if [[ ! -h $munin/$plugin ]] ; then
if [[ ! -f $munin/$plugin ]] ; then echo "plugin not enabled" ; exit 1 ; fi
fi
echo removing $munin/$plugin ; rm $munin/$plugin && munin_restart
}
findplugin() {
for pluginpath in ${plugins[*]} ; do
if [[ -f "$pluginpath/$1" ]] ; then
echo "$pluginpath"
break
fi
done
}
munin_enable() { # creates a link to plugin in $munin
if [[ -z "$plugin" ]] ; then munin_available ; exit 1 ; fi
if [[ -f $munin/$plugin ]] ; then echo plugin already enabled ; exit 0 ; fi
usepath=$(findplugin "$plugin")
if [[ -z "$usepath" ]] ; then echo plugin not found ; exit 1 ; fi
source="$plugin"
chmod +x "${usepath}/${source}"
if [[ ! -z "$wildcard" ]] ; then plugin+="$wildcard" ; fi
ln -s "${usepath}/${source}" "${munin}/${plugin}"
echo "enabled $(stat -c%N ${munin}/${plugin})"
echo "-------------------------------------------------------------------"
echo "plugin output:"
munin-run "${plugin}"
echo "-------------------------------------------------------------------"
munin_restart
}
munin_purge() { # move link, web files and rrd file to $trash
if mkdir -p "$trash" ; then
munin_disable $plugin
cleanplugin="${plugin//.-/_}"
ls $muninlib/$muninhost-$cleanplugin-*.rrd
mv $muninlib/$muninhost-$cleanplugin-*.rrd "$trash"
else
echo "can't access $trash dir"
exit 1
fi
}
munin_pack() { # pack all plugins into a tgz archive
tar cpzf "$archive" ${plugins[@]//plugins/plugins/* }
}
munin_edit() { # edit plugin source of an active plugin
plugintarget=$(chase "$munin/$plugin")
if [[ -z "$plugintarget" ]] ; then
pluginpath=$(findplugin "$plugin")
if [[ -z "$pluginpath" ]] ; then
echo "plugin not found"
exit 1
fi
plugintarget="$pluginpath/$plugin"
fi
$EDIT "$plugintarget"
checkin "$plugintarget"
[[ "$autopack" == "yes" ]] && munin_pack
}
munin_permissions() { # edit plugin permissions file
CHANGED=$(stat -c%Y $permissions)
$EDIT $permissions
(( CHANGED == $(stat -c%Y $permissions) )) || munin_restart
}
munin_bak() { # remove files ending in ~ as left by joe as backup files
for pluginpath in ${plugins[*]} ; do
ls $pluginpath/*~ 2> /dev/null && rm $pluginpath/*~
done
}
munin_template() { # start editing a new plugin, using template
echo $plugin
if [[ -f ${plugins}/$plugin ]]; then
echo "$plugin already exists"
else
cp ${plugins}/template ${plugins}/$plugin
munin edit $plugin
fi
}
munin_migrate() { # move system plugin to local plugins, relink if necessary
if [[ -f ${plugins[1]}/$plugin ]]; then
plugintarget=$(chase "$munin/$plugin")
[[ $plugintarget ]] && munin disable $plugin
mv ${plugins[1]}/$plugin ${plugins[0]}
[[ $plugintarget ]] && munin enable $plugin
fi
}
# -------------------------------------------------------------------------
munin_help() { # shows this
grep '^munin_.*().*#' $(which $0) |
sed 's/().*#/ : /;s/_/ /'
}
# -------------------------------------------------------------------------
munin_${1:-help}
# consider to generate a warning with absolute graph styles:
# grep -i "\.type *absolute"