diff --git a/plugins/disk/iostat b/plugins/disk/iostat deleted file mode 100755 index 16278f6b..00000000 --- a/plugins/disk/iostat +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -# -# Monitor disk iostat on FreeBSD host. -# -# Parameters understood: -# -# config (required) -# autoconf (optional - used by munin-config) -# -# Magic markers (optional - used by munin-config and installation -# scripts): -# -#%# family=auto -#%# capabilities=autoconf - -PATH=/bin:/usr/bin - -if [ "$1" = "autoconf" ]; then - echo yes - exit 0 -fi - -DISKS=`/usr/sbin/iostat -dIn9 | head -1` - -if [ "$1" = "config" ]; then - echo 'graph_title IOstat' - echo 'graph_args --base 1024 -l 0' - echo 'graph_vlabel Bytes per ${graph_period}' - echo 'graph_category disk' - echo 'graph_info This graph shows disk load on the machine.' - - for D in $DISKS - do - if echo $D | grep -vq '^pass'; then - echo "$D.label $D" - echo "$D.type DERIVE" - echo "$D.min 0" - fi - done - - exit 0 -fi - -VALUES=`/usr/sbin/iostat -dIn9 | tail -1` -COL=3 # 3rd value for each disk is grabbed - -for D in $DISKS -do - if echo $D | grep -vq '^pass'; then - echo -n "$D.value " - VAL=`echo $VALUES | cut -d ' ' -f $COL` - echo "$VAL 1048576 * p" | dc | cut -d '.' -f 1 - fi - COL=$(($COL + 3)) -done diff --git a/plugins/disk/smart b/plugins/disk/smart deleted file mode 100755 index 7616fc97..00000000 --- a/plugins/disk/smart +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl -# -# Plugin to monitor all S.M.A.R.T. capable disks -# author: paulv@dds.nl / paulv@bikkel.org -# licence : public domain -# -# Usage: copy or link into /etc/munin/plugins/ as smart_[device] ( smart_sg0 for example) -# Run as root -# -# Parameters: -# -# config (required) -# autoconf (optional - used by munin-config) -# -# Magic markers (optional - used by munin-config and some installation -# scripts): -# -#%# family=manual -#%# capabilities=autoconf -# - -use strict; - -my $device = "/dev/$1" if ( $0 =~ /[\w_-]+_(\w+\d+)$/ ); -my $smartctl = 'smartctl'; -my $smartctl_param = ' --attributes '; -my %attr; - -if ( $ARGV[0] and $ARGV[0] eq "autoconf" ) { - - print "yes\n"; - exit 0; -} - -open(SMART,"$smartctl $smartctl_param $device |") || die $!; - -while() { - chop; - if ( m/\s*(\d+)\s+([\w_-]+)\s+(\d+x.+)\s+(\d+)\s+(\d+)\s+(\d+)\s+([\w_-]+)\s+(\w+)\s+([\w_-]+)\s+(\d+)/ ) { - my $key = $1 . '_' . $2; - my $rawvalue = $10; - - $key = "170_Reserved_Block_Count" if $key eq "170_Unknown_Attribute"; - $key = "171_Program_Fail_Count" if $key eq "171_Unknown_Attribute"; - $key = "172_Erase_Fail_Count" if $key eq "172_Unknown_Attribute"; - $key = "173_Wear_Leveling_Count" if $key eq "173_Unknown_Attribute"; - $key = "174_Unexpected_Pwr_Loss" if $key eq "174_Unknown_Attribute"; - $key = "189_High_Fly_Writes" if $key eq "189_Unknown_Attribute"; - $key = "202_TA_Increase_Count" if $key eq "202_Unknown_Attribute"; - $key = "206_Flying_Height" if $key eq "206_Unknown_Attribute"; - - $attr{$key} = $rawvalue; - } -} - - -if ( $ARGV[0] and $ARGV[0] eq "config" ) -{ - - print "graph_title SMART values for $device\n"; - print "graph_args --base 1000 -l 0\n"; - print "graph_category disk\n"; - print "graph_vlabel value\n"; - print "graph_scale no\n"; - print "graph_total Total\n"; - foreach my $i (keys %attr) - { - print "$i.label smartattribute $i\n"; - print "$i.draw LINE2\n"; - print "$i.min 0\n"; - } - exit 0; -} - -foreach my $k (keys %attr) { - print $k . ".value " . $attr{$k} . "\n"; -} -# end diff --git a/plugins/disk/smart-by-id_ b/plugins/disk/smart-by-id_ deleted file mode 100755 index 04ae3a49..00000000 --- a/plugins/disk/smart-by-id_ +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -DISK=${0/*smart-by-id_/} -SMARTCTL="`which smartctl | head -1` $SMARTOPTS" - -echo "# $DISK" - -export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -case $1 in -config) - echo 'graph_title S.M.A.R.T values for drive '`readlink -f /dev/disk/by-id/$DISK` - echo 'graph_vlabel Attribute S.M.A.R.T value' - echo 'graph_args --base 1000 --lower-limit 0' - echo 'graph_category disk' - echo 'graph_info This graph shows the value of all S.M.A.R.T attributes of drive '`$SMARTCTL -i /dev/disk/by-id/$DISK | grep -Ei 'model|serial|firmware' | sed -re 's/.+?: +//gm' | tr '\n' ' '` - echo 'smartctl_exit_status.label smartctl exit value' - echo 'smartctl_exit_status.draw LINE2' - echo 'smartctl_exit_class.label smartctl exit status' - echo 'smartctl_exit_class.draw AREA' - echo 'smartctl_exit_class.warning :0' - echo 'smartctl_exit_class.critical :1' - - $SMARTCTL -A /dev/disk/by-id/$DISK | grep 0x | while read - do - OP=($REPLY) - ON=`echo -n ${OP[1]} | tr -c '[A-z0-9]' '_'` - OL=`echo -n ${OP[1]} | tr '_' ' '` - echo ${ON}.label ${OL} - echo ${ON}.draw LINE2 - echo ${ON}.critical ${OP[5]}: - done - ;; -suggest) - ls -1 /dev/disk/by-id/scsi-* | grep -v part | grep -o scsi.* - ;; -"") - $SMARTCTL -a /dev/disk/by-id/$DISK &> /dev/null - SES=$? - echo "smartctl_exit_status.value $SES" - if [ $SES -gt 0 ] - then - if [ $((SES & 7)) -gt 0 ] ; then exit 1 ; fi - if [ $((SES & 24)) -gt 0 ] ; then SES=2 ; fi - if [ $((SES & 224)) -gt 0 ] ; then SES=1 ; fi - fi - echo "smartctl_exit_class.value $SES" - $SMARTCTL -A /dev/disk/by-id/$DISK | awk '/0x/ { gsub(/[^a-zA-Z0-9]/,"_",$2); print $2.".value",$4; }' - ;; -esac - -#exit 0 \ No newline at end of file diff --git a/plugins/disk/smart_ b/plugins/disk/smart_ deleted file mode 100755 index a1180284..00000000 --- a/plugins/disk/smart_ +++ /dev/null @@ -1,585 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: iso-8859-1 -*- -# -# Wildcard-plugin to monitor S.M.A.R.T attribute values through smartctl, -# which is part of smartmontools package: -# http://smartmontools.sourceforge.net/ -# -# To monitor a S.M.A.R.T device, link smart_ to this file. -# E.g. -# ln -s /usr/share/munin/plugins/smart_ /etc/munin/plugins/smart_hda -# ...will monitor /dev/hda. -# -# Needs following minimal configuration in plugin-conf.d/munin-node: -# [smart_*] -# user root -# group disk -# -# Parameters -# smartpath - Specify path to smartctl program (Default: /usr/sbin/smartctl) -# smartargs - Override '-a' argument passed to smartctl with '-A -i'+smartargs -# ignorestandby - Ignore the standby state of the drive and perform SMART query. Default: False -# -# Parameters can be specified on a per-drive basis, eg: -# [smart_hda] -# user root -# group disk -# env.smartargs -H -c -l error -l selftest -l selective -d ata -# env.smartpath /usr/local/sbin/smartctl -# -# [smart_twa0-1] -# user root -# group disk -# env.smartargs -H -l error -d 3ware,1 -# env.ignorestandby True -# -# [smart_twa0-2] -# user root -# group disk -# env.smartargs -H -l error -d 3ware,2 -# -# Author: Nicolas Stransky -# -# v1.0 22/08/2004 - First draft -# v1.2 28/08/2004 - Clean up the code, add a verbose option -# v1.3 14/11/2004 - Compatibility with python<2.2. See comments in the code -# v1.4 17/11/2004 - Deal with non zero exit codes of smartctl -# - config now prints the critical thresholds, as reported by smartctl -# v1.5 18/11/2004 - Plot smartctl_exit_code bitmask -# v1.6 21/11/2004 - Add autoconf and suggest capabilities -# - smartctl path can be passed through "smartpath" environment variable -# - Additional smartctl args can be passed through "smartargs" environment variable -# v1.7 29/11/2004 - Add suggest capabilities for NetBSD, OpenBSD, FreeBSD and SunOS. -# - Allow to override completely the smartctl arguments with "smartargs" -# v1.8 16/02/2005 - Exit status field now only triggers warnings, not criticals. -# v1.9 07/07/2005 - Allow to query several drives on the same 3ware card. -# - Correct a bug when '-i' was not listed in smartargs -# - Don't fail if no value was obtained for hard drive model -# v1.10 19/08/2005 - smartctl_exit_code is now a numerical value -# v2.0 08/05/2009 - Correct bug in the interpretation of smartctl_exit_code -# - New option to suppress SMART warnings in munin -# - Temporary lack of output for previously existing drive now reports U -# - The plugin now contains its own documentation for use with munindoc -# - Removed python<2.2 compatibility comments -# - Better autodetection of drives -# - Don't spin up devices in a low-power mode. -# -# Copyright (c) 2004-2009 Nicolas Stransky. -# -# Permission to use, copy, and modify this software with or without fee -# is hereby granted, provided that this entire notice is included in -# all source code copies of any software which is or includes a copy or -# modification of this software. -# -# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR -# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY -# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE -# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR -# PURPOSE. -# -# -# Magic markers -#%# capabilities=autoconf suggest -#%# family=auto - -## You may edit the following 3 variables -# Increase verbosity (True/False) -verbose=False -# Suppress SMART warnings (True/False) -report_warnings=True -# Modify to your needs: -statefiledir='/var/lib/munin/plugin-state/' -# You may not modify anything below this line - -import os, sys, string, pickle -from math import log -plugin_version="2.0" - -def verboselog(s): - global plugin_name - sys.stderr.write(plugin_name+': '+s+'\n') - -if not verbose : - verboselog = lambda s: None - -def read_values(hard_drive): - global smart_values, emptyoutput - try : - verboselog('Reading S.M.A.R.T values') - os.putenv('LC_ALL','C') - smart_output=os.popen(os.getenv('smartpath','/usr/sbin/smartctl')+' '+os.getenv('smartargs','-a')+(os.getenv('ignorestandby',False) and ' ' or ' -n standby ')+'-A -i /dev/'+hard_drive) - read_values=0 - for l in smart_output : - if l[:-1]=='' : - read_values=0 - elif l[:13]=='Device Model:' or l[:7]=='Device:' : - model_list=string.split(string.split(l,':')[1]) - try: model_list.remove('Version') - except : None - model=string.join(model_list) - if read_values==1 : - smart_attribute=string.split(l) - smart_values[string.replace(smart_attribute[1],'-','_')]={"value":smart_attribute[3],"threshold":smart_attribute[5]} - elif l[:18]=="ID# ATTRIBUTE_NAME" : - # Start reading the Attributes block - read_values=1 - exit_status=smart_output.close() - if exit_status!=None : - # smartctl exit code is a bitmask, check man page. - num_exit_status=int(exit_status/256) # Python convention - if int(log(num_exit_status,2))<=2 : # bit code - verboselog('smartctl cannot access S.M.A.R.T values on drive '+hard_drive+'. Command exited with code '+str(num_exit_status)+' (bit '+str(int(log(num_exit_status,2)))+')') - else : - verboselog('smartctl exited with code '+str(num_exit_status)+' (bit '+str(int(log(num_exit_status,2)))+'). '+hard_drive+' may be FAILING RIGHT NOW!') - else : - num_exit_status=0 - except : - verboselog('Cannot access S.M.A.R.T values! Check user rights or propper smartmontools installation/arguments.') - sys.exit(1) - if smart_values=={} : - verboselog('Can\'t find any S.M.A.R.T values in smartctl output!') - emptyoutput=True - #sys.exit(1) - else : emptyoutput=False - smart_values["smartctl_exit_status"]={"value":str(num_exit_status),"threshold":"1"} - try : smart_values["model"]=model - # For some reason we may have no value for "model" - except : smart_values["model"]="unknown" - return(exit_status) - -def open_state_file(hard_drive,mode) : - global statefiledir - return open(statefiledir+'/smart-'+string.join(hard_drive,"-")+'.state',mode) - -def update_state_file(hard_drive) : - try: - verboselog('Saving statefile') - pickle.dump(smart_values,open_state_file(hard_drive,"w")) - except : - verboselog('Error trying to save state file! Check access rights') - -def print_plugin_values(hard_drive) : - global emptyoutput, smart_values - if not emptyoutput: - verboselog('Printing S.M.A.R.T values') - for key in smart_values.keys() : - if key=="model" : continue - print(key+".value "+smart_values[key]["value"]) - else: - print_unknown_from_statefile(hard_drive,smart_values) - -def print_config(hard_drive) : - global report_warnings, smart_values, statefiledir - if os.path.exists(statefiledir+'/smart-'+string.join(hard_drive,"-")+'.state'): - try : - verboselog('Try to recall previous S.M.A.R.T attributes for '+string.join(hard_drive,",")) - smart_values_state=pickle.load(open_state_file(hard_drive,"r")) - except : - verboselog('Error opening existing state file!') - sys.exit(1) - else : - verboselog('No state file, reading S.M.A.R.T values for the first time') - read_values(hard_drive[0]) - pickle.dump(smart_values,open_state_file(hard_drive,"w")) - smart_values_state=smart_values - - verboselog('Printing configuration') - print('graph_title S.M.A.R.T values for drive '+string.join(hard_drive,",")) - print('graph_vlabel Attribute S.M.A.R.T value') - print('graph_args --base 1000 --lower-limit 0') - print('graph_category disk') - print('graph_info This graph shows the value of all S.M.A.R.T attributes of drive '+string.join(hard_drive,",")+' ('+smart_values_state['model']+'). smartctl_exit_status is the return value of smartctl. A non-zero return value indicates an error, a potential error, or a fault on the drive.') - attributes=smart_values_state.keys() - attributes.sort() - for key in attributes : - if key in ['smartctl_exit_status','model'] : continue - print(key+'.label '+key) - print(key+'.draw LINE2') - if report_warnings: print(key+'.critical '+smart_values_state[key]["threshold"]+':') - print('smartctl_exit_status.label smartctl_exit_status') - print('smartctl_exit_status.draw LINE2') - if report_warnings: print('smartctl_exit_status.warning '+smart_values_state['smartctl_exit_status']["threshold"]) - -def print_unknown_from_statefile(hard_drive,smart_values) : - global statefiledir - if os.path.exists(statefiledir+'/smart-'+string.join(hard_drive,"-")+'.state'): - try : - verboselog('Failed to get S.M.A.R.T values from drive. Try to recall previous S.M.A.R.T attributes for '+string.join(hard_drive,",")) - smart_values_state=pickle.load(open_state_file(hard_drive,"r")) - except : - verboselog('Error opening existing state file!') - sys.exit(1) - else : - verboselog('No state file, reading S.M.A.R.T values for the first time') - exit(1) - - verboselog('Printing unknown values for all attributes in state file') - attributes=smart_values_state.keys() - attributes.sort() - for key in attributes : - if key=='model' : continue - print(key+'.value U') - -def get_hard_drive_name() : - global plugin_name - try : - name=[plugin_name[string.rindex(plugin_name,'_')+1:]] - if os.uname()[0]=="SunOS" : - try : - # if hard_drive name starts with "rdsk" or "rmt", try to reconstruct the path - if name[0][0:4]=="rdsk": - name[0]=os.path.join("rdsk",name[0][4:]) - elif name[0][0:3]=="rmt": - name[0]=os.path.join("rmt",name[0][3:]) - except : - verboselog('Failed to find SunOS hard_drive') - # For 3ware cards, we have to set multiple plugins for the same hard drive name. - # Let's see if we find a '-' in the drive name. - if name[0].find('-')!=-1: - # Put the drive name and it's number in a list - name=[name[0][:string.rindex(name[0],'-')],name[0][string.rindex(name[0],'-')+1:]] - # Chech that the drive exists in /dev - if not os.path.exists('/dev/'+name[0]): - verboselog('/dev/'+name[0]+' not found!') - sys.exit(1) - return(name) - except : - verboselog('No S.M.A.R.T device name found in plugin\'s symlink!') - sys.exit(1) - -def find_smart_drives() : - global emptyoutput - # Try to autodetect Linux, *BSD, SunOS drives. Don't try to autodetect drives on a 3Ware card. - drives=[] - if os.uname()[0]=="Linux" : - if os.path.exists('/sys/block/'): - # Running 2.6 - try : - for drive in os.listdir('/sys/block/') : - if drive[:2] in ['md','fd','lo','ra','dm'] : continue # Ignore MD, Floppy, loop , RAM and LVM devices. - try : - verboselog('Trying '+drive+'...') - exit_status=read_values(drive) - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append(drive) - except : - continue - except : - verboselog('Failed to list devices in /sys/block') - else : - verboselog('Not running linux2.6, failing back to /proc/partitions') - try : - partitions=open('/proc/partitions','r') - L=partitions.readlines() - for l in L : - words=string.split(l) - if len(words)==0 or words[0][0] not in string.digits : continue - if words[0] in ['1','9','58','254'] : continue # Ignore RAM, md, LVM and LVM2 devices - if words[-1][-1] not in string.digits : - try : - verboselog('Trying '+words[-1]+'...') - exit_status=read_values(words[-1]) - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append(words[-1]) - except : - continue - verboselog('Found drives in /proc/partitions ! '+str(drives)) - except : - verboselog('Failed to list devices in /proc/partitions') - elif os.uname()[0]=="OpenBSD" : - try : - sysctl_kerndisks=os.popen('sysctl hw.disknames') - kerndisks=string.strip(sysctl_kerndisks.readline()) - for drive in string.split(kerndisks[string.rindex(kerndisks,'=')+1:],',') : - if drive[:2] in ['md','cd','fd'] : continue # Ignore Memory Disks, CD-ROM drives and Floppy - try : - verboselog('Trying '+drive+'c...') - exit_status=read_values(drive+'c') - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append(drive+'c') - except : - continue - except : - verboselog('Failed to list OpenBSD disks') - elif os.uname()[0]=="FreeBSD" : - try : - sysctl_kerndisks=os.popen('sysctl kern.disks') - kerndisks=string.strip(sysctl_kerndisks.readline()) - for drive in string.split(kerndisks)[1:] : - if drive[:2] in ['md','cd','fd'] : continue # Ignore Memory Disks, CD-ROM drives and Floppy - try : - verboselog('Trying '+drive+'...') - exit_status=read_values(drive) - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append(drive) - except : - continue - except : - verboselog('Failed to list FreeBSD disks') - elif os.uname()[0]=="NetBSD" : - try : - sysctl_kerndisks=os.popen('sysctl hw.disknames') - kerndisks=string.strip(sysctl_kerndisks.readline()) - for drive in string.split(kerndisks)[2:] : - if drive[:2] in ['md','cd','fd'] : continue # Ignore Memory Disks, CD-ROM drives and Floppy - try : - verboselog('Trying '+drive+'c...') - exit_status=read_values(drive+'c') - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append(drive+'c') - except : - continue - except : - verboselog('Failed to list NetBSD disks') - elif os.uname()[0]=="SunOS" : - try : - from glob import glob - for drivepath in glob('/dev/rdsk/*s2') : - try : - drive=os.path.basename(drivepath) - verboselog('Trying rdsk'+drive+'...') - exit_status=read_values('rdsk'+drive) - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append('rdsk'+drive) - except : - continue - for drivepath in glob('/dev/rmt/*') : - try : - drive=os.path.basename(drivepath) - verboselog('Trying rmt'+drive+'...') - exit_status=read_values('rmt'+drive) - if (exit_status==None or int(log(int(exit_status/256),2))>2) and not emptyoutput: - drives.append('rmt'+drive) - except : - continue - except : - verboselog('Failed to list SunOS disks') - return(drives) - -### Main part ### - -smart_values={} -emptyoutput=False -plugin_name=list(os.path.split(sys.argv[0]))[1] -verboselog('plugins\' UID: '+str(os.geteuid())+' / plugins\' GID: '+str(os.getegid())) - -# Parse arguments -if len(sys.argv)>1 : - if sys.argv[1]=="config" : - hard_drive=get_hard_drive_name() - print_config(hard_drive) - sys.exit(0) - elif sys.argv[1]=="autoconf" : - if os.path.exists(os.getenv('smartpath','/usr/sbin/smartctl')) : - print('yes') - sys.exit(0) - else : - print('no (smartmontools not found)') - sys.exit(1) - elif sys.argv[1]=="suggest" : - for drive in find_smart_drives() : - print(drive) - sys.exit(0) - elif sys.argv[1]=="version" : - print('smart_ Munin plugin, version '+plugin_version) - sys.exit(0) - elif sys.argv[1]!="" : - verboselog('unknown argument "'+sys.argv[1]+'"') - sys.exit(1) - -# No argument given, doing the real job: -hard_drive=get_hard_drive_name() -read_values(hard_drive[0]) -if not emptyoutput: update_state_file(hard_drive) -print_plugin_values(hard_drive) -exit(0) - - -### The following is the smart_ plugin documentation, intended to be used with munindoc -""" -=head1 NAME - -smart_ - Munin wildcard-plugin to monitor S.M.A.R.T. attribute values through smartctl - -=head1 APPLICABLE SYSTEMS - -Node with B interpreter and B (http://smartmontools.sourceforge.net/) -installed and in function. - -=head1 CONFIGURATION - -=head2 Create link in service directory - -To monitor a S.M.A.R.T device, create a link in the service directory -of the munin-node named smart_, which is pointing to this file. - -E.g. - -ln -s /usr/share/munin/plugins/smart_ /etc/munin/plugins/smart_hda - -...will monitor /dev/hda. - -=head2 Grant privileges in munin-node - -The plugin must be run under high privileged user B, to get access to the raw device. - -So following minimal configuration in plugin-conf.d/munin-node is needed. - -=over 2 - - [smart_*] - user root - group disk - -=back - -=head2 Set Parameter if needed - - smartpath - Specify path to smartctl program (Default: /usr/sbin/smartctl) - smartargs - Override '-a' argument passed to smartctl with '-A -i'+smartargs - ignorestandby - Ignore the standby state of the drive and perform SMART query. Default: False - -Parameters can be specified on a per-drive basis, eg: - -=over 2 - - [smart_hda] - user root - env.smartargs -H -c -l error -l selftest -l selective -d ata - env.smartpath /usr/local/sbin/smartctl - -=back - -In particular, for SATA drives, with older versions of smartctl: - -=over 2 - - [smart_sda] - user root - env.smartargs -d ata -a - - [smart_twa0-1] - user root - env.smartargs -H -l error -d 3ware,1 - env.ignorestandby True - - [smart_twa0-2] - user root - env.smartargs -H -l error -d 3ware,2 - -=back - -=head1 INTERPRETATION - -If a device supports the B it offers readable -access to the attribute table. There you find the B, -a B and a B (set by the vendor) -for each attribute, that is supported by that device. - -The meaning and handling of the raw value is a secret of the -vendors embedded S.M.A.R.T.-Software on the disk. The only -relevant info from our external view is the B -in comparison with the B. If the attributes value is -equal or below the threshold, it signals its failure and -the B of the device will switch from B to B. - -This plugin fetches the B -and draw a curve for each of them. -It takes the vendors threshold as critical limit for the munin datafield. -So you will see an alarm, if the value reaches the vendors threshold. - -Looking at the graph: It is a bad sign, if the curve starts -to curl or to meander. The more horizontal it runs, -the better. Of course it is normal, that the temperatures -curve swings a bit. But the others should stay steady on -their level if everything is ok. - -S.M.A.R.T. distinguishes between B and B -Attributes. An old disk will have more curling curves -because of degradation, especially for the B Attributes. -You should then backup more often, run more selftests[1] and prepare -the disks replacement. - -B, if a Attribute goes below threshold. -Immediately back-up your data and replace your hard disk drive. -A failure may be imminent.. - -[1] Consult the smartmontools manpages to learn about -offline tests and automated selftests with smartd. -Only with both activated, the values of the SMART-Attributes -reflect the all over state of the device. - -Tutorials and articles about S.M.A.R.T. and smartmontools: -http://smartmontools.sourceforge.net/doc.html#tutorials - -=head1 MAGIC MARKERS - - #%# family=auto - #%# capabilities=autoconf suggest - -=head1 CALL OPTIONS - -B - -=over 2 - -Fetches values if called without arguments: - -E.g.: munin-run smart_hda - -=back - -B - -=over 2 - -Prints plugins configuration. - -E.g.: munin-run smart_hda config - -=back - -B - -=over 2 - -Tries to find smartctl and outputs value 'yes' for success, 'no' if not. - -It's used by B to see wether autoconfiguration is possible. - -=back - -B - -=over 2 - -Outputs the list of device names, that it found plugged to the system. - -B use this to build the service links for this wildcard-plugin. - -=back - -=head1 VERSION - -Version 2.0 - -=head1 BUGS - -None known - -=head1 AUTHOR - -(C) 2004-2009 Nicolas Stransky - -(C) 2008 Gabriele Pohl -Reformated existent documentation to POD-Style, added section Interpretation to the documentation. - -=head1 LICENSE - -GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt) - -=cut - - -""" diff --git a/plugins/disk/smart_raw__ b/plugins/disk/smart_raw__ deleted file mode 100755 index e466a7dd..00000000 --- a/plugins/disk/smart_raw__ +++ /dev/null @@ -1,145 +0,0 @@ - #!/usr/bin/python -# -# Copyright (C) 2011 Andreas Thienemann -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -""" -=head1 NAME - -smart_raw__ - Munin plugin to retreive raw SMART values from a disk. - -=head1 APPLICABLE SYSTEMS - -All machines with a SMART capable disk and smartmontools installed. - -This plugin is very useful if you want to need to monitor a single raw S.M.A.R.T. -value reported by a disk. Load Cycle Counts or Pending Sectors come to mind as -these are a good indicator of problems with a disk. - -=head1 CONFIGURATION - -The plugin should be installed as smart_raw_sda_193 which means that the smart value -numbered 193 will be read from the disk sda. - - -Basic configuration for every system is that the plugin needs to be called as root -in order to execute smartmontools. - -Add the following to your /etc/munin/plugin-conf.d/smart_raw: - - [smart_raw_sda_193] - user root - -=head1 INTERPRETATION - -Smart RAW values are provided as is. You need to undertand what you are monitoring... - -=head1 MAGIC MARKERS - - #%# family=contrib - #%# capabilities= - -=head1 VERSION - -0.0.1 - -=head1 BUGS - -None known. - -=head1 AUTHOR - -Andreas Thienemann - -=head1 LICENSE - -GPLv3+ - -=cut -""" - -import subprocess -import sys -import os -import re -import pprint - -# We are a wildcard plugin, figure out what we are being called for -try: - disk = sys.argv[0].split('_')[2] - value = sys.argv[0].split('_')[3] -except IndexError: - sys.exit(1) - -def normalize_name(name): - name = re.sub("[^a-z0-9A-Z]","_", name) - return name - -# Code sniplet from Philipp Keller -# http://code.pui.ch/2007/02/19/set-timeout-for-a-shell-command-in-python/ -def timeout_command(command, timeout): - """call shell-command and either return its output or kill it - if it doesn't normally exit within timeout seconds and return None""" - import subprocess, datetime, os, time, signal - start = datetime.datetime.now() - process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - while process.poll() is None: - time.sleep(0.1) - now = datetime.datetime.now() - if (now - start).seconds> timeout: - os.kill(process.pid, signal.SIGKILL) - os.waitpid(-1, os.WNOHANG) - return None - return process.stdout.read() - -def read_smart(): - """Read SMART attributes""" - out = timeout_command("/usr/sbin/smartctl -A -d ata /dev/%s" % (disk), 2) - smart_attribs = dict() - for line in out.split('\n')[7:-2]: # Cut away the header and the footer - line = line.split() - smart_attribs[line[0]] = { - 'name' : line[1], - 'label' : normalize_name(line[1]), - 'raw' : line [-1], - } - return smart_attribs - -def print_config(): - """Return configuration arguments for munin""" - attribs = read_smart() - print "graph_title S.M.A.R.T raw value %s for drive %s" % (attribs[value]['name'], disk) - print "graph_vlabel Raw value" - print "graph_info RAW smartctl value" - print "graph_category disk" - print "graph_args --base 1000 -l 0" - - print "%s.label %s" % (value, attribs[value]['label']) - sys.exit(0) - -def fetch(): - attribs = read_smart() - print "%s.value %s" % (value, attribs[value]['raw']) - sys.exit(0) - -if "config" in sys.argv[1:]: - print_config() -elif "autoconf" in sys.argv[1:]: - pass -elif "suggest" in sys.argv[1:]: - pass -else: - fetch() diff --git a/plugins/other/sensors_ b/plugins/other/sensors_ deleted file mode 100755 index b4db86ba..00000000 --- a/plugins/other/sensors_ +++ /dev/null @@ -1,184 +0,0 @@ -#!/bin/bash -# -# Plugin: sensors_ -# Author: Carlos Ladeira (caladeira at gmail dot com] -# Version: 08.09.13 -# -# -# This script handles the output of lm-sensors -# like this example: -# -# it87-isa-0290 -# Adapter: ISA adapter -# VCore 1: +1.49 V (min = +0.00 V, max = +4.08 V) -# VCore 2: +2.46 V (min = +0.00 V, max = +4.08 V) -# +3.3V: +3.25 V (min = +0.00 V, max = +4.08 V) -# +5V: +4.97 V (min = +0.00 V, max = +6.85 V) -# +12V: +12.22 V (min = +0.00 V, max = +16.32 V) -# -12V: -1.83 V (min = -27.36 V, max = +3.93 V) -# -5V: -9.48 V (min = -13.64 V, max = +4.03 V) -# Stdby: +4.95 V (min = +0.00 V, max = +6.85 V) -# VBat: +3.33 V -# fan1: 3375 RPM (min = 0 RPM, div = 8) -# fan2: 0 RPM (min = 0 RPM, div = 8) -# fan3: 0 RPM (min = 0 RPM, div = 2) -# M/B Temp: +39°C (low = -1°C, high = +127°C) sensor = thermistor -# CPU Temp: +34°C (low = -1°C, high = +127°C) sensor = thermistor -# Temp3: +48°C (low = -1°C, high = +127°C) sensor = thermistor -# -# -# Wildcard-plugin to monitor output of lm sensors. -# -# Syntax: sensors_[_ignore1[,ignore2[,...]]] -# -# fans monitor fans speed -# voltages monitor system voltages -# temperatures monitor system temperatures -# -# ignore1, ignore2, ... list of sensores to ignore -# -# -# HOW TO SETUP THIS SCRIPT -# -# 1. Start copying this script to the munin main plugin directory -# -# sudo cp sensors_ /usr/share/munin/plugins/sensors_ -# -# 2. create links in the user plugin directory with the desired setup -# Some examples: -# -# ln -s /usr/share/munin/plugins/sensors_ /etc/munin/plugins/sensors_fans -# ln -s /usr/share/munin/plugins/sensors_ /etc/munin/plugins/sensors_voltages -# ln -s /usr/share/munin/plugins/sensors_ /etc/munin/plugins/sensors_temperatures_5V,12V -# ln -s /usr/share/munin/plugins/sensors_ /etc/munin/plugins/sensors_temperatures_Temp3 -# -# -# Munin (http://munin.projects.linpro.no/) -# lm-sensors (http://www.lm-sensors.org/) -# -# Requirements: * lm-sensors (http://www.lm-sensors.org/) -# -# -# Changelog: v08.09.07 - initial release -# v08.09.13 - add ignore parameter list -# -# -#%# family=contrib -#%# capabilities=autoconf suggest - -##### CONSTANTS ##################################################### - -DETECTED_SENSORS=$(sensors -U -A | wc -l) -GCAT="sensors" - -IGNORE_DELIMITER='_' - -ARGS=$(basename $0 | sed -e 's/^sensors_//g') -MODE=$(echo -n $ARGS | cut -d $IGNORE_DELIMITER -f 1) -IGNORE=$(echo -n $ARGS | cut -d $IGNORE_DELIMITER -f 2) - -IGNORE_LIST="" -if [ -n "$IGNORE" ] ; then - if [ "$IGNORE" != "$MODE" ] ; then - IGNORE_LIST="$(echo -n $IGNORE | sed -e 's/,/ /g')" - fi -fi - -case "$MODE" in - - voltages) - LINE_FILTER=" V" - VALUE_FILTER='V' - GTITLE="Voltages" - GLABEL="Volts" - ;; - - temperatures) - LINE_FILTER="C " - VALUE_FILTER='C' - GTITLE="Temperatures" - GLABEL="Celsius" - ;; - - fans) - LINE_FILTER="RPM" - VALUE_FILTER='R' - GTITLE="Fans Speed" - GLABEL="RPM" - ;; - - *) - echo "Invalid Option: $MODE" - exit 1 - -esac - - -##################################################################### - -if [ "$1" == "autoconf" ]; then - - if [ "$DETECTED_SENSORS" -eq 0 ]; then - echo "no" - exit 1 - else - echo "yes" - exit 0 - fi - -elif [ "$1" == "suggest" ]; then - - echo "voltages" - echo "temperatures" - echo "fans" - exit 0 - -elif [ "$1" == "config" ]; then - - echo "graph_title $GTITLE" - echo "graph_vlabel $GLABEL" - echo "graph_category $GCAT" - echo "graph_args --base 1000 -l 0" - echo "graph_scale no" - - sensors | grep "$LINE_FILTER" | - - while read a; do - label=$(echo $a | cut -d ':' -f 1 | sed -e 's/[+| |/]//g' -e 's/-/n/' -e 's/\./_/') - name=$(echo $a | cut -d ':' -f 1) - - found=0 - for item in $IGNORE_LIST; do - if [ "$item" == "$label" ] ; then - found=1 - fi - done - - if [ $found -eq 0 ] ; then - echo $label.label $name - fi - done - -else - - sensors | grep "$LINE_FILTER" | - - while read a; do - label=$(echo $a | cut -d ':' -f 1 | sed -e 's/[+| |/]//g' -e 's/-/n/' -e 's/\./_/') - value=$(echo $a | cut -d ':' -f 2 | cut -d $VALUE_FILTER -f 1 | sed -e 's/[+|[:blank:]|°|C]//g') - - found=0 - for item in $IGNORE_LIST; do - if [ "$item" == "$label" ] ; then - found=1 - fi - done - - if [ $found -eq 0 ] ; then - echo $label.value $value - fi - - done - -fi - diff --git a/plugins/system/meminfo b/plugins/system/meminfo deleted file mode 100755 index 227761f2..00000000 --- a/plugins/system/meminfo +++ /dev/null @@ -1,2201 +0,0 @@ -#!/usr/bin/perl -w -# -*- perl -*- - -=head1 NAME - -meminfo - Plugin to monitor memory usage. -This plugin show many graphs (on my pc ~90 graphs with total ~750 values) -Graph splitted to 8 groups, every group has child graphs: - - Application groups memory usage - show applications groups memory using by group (env.) [env.applications_group] - Group `groupName1` applications memory usage v - ... - show applications groups memory using per application in every group - Group `groupNameX` applications memory usage ^ - Summary group `groupName1` memory usage v - ... - show applications groups memory using as summ of every parametr of application in every group - Summary group `groupNameX` memory usage ^ - Application memory usage - show memory usage per application [env.applications] - Application processes - show processes count of every application - Summary `applicationName1` memory usage v - ... - Summary application processes memory using - Summary `applicationNameX` memory usage ^ - External fragmentztion: Buddyinfo - Buddyinfo/ Nodes and zones summary - Node X, zone ZZZ - Chunks for each zone - External fragmentztion: Page type info - Page type info, summary node-zone-type pages - Node X, zone ZZZ, type TTT - Free pages per node-zone-page by order - Physical memory usage - Main graph, show phisical memory usage - Active/Inactive memory - subj :) - Memory usage by cashes and buffers - subj :) - mmap - mmapp'ed memory - HugePages count - subj :) - HugePages size - subj :) - Kernel memory - subj :) - Low and high memory - subj :) - Slab objects size - subj :) - Slabs size [GroupName1] v - ... - show slabs size. I try split fields by this types. - Slabs size [GroupNameX] ^ - Slabs sizes of groups - "Groups" sizes - Slab objects - Active/inactive objects - Slabs - Active/inactive and shared slabs - Reclaim - Reclaimed - Swap usage - subj :) - First candidates to swap out - subj :) - Writeback - writeback and dirty - Virtual memory usage - subj :) - Vmalloc - show vmalloc usage - Vmalloc allocates - allocates per object - - -=head1 APPLICABLE SYSTEMS - -All Linux systems - -=head1 CONFIGURATION - -The plugin automatically selects which graphics drawing. -But you can select graphs to draw by enabled_graphs environment. -enabled_graphs is a regexp, where you include graphs to draw -Default: undefined -Examples: - - env.enabled_graphs meminfo_\w+\.? # Draw only meminfo graphs - env.enabled_graphs (meminfo|swapinfo)$ # Draw only meminfo and swapinfo graphs, without 'childs' - -Also you can select applications to monitor it by applications environment -applications environment is regexp -Default: undefined -Examples: - - env.applications (firefox|\w{1,3}?sh) # Monitor firefox and shells (bash, zsh, sh, etc...) - -Also you can group applications and show memory using of this groups, per application -in group and summmary applications in group. Use env.applications_group for this. -Format: env.applications_group regexp:groupName;regexp:groupName;... -where regexp - it applications names regexp, and groupName - on-screen group name -Default: undefined -Examples: - - env.applications_group ^(firefox|chrome|opera|konqu|arora):Browsers;(^lx|openbox|menu|gnome|slim|^X):X;^(hal|console-kit|syslog|cron|dhcp|udev|dbus|bluetoo|agett|login|automount):System; - -And you can select time to display data after application close (all values return as 'NaN'), -for this you must used environment env.application_wait Value - secunds -Default: 1800 -Example: - - env.application_wait 86400 #24h - -=head2 RIGHTS NOTE - -Please check, can your munin user read files such as - /proc/meminfo - /proc/slabinfo - /proc/vmallocinfo - /proc/buddyinfo - /proc/pagetypeinfo - /proc/[pid]/status -If no access, just write in plugin-config - [meminfo] - user root - group root - -=head2 WARNING AND CRITICAL SETTINGS - -You can set warning and critical levels for *each* of the data -series the plugin reports. -Template for limits: env.limit_%field% (warning_num:crytical_num|critical_num)[kMG], where -%field% - field name. You can show it in graph viev, 'field internal name' field -warning_num - number, warning value -crytical_num - number, critical value -k - kilobytes, M - megabytes, G - gigabytes -Examples: - - env.limit_apps 300M:500M # Applications, warning - 300M, critical - 500m - env.limit_committed_as 700M # Committed AS, critical - 700M - -=head1 INTERPRETATION - -The plugin shows - -=head1 MAGIC MARKERS - - #%# family=auto - #%# capabilities=autoconf - - -=head1 VERSION - - 1.0 - -=head1 BUGS - -none known - -=head1 AUTHOR - -Gorlow Maxim aka Sheridan (email and jabber) - -=head1 LICENSE - -GPLv2 - -=cut - - - -use strict; -use warnings; -use Munin::Plugin; -use IO::Dir; -use Data::Dumper; - -# ----------------------------------------------------------------------------------------------------------------------------------------------------- -my $graphs_source = -{ - # ---------------------------------------------- - 'meminfo_phisical' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Physical memory usage', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [qw(apps:AREASTACK:- slab:AREASTACK:- buffers:AREASTACK:- cached:AREASTACK:- page_tables:AREASTACK:- cached_swap:AREASTACK:- free:AREASTACK:FFFFCCCC swap_used:AREASTACK:- used:LINE1:- usedwswap:LINE1:- hardware_corrupted:LINE1:- total:LINE1:000000)] - }, - - # ---------------------------------------------- - 'meminfo_phisical.cb' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Memory usage by cashes and buffers', - 'vtitle' => 'bytes', - 'category' => 'cache', - 'total' => 'Total' - }, - 'fields' => [qw(cached:AREASTACK:- buffers:AREASTACK:- cached_swap:AREASTACK:- nfs_unstable:AREASTACK:- writeback_fuse:AREASTACK:- bounce:AREASTACK:-)] - }, - # ---------------------------------------------- - 'meminfo_phisical.active_inactive' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Active/Inactive memory', - 'vtitle' => 'bytes', - 'category' => 'active_inactive' - }, - 'fields' => [qw(active_file:AREA:FF444488 active_anon:STACK:44FF4488 active:LINE1:000000 inactive_file:AREA:4444FF88 inactive_anon:STACK:FFFF4499 inactive:LINE1:FFFFFF)] - }, - # ---------------------------------------------- - 'meminfo_phisical.mmap' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'mmap', - 'vtitle' => 'bytes', - 'category' => 'direct_map' - }, - 'fields' => [qw(direct_map_4k:LINE1:- direct_map_2m:LINE1:- direct_map_4m:LINE1:- direct_map_1g:LINE1:- mapped:LINE1:- mmap_copy:LINE1:-)] - }, - # ---------------------------------------------- - 'meminfo_phisical.kernel' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Kernel memory', - 'vtitle' => 'bytes', - 'category' => 'kernel', - 'total' => 'Total' - }, - 'fields' => [qw(kernel_stack:AREASTACK:- slab:AREASTACK:- qlists:LINE1:-)] - }, - # ---------------------------------------------- - 'meminfo_phisical.low_and_high' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Low and high memory', - 'vtitle' => 'bytes', - 'category' => 'low_and_high' - }, - 'fields' => [qw(low_used:AREASTACK:- low_free:AREASTACK:CCFFCCCC high_used:AREASTACK:- high_free:AREASTACK:FFFFCCCC low_total:LINE1:- high_total:LINE1:- l_h_total:LINE1:000000)] - }, - # ---------------------------------------------- - 'meminfo_phisical.hugepages' => - { - 'munin' => - { - 'args' => '--base 1000 ', - 'title' => 'HugePages count', - 'vtitle' => 'count', - 'category' => 'hugepages' - }, - 'fields' => [qw(huge_pages_total:LINE1:000000 huge_pages_free:AREASTACK:- huge_pages_rsvd:AREASTACK:- huge_pages_surp:AREASTACK:-)] - }, - # ---------------------------------------------- - 'meminfo_phisical.hugepages_sizes' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'HugePages size', - 'vtitle' => 'bytes', - 'category' => 'hugepages' - }, - 'fields' => [qw(huge_page_size:LINE1:00FF00 huge_pages_total_size:LINE1:000000 huge_pages_free_size:AREASTACK:- huge_pages_rsvd_size:AREASTACK:- huge_pages_surp_size:AREASTACK:-)] - }, - # ---------------------------------------------- - 'meminfo_virtual' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Virtual memory usage', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [qw(commit_limit:AREA:88884477 committed_as:AREA:- mlocked:LINE1:- shmem:LINE1:- vmalloc_used:LINE1:-)] - }, - # ---------------------------------------------- - 'meminfo_virtual.vmalloc' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Vmalloc', - 'vtitle' => 'bytes', - 'category' => 'total' - }, - 'fields' => [qw(vmalloc_used:AREASTACK:- vmalloc_free:AREASTACK:FFFFCCCC vmalloc_total:LINE1:000000 vmalloc_chunk:LINE1:-)] - }, - # ---------------------------------------------- - 'meminfo_virtual.vmalloc_allocates' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Vmalloc allocates', - 'vtitle' => 'bytes', - 'category' => 'allocates', - 'total' => 'Total' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'slab' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Slab objects size', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [qw(min_obj_size:AREA:00000000 max_obj_size:STACK:- avg_obj_size:LINE1:-)] - }, - # ---------------------------------------------- - 'slab.slab_objects' => - { - 'munin' => - { - 'args' => '--base 1000 ', - 'title' => 'Slab objects', - 'vtitle' => 'count', - 'category' => 'objects' - }, - 'fields' => [qw(active_objects:AREASTACK:- inactive_objects:AREASTACK:FFFFCCCC total_objects:LINE1:000000)] - }, - # ---------------------------------------------- - 'slab.slabs' => - { - 'munin' => - { - 'args' => '--base 1000 ', - 'title' => 'Slabs', - 'vtitle' => 'count', - 'category' => 'objects' - }, - 'fields' => [qw(active_slabs:AREASTACK:- inactive_slabs:AREASTACK:FFFFCCCC shared_slabs:LINE1:- total_slabs:LINE1:000000)] - }, - # ---------------------------------------------- - 'slab.reclaim' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Reclaim', - 'vtitle' => 'bytes', - 'category' => 'reclaim', - 'total' => 'Total', - }, - 'fields' => [qw(slab_reclaimable:AREA:- slab_unreclaimable:STACK:-)] - }, - # ---------------------------------------------- - 'slab.slabs_size_all_groups' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => "Slabs sizes of groups", - 'vtitle' => 'bytes', - 'total' => 'Total', - 'category' => 'groups_size' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'swapinfo' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Swap usage', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [qw(swap_used:AREA:- swap_free:STACK:FFFFCCCC cached_swap:LINE1:- swap_total:LINE1:000000)] - }, - # ---------------------------------------------- - 'swapinfo.wrback' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Writeback', - 'vtitle' => 'bytes', - 'category' => 'writeback' - }, - 'fields' => [qw(dirty:LINE1:- writeback:LINE1:-)] - }, - # ---------------------------------------------- - 'swapinfo.candidates' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'First candidates to swap out', - 'vtitle' => 'bytes', - 'category' => 'candidates' - }, - 'fields' => [qw(inactive_file:AREASTACK:- inactive_anon:AREASTACK:- anon_pages:AREASTACK:- inactive:LINE1:-)] - }, - # ---------------------------------------------- - 'buddyinfo' => - { - 'munin' => - { - 'args' => '--base 1000', - 'title' => 'External fragmentztion: Buddyinfo', - 'vtitle' => 'chunks', - 'category' => 'memory', - 'info' => 'External fragmentation is a problem under some workloads, and buddyinfo is a useful tool for helping diagnose these problems. Buddyinfo will give you a clue as to how big an area you can safely allocate, or why a previous allocation failed.', - 'total' => 'Total' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'appinfo' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Application memory usage', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'appinfo.processes' => - { - 'munin' => - { - 'args' => '--base 1000', - 'title' => 'Application processes', - 'vtitle' => 'count', - 'category' => 'processes' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'appgroupinfo' => - { - 'munin' => - { - 'args' => '--base 1024', - 'title' => 'Application groups memory usage', - 'vtitle' => 'bytes', - 'category' => 'memory' - }, - 'fields' => [] - }, - # ---------------------------------------------- - 'pagetypeinfo' => - { - 'munin' => - { - 'args' => '--base 1000', - 'title' => 'External fragmentztion: Page type info', - 'vtitle' => 'pages', - 'info' => 'The pagetypinfo gives the same type of information as buddyinfo except broken down by migrate-type and finishes with details on how many page blocks of each type exist.', - 'category' => 'memory' - }, - 'fields' => [] - } -}; - -my $fields_source = -{ - # ---------------------------------------------- - 'apps' => { - 'src' => - { - # y - must exists, n - no - 'calculated' => 'used:y - buffers:y - cached:y - slab:n - page_tables:n - cached_swap:n', - }, - 'munin' => - { - 'label' => 'Applications', - 'info' => 'Memory, used by applications' - } - }, - # ---------------------------------------------- - 'free' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'MemFree' - }, - 'munin' => - { - 'label' => 'Free', - 'info' => 'The sum of LowFree+HighFree' - } - }, - # ---------------------------------------------- - 'used' => { - 'src' => - { - 'calculated' => 'total:y - free:y', - }, - 'munin' => - { - 'label' => 'Used', - 'info' => 'Used memory (see "Total" and "Free")' - } - }, - # ---------------------------------------------- - 'usedwswap' => { - 'src' => - { - 'calculated' => 'used:y + swap_used:y', - }, - 'munin' => - { - 'label' => 'Used + Swap used', - 'info' => 'See "Used" and "Swap used"' - } - }, - # ---------------------------------------------- - 'total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'MemTotal' - }, - 'munin' => - { - 'label' => 'Total', - 'info' => 'Total usable ram (i.e. physical ram minus a few reserved bits and the kernel binary code)' - } - }, - # ---------------------------------------------- - 'buffers' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Buffers' - }, - 'munin' => - { - 'label' => 'Buffers', - 'info' => 'Relatively temporary storage for raw disk blocks shouldn\'t get tremendously large (20MB or so)' - } - }, - # ---------------------------------------------- - 'cached' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Cached' - }, - 'munin' => - { - 'label' => 'Cached', - 'info' => 'In-memory cache for files read from the disk (the pagecache). Doesn\'t include SwapCached' - } - }, - # ---------------------------------------------- - 'cached_swap' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'SwapCached' - }, - 'munin' => - { - 'label' => 'Swap cached', - 'info' => 'Memory that once was swapped out, is swapped back in but still also is in the swapfile (if memory is needed it doesn\'t need to be swapped out AGAIN because it is already in the swapfile. This saves I/O)' - } - }, - # ---------------------------------------------- - 'qlists' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Quicklists' - }, - 'munin' => - { - 'label' => 'Quicklists', - 'info' => '' - } - }, - # ---------------------------------------------- - 'active' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Active' - }, - 'munin' => - { - 'label' => 'Active', - 'info' => 'Memory that has been used more recently and usually not reclaimed unless absolutely necessary.' - } - }, - # ---------------------------------------------- - 'inactive' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Inactive' - }, - 'munin' => - { - 'label' => 'Inactive', - 'info' => 'Memory which has been less recently used. It is more eligible to be reclaimed for other purposes' - } - }, - # ---------------------------------------------- - 'active_file' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Active(file)' - }, - 'munin' => - { - 'label' => 'Active (file)', - 'info' => 'See "Active"' - } - }, - # ---------------------------------------------- - 'inactive_file' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Inactive(file)' - }, - 'munin' => - { - 'label' => 'Inactive (file)', - 'info' => 'See "Inactive"' - } - }, - # ---------------------------------------------- - 'active_anon' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Active(anon)' - }, - 'munin' => - { - 'label' => 'Active (anonymous)', - 'info' => 'See "Active"' - } - }, - # ---------------------------------------------- - 'inactive_anon' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Inactive(anon)' - }, - 'munin' => - { - 'label' => 'Inactive (anonymous)', - 'info' => 'See "Inactive"' - } - }, - # ---------------------------------------------- - 'high_total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HighTotal' - }, - 'munin' => - { - 'label' => 'High total', - 'info' => 'See "High Free"' - } - }, - # ---------------------------------------------- - 'high_free' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HighFree' - }, - 'munin' => - { - 'label' => 'High free', - 'info' => 'Highmem is all memory above ~860MB of physical memory Highmem areas are for use by userspace programs, or for the pagecache. The kernel must use tricks to access this memory, making it slower to access than lowmem.' - } - }, - # ---------------------------------------------- - 'high_used' => { - 'src' => - { - 'calculated' => 'high_total:y - high_free:y' - }, - 'munin' => - { - 'label' => 'High used', - 'info' => 'Used high memory' - } - }, - # ---------------------------------------------- - 'low_total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'LowTotal' - }, - 'munin' => - { - 'label' => 'Low total', - 'info' => 'See "Low Free"' - } - }, - # ---------------------------------------------- - 'low_free' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'LowFree' - }, - 'munin' => - { - 'label' => 'Low free', - 'info' => 'Lowmem is memory which can be used for everything that highmem can be used for, but it is also available for the kernel\'s use for its own data structures. Among many other things, it is where everything from the Slab is allocated. Bad things happen when you\'re out of lowmem.' - } - }, - # ---------------------------------------------- - 'low_used' => { - 'src' => - { - 'calculated' => 'low_total:y - low_free:y' - }, - 'munin' => - { - 'label' => 'Low used', - 'info' => 'Used low memory' - } - }, - # ---------------------------------------------- - 'l_h_total' => { - 'src' => - { - 'calculated' => 'low_total:y + high_total:y' - }, - 'munin' => - { - 'label' => 'Total', - 'info' => 'Total phisical memory' - } - }, - # ---------------------------------------------- - 'swap_total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'SwapTotal' - }, - 'munin' => - { - 'label' => 'Swap total', - 'info' => 'Total amount of swap space available' - } - }, - # ---------------------------------------------- - 'swap_free' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'SwapFree' - }, - 'munin' => - { - 'label' => 'Swap free', - 'info' => 'Memory which has been evicted from RAM, and is temporarily on the disk' - } - }, - # ---------------------------------------------- - 'swap_used' => { - 'src' => - { - 'calculated' => 'swap_total:y - swap_free:y' - }, - 'munin' => - { - 'label' => 'Swap used', - 'info' => 'Memory which has been evicted from RAM, and is temporarily on the disk' - } - }, - # ---------------------------------------------- - 'dirty' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Dirty' - }, - 'munin' => - { - 'label' => 'Dirty', - 'info' => 'Memory which is waiting to get written back to the disk' - } - }, - # ---------------------------------------------- - 'writeback' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Writeback' - }, - 'munin' => - { - 'label' => 'Writeback', - 'info' => 'Memory which is actively being written back to the disk' - } - }, - # ---------------------------------------------- - 'anon_pages' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'AnonPages' - }, - 'munin' => - { - 'label' => 'Anonymous pages', - 'info' => 'Non-file backed pages mapped into userspace page tables' - } - }, - # ---------------------------------------------- - 'mapped' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Mapped' - }, - 'munin' => - { - 'label' => 'Mapped', - 'info' => 'Files which have been mmaped, such as libraries' - } - }, - # ---------------------------------------------- - 'mmap_copy' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'MmapCopy' - }, - 'munin' => - { - 'label' => 'mmap copy', - 'info' => 'Indicates the amount of RAM currently allocated by mmap to hold mappable regions that can\'t be mapped directly. These are copies of the backing device or file if not anonymous.' - } - }, - # ---------------------------------------------- - 'slab' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Slab' - }, - 'munin' => - { - 'label' => 'Slab', - 'info' => 'In-kernel data structures cache' - } - }, - # ---------------------------------------------- - 'slab_reclaimable' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'SReclaimable' - }, - 'munin' => - { - 'label' => 'Slab reclaimable', - 'info' => 'Part of Slab, that might be reclaimed, such as caches' - } - }, - # ---------------------------------------------- - 'slab_unreclaimable' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'SUnreclaim' - }, - 'munin' => - { - 'label' => 'Slab unreclaimable', - 'info' => 'Part of Slab, that cannot be reclaimed on memory pressure' - } - }, - # ---------------------------------------------- - 'page_tables' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'PageTables' - }, - 'munin' => - { - 'label' => 'Page tables', - 'info' => 'amount of memory dedicated to the lowest level of page tables' - } - }, - # ---------------------------------------------- - 'nfs_unstable' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'NFS_Unstable' - }, - 'munin' => - { - 'label' => 'NFS unstable', - 'info' => 'NFS pages sent to the server, but not yet committed to stable <--> storage' - } - }, - # ---------------------------------------------- - 'bounce' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Bounce' - }, - 'munin' => - { - 'label' => 'Bounce', - 'info' => 'Memory used for block device "bounce buffers"' - } - }, - # ---------------------------------------------- - 'writeback_fuse' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'WritebackTmp' - }, - 'munin' => - { - 'label' => 'FUSE buffers', - 'info' => 'Memory used by FUSE for temporary writeback buffers' - } - }, - # ---------------------------------------------- - 'commit_limit' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'CommitLimit' - }, - 'munin' => - { - 'label' => 'Commit limit', - 'info' => 'Based on the overcommit ratio ("vm.overcommit_ratio"), this is the total amount of memory currently available to be allocated on the system. This limit is only adhered to if strict overcommit accounting is enabled (mode 2 in "vm.overcommit_memory"). The CommitLimit is calculated with the following formula=> CommitLimit = ("vm.overcommit_ratio" * Physical RAM) + Swap For example, on a system with 1G of physical RAM and 7G of swap with a `vm.overcommit_ratio` of 30 it would yield a CommitLimit of 7.3G. For more details, see the memory overcommit documentation in vm/overcommit-accounting.', - } - }, - # ---------------------------------------------- - 'committed_as' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Committed_AS' - }, - 'munin' => - { - 'label' => 'Committed AS', - 'info' => 'The amount of memory presently allocated on the system. The committed memory is a sum of all of the memory which has been allocated by processes, even if it has not been "used" by them as of yet. A process which malloc()\'s 1G of memory, but only touches 300M of it will only show up as using 300M of memory even if it has the address space allocated for the entire 1G. This 1G is memory which has been "committed" to by the VM and can be used at any time by the allocating application. With strict overcommit enabled on the system (mode 2 in "vm.overcommit_memory"), allocations which would exceed the CommitLimit (detailed above) will not be permitted. This is useful if one needs to guarantee that processes will not fail due to lack of memory once that memory has been successfully allocated.' - } - }, - # ---------------------------------------------- - 'vmalloc_total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'VmallocTotal' - }, - 'munin' => - { - 'label' => 'Vmalloc total', - 'info' => 'Total size of vmalloc memory area' - } - }, - # ---------------------------------------------- - 'vmalloc_used' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'VmallocUsed' - }, - 'munin' => - { - 'label' => 'Vmalloc used', - 'info' => 'Amount of vmalloc area which is used' - } - }, - # ---------------------------------------------- - 'vmalloc_chunk' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'VmallocChunk' - }, - 'munin' => - { - 'label' => 'Vmalloc chunk', - 'info' => 'largest contiguous block of vmalloc area which is free' - } - }, - # ---------------------------------------------- - 'vmalloc_free' => { - 'src' => - { - # y - must exists, n - no - 'calculated' => 'vmalloc_total:y - vmalloc_used:y' - }, - 'munin' => - { - 'label' => 'Vmalloc free', - 'info' => 'Free size of vmalloc memory area' - } - }, - # ---------------------------------------------- - 'mlocked' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Mlocked' - }, - 'munin' => - { - 'label' => 'Mlocked', - 'info' => '' - } - }, - # ---------------------------------------------- - 'shmem' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Shmem' - }, - 'munin' => - { - 'label' => 'Shared memory', - 'info' => '' - } - }, - # ---------------------------------------------- - 'kernel_stack' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'KernelStack' - }, - 'munin' => - { - 'label' => 'Kernel stack', - 'info' => 'Kernel stack' - } - }, - # ---------------------------------------------- - 'hardware_corrupted' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HardwareCorrupted' - }, - 'munin' => - { - 'label' => 'Hardware corrupted', - 'info' => 'Hardware corrupted' - } - }, - # ---------------------------------------------- - 'huge_pages_total' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HugePages_Total' - }, - 'munin' => - { - 'label' => 'HugePages total', - 'info' => 'Huge Pages is a feature available in later Linux kernels that provides two important benefits: 1. Locks the memory available to huge pages, so it cannot be paged to disk 2. Make the TLB (translation lookaside buffer) much smaller on the processor, as the number of entries is much smaller. This is due to the fact the standard page size in Linux is 4K, whereas a huge page is either 2MB of 4MB in size. This makes managing virtual memory much more efficient, as the processor does not have to work as hard switching pages in and out.' - } - }, - # ---------------------------------------------- - 'huge_pages_free' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HugePages_Free' - }, - 'munin' => - { - 'label' => 'HugePages free', - 'info' => 'See "HugePages_Total"' - } - }, - # ---------------------------------------------- - 'huge_pages_rsvd' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HugePages_Rsvd' - }, - 'munin' => - { - 'label' => 'HugePages reserved', - 'info' => 'See "HugePages_Total"' - } - }, - # ---------------------------------------------- - 'huge_pages_surp' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'HugePages_Surp' - }, - 'munin' => - { - 'label' => 'HugePages surp', - 'info' => 'See "HugePages_Total"' - } - }, - # ---------------------------------------------- - 'huge_pages_total_size' => { - 'src' => - { - 'calculated' => 'huge_page_size:y * huge_pages_total:y' - }, - 'munin' => - { - 'label' => 'HugePages size', - 'info' => 'Total size of HugePages' - } - }, - # ---------------------------------------------- - 'huge_pages_free_size' => { - 'src' => - { - 'calculated' => 'huge_page_size:y * huge_pages_free:y' - }, - 'munin' => - { - 'label' => 'HugePages free', - 'info' => 'Free HugePages memory size' - } - }, - # ---------------------------------------------- - 'huge_pages_rsvd_size' => { - 'src' => - { - 'calculated' => 'huge_page_size:y * huge_pages_rsvd:y' - }, - 'munin' => - { - 'label' => 'HugePages rsvd', - 'info' => 'HugePages reserved size' - } - }, - # ---------------------------------------------- - 'huge_pages_surp_size' => { - 'src' => - { - 'calculated' => 'huge_page_size:y * huge_pages_surp:y' - }, - 'munin' => - { - 'label' => 'HugePages surp', - 'info' => 'HugePages surp size' - } - }, - # ---------------------------------------------- - 'huge_page_size' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'Hugepagesize' - }, - 'munin' => - { - 'label' => 'HugePage size', - 'info' => 'HugePage size' - } - }, - # ---------------------------------------------- - 'direct_map_4k' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'DirectMap4k' - }, - 'munin' => - { - 'label' => 'Direct map 4k', - 'info' => '' - } - }, - # ---------------------------------------------- - 'direct_map_2m' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'DirectMap2M' - }, - 'munin' => - { - 'label' => 'Direct map 2M', - 'info' => '' - } - }, - # ---------------------------------------------- - 'direct_map_4m' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'DirectMap4M' - }, - 'munin' => - { - 'label' => 'Direct map 4M', - 'info' => '' - } - }, - # ---------------------------------------------- - 'direct_map_1g' => { - 'src' => - { - 'target' => 'meminfo', - 'field' => 'DirectMap1G' - }, - 'munin' => - { - 'label' => 'Direct map 1G', - 'info' => '' - } - }, - # ---------------------------------------------- slabinfo ------------- - # ---------------------------------------------- - 'min_obj_size' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'min_obj_size' - }, - 'munin' => - { - 'label' => 'Min. object size', - 'info' => 'Minimal object size' - } - }, - # ---------------------------------------------- - 'avg_obj_size' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'avg_obj_size' - }, - 'munin' => - { - 'label' => 'Avg. object size', - 'info' => 'Average object size' - } - }, - # ---------------------------------------------- - 'max_obj_size' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'max_obj_size' - }, - 'munin' => - { - 'label' => 'Max. object size', - 'info' => 'Maximal object size' - } - }, - # ---------------------------------------------- - 'total_objects' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'total_objects' - }, - 'munin' => - { - 'label' => 'Total objects', - 'info' => 'Total objects' - } - }, - # ---------------------------------------------- - 'active_objects' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'active_objects' - }, - 'munin' => - { - 'label' => 'Active objects', - 'info' => 'Active objects' - } - }, - # ---------------------------------------------- - 'inactive_objects' => { - 'src' => - { - 'calculated' => 'total_objects:y - active_objects:y' - }, - 'munin' => - { - 'label' => 'Inactive objects', - 'info' => 'Inactive objects' - } - }, - # ---------------------------------------------- - 'total_slabs' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'total_slabs' - }, - 'munin' => - { - 'label' => 'Total slabs', - 'info' => 'Total slabs' - } - }, - # ---------------------------------------------- - 'active_slabs' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'active_slabs' - }, - 'munin' => - { - 'label' => 'Active slabs', - 'info' => 'Active slabs' - } - }, - # ---------------------------------------------- - 'shared_slabs' => { - 'src' => - { - 'target' => 'slabinfo', - 'field' => 'shared_slabs' - }, - 'munin' => - { - 'label' => 'Shared slabs', - 'info' => 'Shared slabs' - } - }, - # ---------------------------------------------- - 'inactive_slabs' => { - 'src' => - { - 'calculated' => 'total_slabs:y - active_slabs:y' - }, - 'munin' => - { - 'label' => 'Inactive slabs', - 'info' => 'Inactive slabs' - } - } -}; - -# appdata descriptions -my $application_fields = -{ - 'label' => - { - 'VmLck' => 'Locked in mem', - 'VmHWM' => 'Peak resident', - 'VmPeak' => 'Peak virtual', - 'VmSwap' => 'Swap usage', - 'VmExe' => 'Code segment', - 'VmPTE' => 'Page table entries', - 'VmData' => 'Data segment', - 'VmLib' => 'Shared library', - 'VmSize' => 'Allocated virtual', - 'VmRSS' => 'Mapped in RAM', - 'VmStk' => 'Stack' - }, - 'info' => - { - 'VmLck' => 'The amount of locked memory', - 'VmHWM' => 'Peak resident set size ("high water mark")', - 'VmPeak' => 'Peak virtual memory size', - 'VmSwap' => 'Size of swap usage (the number of referred swapents)', - 'VmExe' => 'The size of the executable segment', - 'VmPTE' => 'Size of page table entries', - 'VmData' => 'The size of the Data segment', - 'VmLib' => 'Size of shared library code', - 'VmSize' => 'The size of the virtual memory allocated to the process', - 'VmRSS' => 'The amount of memory mapped in RAM ( instead of swapped out )', - 'VmStk' => 'The stack size' - }, - 'draw' => - { - 'VmSize' => 'AREA', - 'VmRSS' => 'AREA', - 'VmStk' => 'STACK', - 'VmData' => 'STACK', - 'VmExe' => 'LINE1.5', - 'VmLib' => 'LINE1.5', - 'VmLck' => 'LINE1', - 'VmPTE' => 'LINE1', - 'VmSwap' => 'AREA', - 'VmHWM' => 'LINE2', - 'VmPeak' => 'LINE2' - - }, - 'color' => - { - 'VmSize' => '0066CCBB', - 'VmPeak' => '000000', - 'VmRSS' => '00FF33BB', - 'VmStk' => 'FFCC55BB', - 'VmData' => '00FFFFBB', - 'VmExe' => 'FF1100', - 'VmLib' => 'DD9900', - 'VmLck' => 'AA00AA', - 'VmPTE' => '7E7E7E', - 'VmSwap' => 'FF447788', - 'VmHWM' => 'FFFFFF', - }, - 'order' => [qw(VmSize VmPeak VmRSS VmStk VmData VmSwap VmExe VmLib VmLck VmPTE VmHWM)] -}; - - -# ----------------- main ---------------- -need_multigraph(); - -my @graphs_to_sort = (); -my $stats = {}; -my $storage = {}; -my $applications = {}; -my $enabled_graphs = $ENV{'enabled_graphs'} || '.*'; -$applications->{'show'} = $ENV{'applications'} || undef; # '(psi|chrome|mc|\w{1,3}sh|firefox)'; -$applications->{'group'} = $ENV{'applications_group'} || undef; # '(chrome|firefox):browsers;\w{1,3}sh:sh'; -$applications->{'wait'} = $ENV{'application_wait'} || 1800; - -restore_state_data(); -load_stats(); -save_state_data(); - -if (defined($ARGV[0]) and ($ARGV[0] eq 'autoconf')) -{ - printf("%s\n", -e "/proc/meminfo" ? "yes" : "no (/proc/meminfo not exists)"); - exit (0); -} - -if (defined($ARGV[0]) and ($ARGV[0] eq 'config')) -{ - sort_graphs_fields(); - print_config(); - exit (0); -} - -print_values(); -exit(0); - -# ---------------------------------------- data load --------------------------------- -# ----------------------------------- saving state data using munin -------------------- -sub save_state_data -{ - $storage->{'timestamp'}{'previous'} = time(); - my $d = Data::Dumper->new([$storage]); - $d->Indent(0); - save_state($d->Dump); -} - -# -------------------------------- loading previous state data using munin ------------------- -sub restore_state_data -{ - my $VAR1; - my $states = (restore_state())[0]; - eval $states if defined $states; - $storage = $VAR1; - $storage->{'timestamp'}{'current'} = time(); -} - -# -------------------------- loading memory info --------------------------------- -sub load_meminfo -{ - my $file = "/proc/meminfo"; - my $result = {}; - open (FH, '<', $file) or die "$! $file \n"; - my ($var, $val) = ('',0); - for my $line () - { - chomp $line; - ($var, $val) = split(/:?\s+/, $line); - $val = $val * 1024 unless ($var =~ m/HugePages_.*/); - $result->{$var} = $val; - } - close (FH); - return $result; -} -# -------------------------- loading vmalloc info --------------------------------- -sub load_vmallocinfo -{ - my $file = "/proc/vmallocinfo"; - my $result = {}; - open (FH, '<', $file) or die "$! $file \n"; - my @splitted = (); - my $name = ''; - for my $line () - { - chomp $line; - @splitted = split(/\s+/, $line); - $name = (split(/\+/ , $splitted[2]))[0]; - $result->{$name} = 0 unless (exists($result->{$name})); - $result->{$name} += $splitted[1]; - - my $field_name = sprintf("vi_%s", clean_fieldname($name)); - append_field ($field_name, 'vmallocinfo', $name, $name, $name); - append_field_to_graph($field_name, 'meminfo_virtual.vmalloc_allocates', 'AREASTACK', '-'); - } - push(@graphs_to_sort, 'meminfo_virtual.vmalloc_allocates'); - close (FH); - #print Dumper $result; - - return $result; -} -# -------------------------- loading slab info --------------------------------- -sub load_slabinfo -{ - my $file = "/proc/slabinfo"; - my $result = {}; - open (FH, '<', $file) or die "$! $file \n"; - my $groups = {}; - - my ($temp, $objects, $tunables, $slabdata) = ('','','',''); - # objects - my ($name, $active_objs, $num_objs, $objsize, $objperslab, $pagesperslab) = ('','','','','',''); - # tunables - #my ($limit, $batchcount, $sharedfactor) = ('','',''); - # slabdata - my ($active_slabs, $num_slabs, $sharedavail) = ('','',''); - - my ($min_obj_size, $max_obj_size, $total_active_objects, $total_objects_size, $total_objects) = (1024, 0, 0, 0); - my ($total_slabs, $total_active_slabs, $total_shared_slabs) = (0, 0, 0); - # name : tunables : slabdata - for my $line () - { - next if $line =~ m/^(#\s+|slabinfo)/; - chomp $line; - ($objects, $tunables, $slabdata) = split(/\s+:\s+/, $line ); - ($name, $active_objs, $num_objs, $objsize, $objperslab, $pagesperslab) = split(/\s+/ , $objects ); - #($temp, $limit, $batchcount, $sharedfactor) = split(/\s+/ , $tunables); - ($temp, $active_slabs, $num_slabs, $sharedavail) = split(/\s+/ , $slabdata); - # splitting slabs to groups - if ($name =~ m/((TC|UD|SCT)P|RAW|UNIX|inet|ip6)/i) - { - push(@{$groups->{'network'}}, $name); - } - elsif($name =~ m/[-_]/) - { - my @parts = split(/[-_]/, $name); - push(@{$groups->{$parts[0]}}, $name); - } - else - { - push(@{$groups->{'other'}}, $name); - } - - if($num_objs > 0) - { - $min_obj_size = $objsize if $objsize < $min_obj_size; - $max_obj_size = $objsize if $objsize > $max_obj_size; - $total_objects_size += $objsize * $num_objs; - $total_objects += $num_objs; - $total_active_objects += $active_objs; - } - if($num_slabs > 0) - { - $total_slabs += $num_slabs; - $total_active_slabs += $active_slabs; - $total_shared_slabs += $sharedavail; - } - # foreach slab field append this field to global fields list - my $field_name = sprintf("slab_%s_size", clean_fieldname($name)); - append_field($field_name, 'slabinfo', $field_name, $name, ''); - $result->{$field_name} = $objsize*$num_objs; - } - # second iteration for better splitting slabs to groups - for my $group ( keys %{$groups} ) - { - if ( scalar(@{$groups->{$group}}) == 1 ) - { - my $name = $groups->{$group}[0]; - if ($name =~ m/cache/) { push(@{$groups->{'caches'}}, $name); } - else { push(@{$groups->{'other'}}, $name) ; } - delete($groups->{$group}); - } - } - # appending grsaph of slabs groups to global graphs list - - # groups graphs - for my $group ( sort keys %{$groups} ) - { - my @group_size_formula = (); - # appending group graph to global graphs list - my $graph_name = sprintf("slab.slabs_size_%s", $group); - append_graph($graph_name, '--base 1024', - sprintf("Slabs size [%s]" , $group), - sprintf("Slabs size jf group, named '%s'", $group), - 'bytes', 'groups_size', 'Total'); - # appending fields to graph and calculating formula - for my $group_field ($groups->{$group}[0] =~ m/-\d+(\(.*\))?$/ ? @{$groups->{$group}} : sort @{$groups->{$group}}) - { - my $group_field_name = sprintf("slab_%s_size", clean_fieldname($group_field)); - append_field_to_graph($group_field_name, $graph_name, 'AREASTACK', '-'); - push (@group_size_formula, $group_field_name) - } - # appending `summ of group` field to global fields list - my $summ_field_name = sprintf("slab_size_summ_%s", clean_fieldname($group)); - append_formula_field ($summ_field_name, join(":n + ", @group_size_formula).':n', $group, ''); - append_field_to_graph($summ_field_name, 'slab.slabs_size_all_groups', 'AREASTACK', '-'); - } - #$graphs_source->{'slab.slabs_size_all_groups'}{'fields'} = sort(@{$graphs_source->{'slab.slabs_size_all_groups'}{'fields'}}); - #print Dumper $groups; - $result->{'min_obj_size'} = $min_obj_size; - $result->{'avg_obj_size'} = $total_objects_size / $total_objects; - $result->{'max_obj_size'} = $max_obj_size; - $result->{'total_objects'} = $total_objects; - $result->{'active_objects'} = $total_active_objects; - $result->{'total_slabs'} = $total_slabs; - $result->{'active_slabs'} = $total_active_slabs; - $result->{'shared_slabs'} = $total_shared_slabs; - close (FH); - return $result; -} -# -------------------------- loading buddyinfo --------------------------------- -sub load_buddyinfo -{ - my $file = "/proc/buddyinfo"; - my $result = {}; - open (FH, '<', $file) or die "$! $file \n"; - my ($node, $zone, $info) = ('','',''); - my ($graph_name, $field_name, $summ_field_name, $num) = ('','','',0); - my @splitted_info = (); - for my $line () - { - chomp $line; - ($node, $info) = split(/,\s+zone\s+/, $line); - @splitted_info = split(/\s+/, $info); - $zone = shift (@splitted_info); - $summ_field_name = clean_fieldname(sprintf("summ_%s_%s", $node, $zone)); - append_field ($summ_field_name, 'buddyinfo', $summ_field_name, sprintf("%s, zone %s", $node, $zone), 'Chunks count'); - append_field_to_graph($summ_field_name, 'buddyinfo', 'AREASTACK', '-'); - $result->{$summ_field_name} = 0; - $graph_name = 'buddyinfo.'.clean_fieldname(sprintf("%s_%s", $node, $zone)); - append_graph($graph_name, '--base 1000', - sprintf("%s, zone %s" , $node, $zone), - sprintf("Chunks of %s, zone %s", $node, $zone), - 'chunks', $node, 'Total'); - $num = 0; - - for my $chunk (@splitted_info) - { - $result->{$summ_field_name} += $chunk; - $field_name = clean_fieldname(sprintf("chunk_%s_%s_%s", $node, $zone, $num)); - append_field ($field_name, 'buddyinfo', $field_name, sprintf("Chunks of (2^%2d) * Page size", $num), 'Chunks count'); - append_field_to_graph($field_name, $graph_name, 'AREASTACK', '-'); - $num++; - $result->{$field_name} = $chunk; - } - } - close (FH); - return $result; -} - -# ---------------- applications info ----------- -sub summ_app_usage -{ - my $app_data = $_[0]; - return exists($app_data->{'data'}{'VmData'}) ? $app_data->{'data'}{'VmData'} : 0 + - exists($app_data->{'data'}{'VmRSS'}) ? $app_data->{'data'}{'VmRSS'} : 0 + - exists($app_data->{'data'}{'VmStk'}) ? $app_data->{'data'}{'VmStk'} : 0; -} -sub load_appinfo -{ - my $result = {}; - my $procdir = IO::Dir->new("/proc"); - if(defined $procdir) - { - push(@graphs_to_sort, qw(appinfo appgroupinfo appinfo.processes)); - my $current_time = time(); - my $status_file = ''; - my ($pid, $label, $data, $app_name, $field_name, $summ_field_name, $processes_field_name, $group_summ_field_name, $graph_name, $bytes) = (0,'','','','','','','','',0); - #loading application groups - my $groups = {}; - if(defined($applications->{'group'})) - { - my ($g_name, $g_reg) = ('',''); - for my $gr (split(/;/, $applications->{'group'})) - { - ($g_reg, $g_name) = split(/:/, $gr); - $groups->{$g_name} = $g_reg; - } - } - - # for each /proc/{pid} - while (defined ($pid = $procdir->read)) - { - next unless $pid =~ m/\d+/; # only pids - my $status_file = sprintf("/proc/%s/status", $pid); - my $app_data = {}; - open (FH, '<', $status_file) or next; - # collect application data - for my $line () - { - chomp $line; - ($label, $data) = split(/:\s+/, $line); - $app_data->{'name'} = $data if $label eq 'Name'; - $app_data->{'data'}{$label} = (split(/\s+/, $data))[0] * 1024 if($label =~ m/^Vm.*/); - } - close (FH); - # application data has memory information? - if(exists($app_data->{'data'}{'VmSize'})) - { - - # generate graphs/fields, collect values - # application in list? - if(defined($applications->{'show'}) and $app_data->{'name'} =~ m/$applications->{'show'}/) - { - $storage->{'applications'}{'single'}{$app_data->{'name'}} = $current_time; - append_application($app_data, $result); - } - for my $group (keys %{$groups}) - { - if($app_data->{'name'} =~ m/$groups->{$group}/) - { - $storage->{'applications'}{'groups'}{$group}{$app_data->{'name'}} = $current_time; - append_application_to_group($app_data, $group, $result); - } - } - } - } - # not runned applications detect and show - my $dummy_app_data = {}; - for my $app (keys %{$storage->{'applications'}{'single'}}) - { - next if($storage->{'applications'}{'single'}{$app} == $current_time); - if($current_time - $storage->{'applications'}{'single'}{$app} >= $applications->{'wait'}) - { - delete ($storage->{'applications'}{'single'}{$app}); - next; - } - $dummy_app_data->{'name'} = $app; - append_application($dummy_app_data, $result); - } - for my $group (keys %{$storage->{'applications'}{'groups'}}) - { - for my $app (keys %{$storage->{'applications'}{'groups'}{$group}}) - { - next if($storage->{'applications'}{'groups'}{$group}{$app} == $current_time); - if ($current_time - $storage->{'applications'}{'groups'}{$group}{$app} >= $applications->{'wait'}) - { - delete ($storage->{'applications'}{'groups'}{$group}{$app}); - next; - } - $dummy_app_data->{'name'} = $app; - append_application_to_group($dummy_app_data, $group, $result); - } - } - } - return $result; -} - -sub append_application -{ - my ($app_data, $result) = @_[0..1]; - - # field for summary - my $summ_field_name = clean_fieldname(sprintf("summ_%s", $app_data->{'name'})); - append_field ($summ_field_name, 'appinfo', $summ_field_name, $app_data->{'name'}, $app_data->{'name'}); - append_field_to_graph($summ_field_name, 'appinfo', 'LINE1', '-'); - - # field for processes count - my $processes_field_name = clean_fieldname(sprintf("pr_%s", $app_data->{'name'})); - append_field ($processes_field_name, 'appinfo', $processes_field_name, $app_data->{'name'}, sprintf("%s processes count", $app_data->{'name'})); - append_field_to_graph($processes_field_name, 'appinfo.processes', 'LINE1', '-'); - - # values - $result->{$summ_field_name} = 0 unless (exists($result->{$summ_field_name})); - $result->{$processes_field_name} = 0 unless (exists($result->{$processes_field_name})); - $result->{$processes_field_name} ++ if (exists($app_data->{'data'})); - $result->{$summ_field_name} += summ_app_usage($app_data) if exists($app_data->{'data'}); - $result->{$summ_field_name} = 'NaN' unless (exists($app_data->{'data'})); - - # per-application graphs - my $graph_name = sprintf("appinfo.app_%s", clean_fieldname($app_data->{'name'})); - append_graph($graph_name, '--base 1024', - sprintf("Summary `%s` memory usage" , $app_data->{'name'}), - sprintf("All `%s` processes summ by each parameter", $app_data->{'name'}), - 'bytes', 'summary'); - - for my $label (@{$application_fields->{'order'}}) - { - my $field_name = clean_fieldname(sprintf("app_%s_%s", $app_data->{'name'}, $label)); - append_field ($field_name, 'appinfo', $field_name, $application_fields->{'label'}{$label}, $application_fields->{'info'}{$label}); - append_field_to_graph($field_name, $graph_name, $application_fields->{'draw'}{$label}, $application_fields->{'color'}{$label}); - - $result->{$field_name} = 0 unless (exists($result->{$field_name})); - $result->{$field_name} += $app_data->{'data'}{$label} if (exists($app_data->{'data'}{$label})); - $result->{$field_name} = 'NaN' unless (exists($app_data->{'data'}{$label})); - } - #return $graph_name; -} - -sub append_application_to_group -{ - my ($app_data, $group, $result) = @_[0..2]; - my $group_summ_field_name = clean_fieldname(sprintf("group_summ_%s", $group)); - append_field ($group_summ_field_name, 'appinfo', $group_summ_field_name, $group, $group); - append_field_to_graph($group_summ_field_name, 'appgroupinfo', 'LINE1', '-'); - - # per process in group - my $graph_name = sprintf("appgroupinfo.group_%s_applications", clean_fieldname($group)); - append_graph($graph_name, '--base 1024', - sprintf("Group `%s` applications memory usage", $group), - sprintf("All group `%s` applications summ" , $group), - 'bytes', 'applications', 'Total'); - push(@graphs_to_sort, $graph_name); - - my $summ_field_name = clean_fieldname(sprintf("group_%s_proc_%s", $group, $app_data->{'name'})); - append_field ($summ_field_name, 'appinfo', $summ_field_name, $app_data->{'name'}, $app_data->{'name'}); - append_field_to_graph($summ_field_name, $graph_name, 'AREASTACK', '-'); - - $result->{$summ_field_name} = 0 unless (exists($result->{$summ_field_name})); - $result->{$summ_field_name} += summ_app_usage($app_data) if exists($app_data->{'data'}); - $result->{$summ_field_name} = 'NaN' unless (exists($app_data->{'data'})); - $result->{$group_summ_field_name} = 0 unless (exists($result->{$group_summ_field_name})); - $result->{$group_summ_field_name} += $result->{$summ_field_name} if exists($app_data->{'data'}); - - # per group summary - $graph_name = sprintf("appgroupinfo.group_%s_summ", clean_fieldname($group)); - append_graph($graph_name, '--base 1024', - sprintf("Summary group `%s` memory usage" , $group), - sprintf("All group `%s` processes summ by each parameter", $group), - 'bytes', 'summary'); - - for my $label (@{$application_fields->{'order'}}) - { - my $field_name = clean_fieldname(sprintf("group_%s_%s", $group, $label)); - append_field ($field_name, 'appinfo', $field_name, $application_fields->{'label'}{$label}, $application_fields->{'info'}{$label}); - append_field_to_graph($field_name, $graph_name, $application_fields->{'draw'}{$label}, $application_fields->{'color'}{$label}); - - $result->{$field_name} = 0 unless (exists($result->{$field_name})); - $result->{$field_name} += $app_data->{'data'}{$label} if exists($app_data->{'data'}{$label}); - } -} - -# -------------------------- loading pagetype info --------------------------------- -sub load_pagetypeinfo -{ - my $file = "/proc/pagetypeinfo"; - my $result = {}; - my ($temp, $node, $zone, $type) = ('','','',''); - my ($field_name, $graph_name) = ('',''); - my @types = (); - my @values = (); - open (FH, '<', $file) or die "$! $file \n"; - for my $line () - { - chomp $line; - next if($line =~ m/^(Page|Free|\s*)$/); - if ($line =~ m/^Number/) - { - my $num = 0; - for $temp (split(/\s+/, $line)) - { - push(@types, $temp) if ($num>3); - $num++; - } - next; - } - if ($line =~ m/,\s+type/) - { - ($node, $zone, $temp) = split(/,\s+/, $line); - $node = (split(/\s+/, $node))[1]; - $zone = (split(/\s+/, $zone))[1]; - @values = split(/\s+/, $temp); - shift(@values); $type = shift(@values); - $graph_name = 'pagetypeinfo.'.clean_fieldname(sprintf("n%s_z%s_t%s", $node, $zone, $type)); - append_graph($graph_name, '--base 1024', - sprintf("Node %s, zone %s, type %s" , $node, $zone, $type), - sprintf("Free pages count per migrate type (Node %s, zone %s, type %s)", $node, $zone, $type), - 'pages', 'free'); - my $num = 0; - for my $value (@values) - { - $field_name = clean_fieldname(sprintf("fp_n%s_z%s_t%s_o%s", $node, $zone, $type, $num)); - append_field ($field_name, 'pagetypeinfo', $field_name, sprintf("Free pages at order %2s", $num), sprintf("Free pages count per migrate type at order %2s", $num)); - append_field_to_graph($field_name, $graph_name, 'AREASTACK', '-'); - $result->{$field_name} = $value; - $num++; - } - next; - } - if($line =~ m/,\s+zone/) - { - ($node, $temp) = split(/,\s+/, $line); - $node = (split(/\s+/, $node))[1]; - @values = split(/\s+/, $temp); - shift(@values); $zone = shift(@values); - my $num = 0; - for my $value (@values) - { - $field_name = clean_fieldname(sprintf("blocks_n%s_z%s_t%s", $node, $zone, $types[$num])); - append_field ($field_name, 'pagetypeinfo', $field_name, sprintf("Node %2s, zone %9s, type %11s", $node, $zone, $types[$num]), sprintf("Number of blocks type %s", $types[$num])); - append_field_to_graph($field_name, 'pagetypeinfo', 'AREASTACK', '-'); - $result->{$field_name} = $value; - $num++; - } - } - } - close (FH); - return $result; -} - - -# ----------------------- all stats ------------------ -sub load_stats -{ - $stats->{'meminfo'} = load_meminfo() if (-e "/proc/meminfo" and -r "/proc/meminfo" ); - $stats->{'slabinfo'} = load_slabinfo() if (-e "/proc/slabinfo" and -r "/proc/slabinfo" ); - $stats->{'vmallocinfo'} = load_vmallocinfo() if (-e "/proc/vmallocinfo" and -r "/proc/vmallocinfo" ); - $stats->{'buddyinfo'} = load_buddyinfo() if (-e "/proc/buddyinfo" and -r "/proc/buddyinfo" ); - $stats->{'pagetypeinfo'} = load_pagetypeinfo() if (-e "/proc/pagetypeinfo" and -r "/proc/pagetypeinfo" ); - $stats->{'appinfo'} = load_appinfo() if (defined($applications->{'show'}) or defined($applications->{'group'})); - #print Dumper $stats; -} -# appending graphs and fields -sub append_field -{ - my ($field_name, $target, $name, $label, $info) = @_[0..4]; - unless (exists($fields_source->{$field_name})) - { - $fields_source->{$field_name} = - { - 'src' => { 'target' => $target, 'field' => $name }, - 'munin' => { 'label' => $label, 'info' => $info } - }; - } -} - -sub append_formula_field -{ - my ($field_name, $formula, $label, $info) = @_[0..4]; - unless (exists($fields_source->{$field_name})) - { - $fields_source->{$field_name} = - { - 'src' => { 'calculated' => $formula }, - 'munin' => { 'label' => $label, 'info' => $info } - }; - } -} - -sub append_field_to_graph -{ - my ($field_name, $graph_name, $draw, $color) = @_[0..3]; - my $item = sprintf("%s:%s:%s", $field_name, $draw, $color); - push(@{$graphs_source->{$graph_name}{'fields'}}, $item) unless (grep $_ eq $item, @{$graphs_source->{$graph_name}{'fields'}}); -} - -sub append_graph -{ - my ($graph_name, $args, $title, $info, $vtitle, $category, $total) = @_[0..6]; - unless (exists($graphs_source->{$graph_name})) - { - $graphs_source->{$graph_name} = - { - 'munin' => - { - 'args' => $args, 'title' => $title, - 'info' => $info, 'vtitle' => $vtitle, - 'category' => $category - }, - 'fields' => [] - }; - if (defined($total)) { $graphs_source->{$graph_name}{'munin'}{'total'} = $total; } - } -} - -sub sort_graphs_fields -{ - for my $graph_name (@graphs_to_sort) - { - my @fields = (); - push (@fields, @{$graphs_source->{$graph_name}{'fields'}}); - delete($graphs_source->{$graph_name}{'fields'}); - push (@{$graphs_source->{$graph_name}{'fields'}}, sort(@fields)); - } -} - -# --------- convert num[kMG] values to numbers -------------------------------- -sub convert_postfixed -{ - my $src = $_[0]; - $src =~ s/,/./ig; - my $result = $src; - my ($num, $suff) = $src =~ /([\d\.]+)(\w)/; - if ($suff eq 'k') { $result = $num * 1024; } - elsif($suff eq 'M') { $result = $num * 1024 * 1024; } - elsif($suff eq 'G') { $result = $num * 1024 * 1024 * 1024; } - return $result; -} - -# ---------------- loading limits ------------- -sub load_limits -{ - for my $field_name (keys (%{$fields_source})) - { - my $limit_name = sprintf("limit_%s", $field_name); - my $limit = $ENV{$limit_name} || undef; - if(defined($limit)) - { - my ($crit, $warn) = (undef, undef); - if($limit =~ m/:/) { ($warn, $crit) = split(/:/, $limit); } - else { $crit = $limit; } - $fields_source->{$field_name}{'munin'}{'warning'} = convert_postfixed($warn) if defined($warn); - $fields_source->{$field_name}{'munin'}{'critical'} = convert_postfixed($crit) if defined($crit); - } - } -} - - -# --------------------------------------- both ----------------------------- -# check graph enabled or not -sub graph_is_enabled -{ - return $_[0] =~ m/$enabled_graphs/ig; -} -# extract calculated fields -my $calculated_sources = {}; -sub calculated_sources -{ - my $field_name = $_[0]; - unless(exists($calculated_sources->{$field_name})) - { - my $field = $fields_source->{$field_name}; - $calculated_sources->{$field_name}{'must_count'} = 0; - my ($fld, $must) = ('',''); - for my $val (split(/\s.\s/, $field->{'src'}{'calculated'})) - { - ($fld, $must) = split(/:/, $val); - push(@{$calculated_sources->{$field_name}{'fields'}}, $fld); - $calculated_sources->{$field_name}{$fld} = 0; - if($must eq 'y') - { - $calculated_sources->{$field_name}{$fld} = 1; - $calculated_sources->{$field_name}{'must_count'} ++; - } - } - #print Dumper $calculated_sources->{$field_name}; - } - return $calculated_sources->{$field_name}; -} -# --- graph fields ---- -sub graph_fields -{ - my $graph_name = $_[0]; - my $graph_fields = {}; - my ($field_name, $draw, $colour) = ('','',''); - my $graph = $graphs_source->{$graph_name}; - for my $field (@{$graph->{'fields'}}) - { - ($field_name, $draw, $colour) = split(/:/, $field); - push(@{$graph_fields->{'fields'}}, $field_name); - $graph_fields->{$field_name}{'draw'} = $draw; - $graph_fields->{$field_name}{'colour'} = $colour if $colour ne '-'; - } - return $graph_fields; -} -# ---- exists field or not -------------- -my $fields_exists = {}; -sub field_exists -{ - my $field_name = $_[0]; - unless(exists($fields_exists->{$field_name})) - { - my $field = $fields_source->{$field_name}; - if (exists($field->{'src'}{'target'})) - { - $fields_exists->{$field_name} = exists($stats->{$field->{'src'}{'target'}}{$field->{'src'}{'field'}}); - } - elsif (exists($field->{'src'}{'calculated'})) - { - my $sources = calculated_sources($field_name); - my $must_count = 0; - for my $fld (@{$sources->{'fields'}}) - { - $must_count++ if ($sources->{$fld} && field_exists($fld)); - } - $fields_exists->{$field_name} = ($must_count == $sources->{'must_count'}); - } - } - return $fields_exists->{$field_name}; -} -# ---------------------------------------- config ------------------------------------- -sub print_config -{ - my $gr = {}; - load_limits(); - for my $graph_name (keys(%{$graphs_source})) - { - my $graph = $graphs_source->{$graph_name}; - my $order = ''; - my $graph_fields = graph_fields($graph_name); - for my $field_name (@{$graph_fields->{'fields'}}) - { - my $field = $fields_source->{$field_name}; - if (field_exists($field_name)) - { - for my $option (keys(%{$field->{'munin'}})) - { - $gr->{$graph_name}{'fields'}{$field_name}{$option} = $field->{'munin'}{$option}; - } - $gr->{$graph_name}{'fields'}{$field_name}{'draw'} = $graph_fields->{$field_name}{'draw'}; - $gr->{$graph_name}{'fields'}{$field_name}{'colour'} = $graph_fields->{$field_name}{'colour'} if exists($graph_fields->{$field_name}{'colour'}); - $order .= $field_name.' '; - } - } - if(exists($gr->{$graph_name}{'fields'})) - { - $gr->{$graph_name}{'munin'} = $graph->{'munin'}; - $gr->{$graph_name}{'munin'}{'order'} = $order; - } - } - #print Dumper $gr; - for my $graph (sort keys %{$gr}) - { - next unless (graph_is_enabled($graph)); - printf ("multigraph %s\n", $graph); - for my $option (sort keys %{$gr->{$graph}{'munin'}}) - { - printf ("graph_%s %s\n", $option, $gr->{$graph}{'munin'}{$option}); - } - for my $field (sort keys %{$gr->{$graph}{'fields'}}) - { - for my $type (sort keys %{$gr->{$graph}{'fields'}{$field}}) - { - printf ("%s.%s %s\n", $field, $type, $gr->{$graph}{'fields'}{$field}{$type}); - } - } - print "\n"; - } -} - -# -------------------------------------- values -------------------------------- -my $values = {}; -sub field_value -{ - my $field_name = $_[0]; - unless(exists($values->{$field_name})) - { - my $field = $fields_source->{$field_name}; - if (exists($field->{'src'}{'target'})) - { - $values->{$field_name} = $stats->{$field->{'src'}{'target'}}{$field->{'src'}{'field'}}; - } - elsif (exists($field->{'src'}{'calculated'})) - { - my $sources = calculated_sources($field_name); - my $formula = $field->{'src'}{'calculated'}; - for my $form_field (@{$sources->{'fields'}}) - { - my $val = field_exists($form_field) ? field_value($form_field) : 0; - $formula =~ s/$form_field:./$val/; - } - #print $formula." !!\n"; - my $result = 0; - eval '$result = '.$formula.';'; - $values->{$field_name} = $result; - } - } - return $values->{$field_name}; -} - -sub print_values -{ - my $gr = {}; - for my $graph_name (keys(%{$graphs_source})) - { - my $graph = $graphs_source->{$graph_name}; - my $graph_fields = graph_fields($graph_name); - for my $field_name (@{$graph_fields->{'fields'}}) - { - my $field = $fields_source->{$field_name}; - $gr->{$graph_name}{$field_name} = field_value($field_name) if field_exists($field_name); - } - } - - for my $graph_name (sort (keys %{$gr})) - { - next unless (graph_is_enabled($graph_name)); - printf ("multigraph %s\n", $graph_name); - for my $field_name (sort keys %{$gr->{$graph_name}}) - { - printf("%s.value %s\n", $field_name, $gr->{$graph_name}{$field_name}); - } - print "\n"; - } - -} - diff --git a/plugins/system/systat b/plugins/system/systat deleted file mode 100755 index 3a1c9c72..00000000 --- a/plugins/system/systat +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh -# System statistics for FreeBSD -# Author: Gergely Czuczy -# -#%# family=auto -#%# capabilities=autoconf - -sysctl='/sbin/sysctl' - -case $1 in - config) - cat <&2 - exit 1 -} - -#//////////////////////////////////////////////////////////////////////////// -# Récupère le mot de passe de l'utilisateur $1 contenu dans le fichier XML $2 -# -# @param in $1 Nom de l'utilisateur -# @param in $2 Fichier XML contenant les utilisateurs Tomcat -# @stdout Mot de passe de l'utilisateur -#//////////////////////////////////////////////////////////////////////////// -getPassword(){ - local PASSWORD=$(xmlstarlet sel -t -m "tomcat-users/user[@username='$1']" -v "@password" "$2" 2> /dev/null) - [[ -z $PASSWORD ]] && die "Aucun mot de passe trouvé dans le fichier « $2 » pour le compte « $1 » !" - echo $PASSWORD -} - -#////////////////////////////////////////////////////// -# Récupère la page en XML contenant le statut de la JVM -# -# @param in $1 Login pour accéder à la page de statut -# @param in $2 Mot de passe -# @param in $3..$n URL à tester -#////////////////////////////////////////////////////// -getStatusPage(){ - local USER="$1" - local PASSWORD="$2" - while [[ $# -gt 2 ]]; do - local STATUS=$(wget -O- -q --no-check-certificate --http-user "$USER" --http-password "$PASSWORD" "$3") - [[ -n $STATUS ]] && { - echo $STATUS - return - } - shift - done -} - -#/////////////////////////////////////// -# Affiche la mémoire maximale allouable -# -# @param in $1 Page de statut de la JVM -# @stdout Mémoire maximale allouable -#/////////////////////////////////////// -getMaxMemory(){ - local MAX_MEM=$(xmlstarlet sel -t -m "status/jvm/memory" -v "@max" <<< "$1" 2> /dev/null) - [[ -z $MAX_MEM ]] && die "Impossible de trouver la mémoire maximale allouable !" - echo $MAX_MEM -} - -#/////////////////////////////////////////////////////////////////////////// -# Affiche la configuration du plugin -# -# @param in $1 Mémoire maximale allouable -# @param in $2 Pourcentage à utiliser pour définir les « warnings » [0-100] -# @param in $3 Pourcentage à utiliser pour définir les « criticals » [0-100] -# @stdout Configuration du plugin -#/////////////////////////////////////////////////////////////////////////// -showConfig(){ - local TMP=$(echo -e {max,total,free}.{'type GAUGE','min 0','draw AREA'}"\n") - echo "graph_category Tomcat - graph_title Tomcat JVM - graph_info Mémoire de la JVM Tomcat - graph_vlabel Mémoire - $TMP - max.label max - total.label total - free.label free - total.warning $(($1 * $2 / 100)) - total.critical $(($1 * $3 / 100)) - " | sed -r 's/^\s+//' - exit 0 -} - -#///////////////////////////////////////////////////////////////////////////////////////// -# Affiche les données sur la mémoire utilisée, disponible et maximale de la JVM de tomcat. -# -# @param in $1 Page de statut de la JVM -# @stdout Données sur la mémoire utilisée, disponible et maximale de la JVM de tomcat -#///////////////////////////////////////////////////////////////////////////////////////// -showData(){ - xmlstarlet sel -t -m "status/jvm/memory" \ - -o "max.value " -v "@max" -n \ - -o "total.value " -v "@total" -n \ - -o "free.value " -v "@free" \ - <<< "$1" 2> /dev/null -} - -# Le fichier $TOMCAT_USERS n'est pas lisible => on quitte -[[ ! -r $TOMCAT_USERS ]] && die "Impossible de lire le fichier $TOMCAT_USERS !" - -# On récupère le mot de passe de l'utilisateur $USER -PASSWORD=$(getPassword $USER $TOMCAT_USERS) - -# On récupère la page de statut de la JVM de tomcat -STATUS_PAGE=$(getStatusPage $USER $PASSWORD $URLS) -[[ -z $STATUS_PAGE ]] && die 'Erreur : impossible de récupérer la page de statut de Tomcat !' ; - -# On affiche la configuration du plugin -[[ $1 == 'config' ]] && showConfig $(getMaxMemory "$STATUS_PAGE") $WARNING $CRITICAL - -# On affiche les données du plugin -showData "$STATUS_PAGE" diff --git a/plugins/tomcat/jvm-thread-info b/plugins/tomcat/jvm-thread-info deleted file mode 100755 index 1286e8fd..00000000 --- a/plugins/tomcat/jvm-thread-info +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/bash -e -# -# Plugin munin affichant le nombre de threads occupées, disponibles et maximales de la JVM de tomcat. -# -## Dépendances -# xmlstarlet -# wget -# -## Configuration -# -# Pour pouvoir lire le mot de passe automatiquement, le script doit tourner -# sous l'utilisateur tomcat55. Dans /etc/munin/plugin-conf.d/munin-node, -# ajouter : -# -# [tomcat_*] -# user tomcat55 -# -# Autres options disponibles : -# -# env.status_url : URL vers la page « status » en XML du manager -# env.http_username : Utilisateur HTTP -# env.users_filename : Chemin vers le fichier tomcat-users.xml -# -## - -TOMCAT_USERS=${users_filename:-'/etc/tomcat5.5/tomcat-users.xml'} -USER=${http_username:-'munin'} -URLS=( ${status_url:-'http://localhost/manager/status?XML=true https://localhost/manager/status?XML=true http://localhost/manager/status?XML=true'} ) - -WARNING=80 -CRITICAL=90 - -#///////////////////////////////////////////////////////////////////////////////// -# Affiche un message d'erreur et termine le script en renvoyant le code d'erreur 1 -# -# @param Message à afficher -#///////////////////////////////////////////////////////////////////////////////// -die(){ - echo "$1" >&2 - exit 1 -} - -#//////////////////////////////////////////////////////////////////////////// -# Récupère le mot de passe de l'utilisateur $1 contenu dans le fichier XML $2 -# -# @param in $1 Nom de l'utilisateur -# @param in $2 Fichier XML contenant les utilisateurs Tomcat -# @stdout Mot de passe de l'utilisateur -#//////////////////////////////////////////////////////////////////////////// -getPassword(){ - local PASSWORD=$(xmlstarlet sel -t -m "tomcat-users/user[@username='$1']" -v "@password" "$2" 2> /dev/null) - [[ -z $PASSWORD ]] && die "Aucun mot de passe trouvé dans le fichier « $2 » pour le compte « $1 » !" - echo $PASSWORD -} - -#////////////////////////////////////////////////////// -# Récupère la page en XML contenant le statut de la JVM -# -# @param in $1 Login pour accéder à la page de statut -# @param in $2 Mot de passe -# @param in $3..$n URL à tester -#////////////////////////////////////////////////////// -getStatusPage(){ - local USER="$1" - local PASSWORD="$2" - while [[ $# -gt 2 ]]; do - local STATUS=$(wget -O- -q --no-check-certificate --http-user "$USER" --http-password "$PASSWORD" "$3") - [[ -n $STATUS ]] && { - echo $STATUS - return - } - shift - done -} - -#/////////////////////////////////////// -# Affiche le nombre maximal de threads -# -# @param in $1 Page de statut de la JVM -# @stdout Nombre maximal de threads -#/////////////////////////////////////// -getMaxThreads(){ - local MAX_THREADS=$(xmlstarlet sel -t -m "status/connector/threadInfo" -v "@maxThreads" <<< "$1" 2> /dev/null) - [[ -z $MAX_THREADS ]] && die "Impossible de trouver le nombre maximal de threads !" - echo $MAX_THREADS -} - -#/////////////////////////////////////////////////////////////////////////// -# Affiche la configuration du plugin -# -# @param in $1 Nombre maximal de threads -# @param in $2 Pourcentage à utiliser pour définir les « warnings » [0-100] -# @param in $3 Pourcentage à utiliser pour définir les « criticals » [0-100] -# @stdout Configuration du plugin -#/////////////////////////////////////////////////////////////////////////// -showConfig(){ - local TMP=$(echo -e {maxThreads,currentThreadCount,currentThreadsBusy}.{'type GAUGE','min 0','draw AREA'}"\n") - echo "graph_category Tomcat - graph_title Tomcat Threads - graph_info nombre de threads occupées, disponibles et maximales de la JVM de tomcat - graph_vlabel Threads - $TMP - maxThreads.label maxThreads - currentThreadCount.label currentThreadCount - currentThreadsBusy.label currentThreadsBusy - currentThreadCount.warning $(($1 * $2 / 100)) - currentThreadCount.critical $(($1 * $3 / 100)) - " | sed -r 's/^\s+//' - exit 0 -} - -#//////////////////////////////////////////////////////////////////////////////////////////////////// -# Affiche les données sur le nombre de threads occupées, disponibles et maximales de la JVM de tomcat -# -# @param in $1 Page de statut de la JVM -# @stdout Données sur le nombre de threads occupées, disponibles et maximales de la JVM de tomcat -#//////////////////////////////////////////////////////////////////////////////////////////////////// -showData(){ - xmlstarlet sel -t -m "status/connector/threadInfo" \ - -o "currentThreadCount.value " -v "@currentThreadCount" -n \ - -o "currentThreadsBusy.value " -v "@currentThreadsBusy" -n \ - -o "maxThreads.value " -v "@maxThreads" \ - <<< "$1" #2> /dev/null -} - -# Le fichier $TOMCAT_USERS n'est pas lisible => on quitte -[[ ! -r $TOMCAT_USERS ]] && die "Impossible de lire le fichier $TOMCAT_USERS !" - -# On récupère le mot de passe de l'utilisateur $USER -PASSWORD=$(getPassword $USER $TOMCAT_USERS) - -# On récupère la page de statut de la JVM de tomcat -STATUS_PAGE=$(getStatusPage $USER $PASSWORD $URLS) -[[ -z $STATUS_PAGE ]] && die 'Erreur : impossible de récupérer la page de statut de Tomcat !' ; - -# On affiche la configuration du plugin -[[ $1 == 'config' ]] && showConfig $(getMaxThreads "$STATUS_PAGE") $WARNING $CRITICAL - -# On affiche les données du plugin -showData "$STATUS_PAGE" diff --git a/plugins/tomcat/tomcat b/plugins/tomcat/tomcat deleted file mode 100755 index db63ce69..00000000 --- a/plugins/tomcat/tomcat +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/ruby -# -# Plugin to monitor the Tomcat servers. -# -# Original Author: Rune Nordboe Skillingstad -# Rewrite: laxis 2008.05 -# -# Requirements: -# - Needs access to http://:@localhost:8080/manager/status?XML=true (or modify the -# address for another host). A munin-user in $CATALINA_HOME/conf/tomcat-users.xml -# should be set up for this to work. -# - libxml-ruby -# -# Install: -# - copy script to /etc/munin -# - cd /etc/munin -# - ./tomcat install -# -# Tip: To see if it's already set up correctly, just run this plugin -# with the parameter "autoconf". If you get a "yes", everything should -# work like a charm already. -# -# tomcat-users.xml example: -# -# -# Parameters supported: -# -# config -# autoconf -# install -# -# Configurable variables -# -# host - Destination host -# port - HTTP port numbers -# timeout - Connection timeout -# request - Override default status-url -# user - Manager username -# password - Manager password -# connector - Connector to query, defaults to "http-".$PORT -# -# Sample config: -# [tomcat_*] -# env.host 127.0.0.1 -# env.port 8080 -# env.request /manager/status?XML=true -# env.user munin -# env.password pass -# env.timeout 30 -# env.connector jk-8009 -# -# Magic markers: -#%# family=auto -#%# capabilities=autoconf - - -require 'net/http' -require 'xml/libxml' - -@host = ENV.member?('host') ? ENV['host']: "127.0.0.1" -@port = ENV.member?('port') ? ENV['port']: 8080 -@request = ENV.member?('request') ? ENV['request']: "/manager/status?XML=true" -@user = ENV.member?('user') ? ENV['user']: "munin" -@password = ENV.member?('password') ? ENV['password']: "munin" -@timeout = ENV.member?('timeout') ? ENV['timeout']: 30 -@connector = ENV.member?('connector') ? ENV['connector']: "http-#{@port}"; - -# hash -w = { - "jvmMemory" => { "max" => "U", - "total" => "U", - "used" => "U" }, - "threadInfo" => { "maxThreads" => "U", - "currentThreadCount" => "U", - "currentThreadsBusy" => "U" }, - "requestMaxTime" => { "maxTime" => "U" }, - "requestTime" => { "avgTime" => "U" }, - "requestCount" => { "requestCount" => "U", - "errorCount" => "U" }, - "requestBytes" => { "bytesReceived" => "U", - "bytesSent" => "U" } - } - -# http request -def getstat() - Net::HTTP.start(@host, @port) do |http| - http.open_timeout = @timeout - req = Net::HTTP::Get.new(@request) - req.basic_auth @user, @password - response = http.request(req) - response.value() - return response.body - end rescue begin - return false - end -end - -def autoconf() - begin - if getstat() - puts "yes" - return 0 - end - rescue - puts "no (#{$!})" - return 1 - end -end - -if ARGV[0] == "autoconf" - exit autoconf() -end - -if ARGV[0] == "install" - exit if autoconf() != 0 - Dir["plugins/tomcat*"].each { |f| - print "removing #{f}\n" - File.unlink f - } - w.each { |k, v| - print "installing plugins/tomcat_#{k}\n" - File.symlink "../tomcat", "plugins/tomcat_#{k}" if ! FileTest.symlink? "plugins/tomcat_#{k}" - } - exit -end - -# open stderr -e = IO.new(2, "w") - -mode = $0.gsub /.*\/tomcat_/, "" -if mode =~ /tomcat/ then - e.puts "Invalid mode" - exit 1 -end - -# munin config request -if ARGV[0] == "config" - puts "graph_title tomcat_#{mode}" - puts "graph_args -l 0 --base 1000" - #print "graph_order " - #w[mode].each { |k, v| - #print "#{k} " - #} - #puts - case mode - when "jvmMemory" - puts "graph_category tomcat" - puts "graph_vlabel bytes" - puts "graph_order max total used" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type GAUGE" - puts "#{k}.min 0" - puts "#{k}.draw AREA" - } - when "requestCount" - puts "graph_category tomcat" - puts "graph_order requestCount errorCount" - puts "graph_vlabel Request / sec" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type COUNTER" - puts "#{k}.min 0" - puts "#{k}.draw AREA" if k == "requestCount" - puts "#{k}.draw LINE2" if k != "requestCount" - } - when "requestBytes" - puts "graph_category tomcat" - puts "graph_vlabel bytes in (-) / out (+) per ${graph_period}" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type DERIVE" - puts "#{k}.min 0" - puts "#{k}.graph no" if k == "bytesReceived" - puts "#{k}.negative bytesReceived" if k == "bytesSent" - - } - when "requestMaxTime" - puts "graph_category tomcat" - puts "graph_vlabel sec" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type GAUGE" - puts "#{k}.min 0" - puts "#{k}.draw LINE2" - } - when "requestTime" - puts "graph_category tomcat" - puts "graph_vlabel Average RequestTime (sec) / Request" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type GAUGE" - puts "#{k}.min 0" - puts "#{k}.draw LINE2" - } - when "threadInfo" - puts "graph_category tomcat" - puts "graph_order maxThreads currentThreadCount currentThreadsBusy" - w[mode].each { |k, v| - puts "#{k}.label #{k}" - puts "#{k}.type GAUGE" - puts "#{k}.min 0" - puts "#{k}.draw AREA" - } - end - exit 0 -end - - -# XML parsolasa -begin - parser = XML::Parser.string(getstat()) - doc = parser.parse -end rescue begin - e.puts "Parse error" - exit 1 -end - -# root element kivalasztasa -root = doc.root -if root.name != "status" - e.puts "Invalid XML" - exit 1 -end - -# copy jvm memory datas to hash -node = doc.find('//status/jvm/memory').first -w["jvmMemory"]["used"] = node.property("total").to_i - node.property("free").to_i -w["jvmMemory"]["total"] = node.property("total") -w["jvmMemory"]["max"] = node.property("max") - -# copy connector datas to hash -doc.find('//status/connector').each do |node| -if node.property("name") == @connector - node.each do |child| - if child.name == "threadInfo" - w["threadInfo"]["maxThreads"] = child.property("maxThreads") - w["threadInfo"]["currentThreadCount"] = child.property("currentThreadCount") - w["threadInfo"]["currentThreadsBusy"] = child.property("currentThreadsBusy") - end - if child.name == "requestInfo" - w["requestMaxTime"]["maxTime"] = child.property("maxTime") - w["requestTime"]["avgTime"] = sprintf "%.2f", (child.property("processingTime").to_f / child.property("requestCount").to_f / 1000) - w["requestCount"]["requestCount"] = child.property("requestCount") - w["requestCount"]["errorCount"] = child.property("errorCount") - w["requestBytes"]["bytesReceived"] = child.property("bytesReceived") - w["requestBytes"]["bytesSent"] = child.property("bytesSent") - end - end - end -end - -# print result -w[mode].each do |k, v| - printf "#{k}.value %s\n", v -end - -# XML Output: -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# diff --git a/plugins/tomcat/tomcat_ b/plugins/tomcat/tomcat_ deleted file mode 100644 index 0a8c973a..00000000 --- a/plugins/tomcat/tomcat_ +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/python - -''' -Wildcard plugin to monitor Apache Tomcat connectors and/or JBoss' JVM. - -To use this plugin: -1. Set site, username and password variables before you do anything else. -2. Run plugin with suggest argument to get all the available options. -3. Copy plugin to munin plugins folder and make it executable. -4. Create symbolic links based on output from step 2. Examples: - tomcat_jvm - monitor JVM usage - tomcat_ajp-127.0.0.1-8009 - monitor ajp connector - tomcat_http-127.0.0.1-8080 - monitor http connector -5. Check links by running them. -6. Restart munin-node. -7. Enjoy graphs. - -Munin's muni-node-configure can be used to do steps 2, 3 and 4 for you. - -Example of using munin-node configuration to configure the plugin: - -[tomcat_jvm] - env.site http://127.0.0.1:8080/status?XML=true - env.username admin - env.password admin - env.url_timeout 5 - timeout 10 - -url_timeout - timeout for urllib2 -timeout - plugin timeout - -Plugin must return before timeout value runs out, otherwise bye, bye -graphs. - -Magic markers -#%# capabilities=autoconf suggest -#%# family=auto -''' - -import urllib2 -import base64 -import xml.dom.minidom -import sys, os, re - -# Configure me ... -site = 'http://127.0.0.1:8080/status?XML=true' -url_timeout = 5 -username = 'admin' -password = 'admin' - -# Or do it with the environment variables in munin-node configuration. -if os.environ.has_key('site'): - site = os.environ['site'] - -if os.environ.has_key('url_timeout'): - url_timeout = os.environ['url_timeout'] - -if os.environ.has_key('username'): - username = os.environ['username'] - -if os.environ.has_key('password'): - password = os.environ['password'] - -# Timeout for urlopen. -required_version = (2, 6) -current_version = sys.version_info[:2] - -connector_attrs = ( - 'maxThreads', - 'minSpareThreads', - 'maxSpareThreads', - 'currentThreadCount', - 'currentThreadBusy' -) - -jvm_attrs = ( - 'free', - 'total', - 'max' -) - -ctx = sys.argv[0].rstrip('.py').split('_')[1] - -def site_auth(): - # Prepare base64 encoded string - enc_string = base64.encodestring('%s:%s' % (username, password)) - - # Prepare request and add headers - request = urllib2.Request(url=site, headers={"Authorization": "Basic %s" % enc_string}) - try: - if current_version >= required_version: - return (0, urllib2.urlopen(request, timeout=url_timeout).read()) - else: - import socket - socket.setdefaulttimeout(url_timeout) - return (0, urllib2.urlopen(request).read()) - except: - return (-1, "Failed to access %s" % site) - -def jvm_data(data): - document = data.documentElement - for sub_document in document.childNodes: - if sub_document.nodeName == 'jvm': - node = sub_document.firstChild - for attr in jvm_attrs: - print "%s.value %s" % (attr, int(node.getAttribute(attr))) - -def connector_data(data, connector_name): - document = data.documentElement - for sub_document in document.childNodes: - if sub_document.nodeName == 'connector' and sub_document.getAttribute('name') == connector_name: - node = sub_document.firstChild - for attr in connector_attrs: - try: - print "%s.value %s" % (attr, int(node.getAttribute(attr))) - except: - pass - -def suggest(data): - document = data.documentElement - for sub_document in document.childNodes: - if sub_document.nodeName == 'jvm': - print "jvm" - elif sub_document.nodeName == 'connector': - print sub_document.getAttribute('name') - else: - pass - -def configure(): - print "graph_title Tomcat status - %s" % ctx - print "graph_category tomcat" - if ctx == 'jvm': - print "graph_args --base 1024 -l 0" - print "graph_scale yes" - print "graph_vlabel JVM in bytes" - print "graph_info This graph shows JVM usage of Tomcat." - for attr in jvm_attrs: - print "%s.label %s" % (attr, attr) - print "%s.type GAUGE" % (attr) - print "%s.min 0" % (attr) - print "%s.draw LINE1" % (attr) - print "%s.info %s %s in bytes" % (attr, ctx, attr) - else: - print "graph_args --base 1000 -l 0" - print "graph_scale no" - print "graph_vlabel Connector threads" - print "graph_info This graph shows connector threads for %s" % ctx - for attr in connector_attrs: - print "%s.label %s" % (attr, attr) - print "%s.type GAUGE" % (attr) - print "%s.min 0" % (attr) - print "%s.draw LINE1" % (attr) - print "%s.info %s %s count" % (attr, ctx, attr) - -if __name__ == "__main__": - status, data = site_auth() - if len(sys.argv) == 2 and sys.argv[1] == 'config': - configure() - sys.exit(0) - - elif len(sys.argv) == 2 and sys.argv[1] == 'suggest': - suggest(xml.dom.minidom.parseString(data)) - sys.exit(0) - - elif len(sys.argv) == 2 and sys.argv[1] == 'autoconf': - if status == 0: - print "yes" - else: - print "no (%s)" % data - sys.exit(0) - - else: - if ctx == 'jvm': - if status == -1: - for attr in jvm_attrs: - print "%s.value 0" % (attr) - else: - jvm_data(xml.dom.minidom.parseString(data)) - else: - if status == -1: - for attr in connector_attrs: - print "%s.value 0" % (attr) - else: - connector_data(xml.dom.minidom.parseString(data), ctx) diff --git a/plugins/tomcat/tomcatthreads b/plugins/tomcat/tomcatthreads deleted file mode 100755 index ea2128ad..00000000 --- a/plugins/tomcat/tomcatthreads +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env groovy -/* - * Reports tomcat thread status from the tomcat manager application - * - * Stian B. Lindhom 2010 - */ - -def username = '' -def password = '' -def addr = 'http://localhost:8080/manager/status?XML=true' -def connector = 'http-8080' - -def authString = (username + ":" + password).getBytes().encodeBase64() -def conn = addr.toURL().openConnection() - -def maxthreads -def threadsBusy -def threadCount -conn.setRequestProperty("Authorization", "Basic ${authString}") -if (conn.responseCode == 200) { - def doc = new XmlParser().parseText(conn.content.text) - httpConnector = doc.connector.findAll{ it.'@name'.contains(connector) }[0] - maxthreads = Integer.parseInt(httpConnector.threadInfo.'@maxThreads'.text()) - threadsBusy = Integer.parseInt(httpConnector.threadInfo.'@currentThreadsBusy'.text()) - threadCount = Integer.parseInt(httpConnector.threadInfo.'@currentThreadCount'.text()) -} - -if (args && args[0] == 'config') { - warningThreshold = (Integer) (maxthreads - (maxthreads* 0.2)) - criticalThreshold = (Integer) (maxthreads - (maxthreads * 0.05)) - - println """graph_category Tomcat -graph_title Tomcat threads -graph_info The number of busy threads describes how many HTTP requests are being processed at the moment -graph_vlabel Threads -currentThreadCount.label currentThreadCount -currentThreadsBusy.label currentThreadsBusy -maxThreads.label maxThreads -currentThreadCount.warning ${warningThreshold} -currentThreadCount.critical ${criticalThreshold}""" - return; -} - -println """currentThreadCount.value ${threadCount} -currentThreadsBusy.value ${threadsBusy} -maxThreads.value ${maxthreads}"""