#!/bin/sh set -e : << =cut =head1 NAME processes - Plugin to monitor processes and process states. =head1 ABOUT This plugin requires munin-server version 1.2.5 or 1.3.3 (or higher). This plugin is backwards compatible with the old processes-plugins found on SunOS, Linux and *BSD (i.e. the history is preserved). All fields have colours associated with them which reflect the type of process (sleeping/idle = blue, running = green, stopped/zombie/dead = red, etc.) =head1 CONFIGURATION No configuration for this plugin. =head1 AUTHOR Copyright (C) 2006 Lars Strand =head1 LICENSE GNU General Public License, version 2 =begin comment This file is part of Munin. 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; version 2 dated June, 1991. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. =end comment =head1 MAGIC MARKERS =begin comment These magic markers are used by munin-node-configure when installing munin-node. =end comment #%# family=auto #%# capabilities=autoconf =cut # Search for program in $PATH unless predefined. awk=${awk:-awk} ps=${ps:-ps} # Find operating system OPERSYS=${OPERSYS:-$(uname | cut -f 1 -d _)} [ -z "$OPERSYS" ] && echo >&2 "Failed to detect environment via uname" && exit 1 if [ "$1" = "autoconf" ]; then case "$OPERSYS" in Linux|SunOS|FreeBSD|OpenBSD|NetBSD|Darwin|CYGWIN) if ! "$ps" >/dev/null 2>/dev/null; then echo "no (ps=$ps failed)" elif ! echo | "$awk" '{ print "Hei" }' >/dev/null 2>/dev/null; then echo "no (awk=$awk failed)" else echo yes fi exit 0 ;; *) echo "no (unknown OS)" exit 0 ;; esac fi . "$MUNIN_LIBDIR/plugins/plugin.sh" # Define colours RUNNABLE='22ff22' # Green SLEEPING='0022ff' # Blue STOPPED='cc0000' # Darker red ZOMBIE='990000' # Darkest red UNINTERRUPTIBLE='ffa500' # Orange IDLE='4169e1' # Royal blue PAGING='00aaaa' # Darker turquoise INTERRUPT='ff00ff' # Fuchsia LOCK='ff3333' # Lighter red RUNNING='00ff7f' # Spring green DEAD='ff0000' # Red SUSPENDED='ff1493' # Deep pink TOTAL='c0c0c0' # Silver # Taken from ps(1) # R - Linux, SunOS, FreeBSD, OpenBSD, NetBSD, OSX, HP-UX (runable) # S - Linux, SunOS, FreeBSD*, OpenBSD*, NetBSD*, OSX*, HP-UX (sleeping) # T - Linux, SunOS, FreeBSD, OpenBSD, NetBSD, OSX, HP-UX (stopped) # Z - Linux, SunOS, FreeBSD, OpenBSD, NetBSD, OSX, HP-UX (zombie/terminated) # D - Linux, FreeBSD, OpenBSD, NetBSD (uninterruptible) # I - FreeBSD, OpenBSD, NetBSD, OSX, HP-UX (idle/intermediate) # W - Linux*, FreeBSD*, HP-UX (paging/interrupt/waiting) # L - FreeBSD (lock) # O - SunOS (running) # X - Linux, HP-UX* (dead) # U - OSX, NetBSD* (uninterruptible/suspended) # 0 - HP-UX (nonexistent) # *) Differ meaning if [ "$1" = "config" ]; then echo "graph_title Processes" echo "graph_info This graph shows the number of processes" echo "graph_category processes" echo "graph_args --base 1000 -l 0" echo "graph_vlabel Number of processes" # OS specific flags if [ "$OPERSYS" = "Linux" ]; then echo "graph_order sleeping idle stopped zombie dead paging uninterruptible runnable processes" echo "dead.label dead" echo "dead.draw STACK" echo "dead.colour $DEAD" echo "dead.info The number of dead processes." print_warning dead print_critical dead echo "paging.label paging" echo "paging.draw STACK" echo "paging.colour $PAGING" echo "paging.info The number of paging processes (<2.6 kernels only)." print_warning paging print_critical paging elif [ "$OPERSYS" = "SunOS" ]; then echo "graph_order sleeping stopped zombie runnable running total" echo "running.label running" echo "running.draw STACK" echo "running.colour $RUNNING" echo "running.info The number of processes that are running on a processor." print_warning running print_critical running # Be backwards compatible. echo "total.label total" echo "total.draw LINE1" echo "total.colour $TOTAL" echo "total.info The total number of processes." print_warning total print_critical total elif [ "$OPERSYS" = "FreeBSD" ]; then echo "graph_order sleeping idle stopped zombie lock uninterruptible interrupt runnable processes" echo "lock.label lock" echo "lock.draw STACK" echo "lock.colour $LOCK" echo "lock.info The number of processes that are waiting to acquire a lock." print_warning lock print_critical lock echo "interrupt.label interrupt" echo "interrupt.draw STACK" echo "interrupt.colour $INTERRUPT" echo "interrupt.info The number of idle interrupt threads." print_warning interrupt print_critical interrupt elif [ "$OPERSYS" = "OpenBSD" ]; then echo "graph_order sleeping idle stopped zombie uninterruptible runnable processes" elif [ "$OPERSYS" = "NetBSD" ]; then echo "graph_order sleeping idle stopped zombie uninterruptible suspended runnable processes" echo "suspended.label suspended" echo "suspended.draw STACK" echo "suspended.colour $SUSPENDED" echo "suspended.info The number of processes that are suspended." print_warning suspended print_critical suspended elif [ "$OPERSYS" = "Darwin" ]; then echo "graph_order sleeping idle stopped zombie uninterruptible running processes" echo "uninterruptible.label uninterruptible" echo "uninterruptible.draw STACK" echo "uninterruptible.colour $UNINTERRUPTIBLE" echo "uninterruptible.info The number of uninterruptible processes (usually IO)." print_warning uninterruptible print_critical uninterruptible elif [ "$OPERSYS" = "HP-UX" ]; then echo "graph_order sleeping intermediate stopped terminated waiting growing nonexistent runnable processes" echo "waiting.label waiting" echo "waiting.draw STACK" echo "waiting.colour $INTERRUPT" echo "waiting.info The number of waiting processes." print_warning waiting print_critical waiting echo "terminated.label terminated" echo "terminated.draw STACK" echo "terminated.colour $ZOMBIE" echo "terminated.info The number of processes that are terminated." print_warning terminated print_critical terminated echo "growing.label growing" echo "growing.draw STACK" echo "growing.colour $RUNNING" echo "growing.info The number of growing processes." print_warning growing print_critical growing echo "intermediate.label intermediate" echo "intermediate.draw STACK" echo "intermediate.colour $IDLE" echo "intermediate.info The number of intermediate processes." print_warning intermediate print_critical intermediate echo "nonexistent.label nonexistent" echo "nonexistent.draw STACK" echo "nonexistent.colour $LOCK" echo "nonexistent.info The number of nonexistent processes." print_warning nonexistent print_critical nonexistent fi # Common flags for some OS if [ "$OPERSYS" = "FreeBSD" ] || [ "$OPERSYS" = "OpenBSD" ] || [ "$OPERSYS" = "NetBSD" ] || [ "$OPERSYS" = "Darwin" ]; then echo "idle.label idle" echo "idle.draw STACK" echo "idle.colour $IDLE" echo "idle.info The number of processes that are idle (sleeping for longer than about 20 seconds)." print_warning idle print_critical idle echo "sleeping.label sleeping" echo "sleeping.draw AREA" echo "sleeping.colour $SLEEPING" echo "sleeping.info The number of processes that are sleeping for less than about 20 seconds." print_warning sleeping print_critical sleeping elif [ "$OPERSYS" = "Linux" ]; then echo "idle.label idle" echo "idle.draw STACK" echo "idle.colour $IDLE" echo "idle.info The number of idle kernel threads (>= 4.2 kernels only)." print_warning idle print_critical idle echo "sleeping.label sleeping" echo "sleeping.draw AREA" echo "sleeping.colour $SLEEPING" echo "sleeping.info The number of sleeping processes." print_warning sleeping print_critical sleeping elif [ "$OPERSYS" = "SunOS" ] || [ "$OPERSYS" = "HP-UX" ]; then echo "sleeping.label sleeping" echo "sleeping.draw AREA" echo "sleeping.colour $SLEEPING" echo "sleeping.info The number of sleeping processes." print_warning sleeping print_critical sleeping fi if [ "$OPERSYS" = "Linux" ] || [ "$OPERSYS" = "FreeBSD" ] || [ "$OPERSYS" = "OpenBSD" ] || [ "$OPERSYS" = "NetBSD" ]; then echo "uninterruptible.label uninterruptible" echo "uninterruptible.draw STACK" echo "uninterruptible.colour $UNINTERRUPTIBLE" echo "uninterruptible.info The number of uninterruptible processes (usually IO)." print_warning uninterruptible print_critical uninterruptible fi # Common (non-cygwin) flags if [ "$OPERSYS" != "CYGWIN" ]; then echo "stopped.label stopped" echo "stopped.draw STACK" echo "stopped.colour $STOPPED" echo "stopped.info The number of stopped or traced processes." print_warning stopped print_critical stopped echo "runnable.label runnable" echo "runnable.draw STACK" echo "runnable.colour $RUNNABLE" echo "runnable.info The number of runnable processes (on the run queue)." print_warning runnable print_critical runnable fi if [ "$OPERSYS" != "CYGWIN" ] && [ "$OPERSYS" != "HP-UX" ]; then echo "zombie.label zombie" echo "zombie.draw STACK" echo "zombie.colour $ZOMBIE" echo "zombie.info The number of defunct ('zombie') processes (process terminated and parent not waiting)." print_warning zombie print_critical zombie fi if [ "$OPERSYS" != "SunOS" ]; then # Not using 'graph_total' due to backwards compatibility. SunOS uses 'total'. #echo 'graph_total total' echo "processes.label total" echo "processes.draw LINE1" echo "processes.colour $TOTAL" echo "processes.info The total number of processes." print_warning processes print_critical processes fi exit 0 fi if [ "$OPERSYS" = "Linux" ]; then # shellcheck disable=SC2016 "$ps" --no-header -eo s | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "uninterruptible.value " 0+stat["D"]; print "runnable.value " 0+stat["R"]; print "sleeping.value " 0+stat["S"]; print "idle.value " 0+stat["I"]; print "stopped.value " 0+stat["T"]; print "paging.value " 0+stat["W"]; print "dead.value " 0+stat["X"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "SunOS" ]; then # shellcheck disable=SC2016 "$ps" -e -o s | "$awk" ' { total++; stat[$1]++ } END { print "total.value " 0+total; print "running.value " 0+stat["O"]; print "sleeping.value " 0+stat["S"]; print "runnable.value " 0+stat["R"]; print "stopped.value " 0+stat["T"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "FreeBSD" ]; then # shellcheck disable=SC2016 "$ps" -axo state= | sed -e 's/^\(.\).*/\1/' | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "uninterruptible.value " 0+stat["D"]; print "idle.value " 0+stat["I"]; print "lock.value " 0+stat["G"]; print "runnable.value " 0+stat["R"]; print "sleeping.value " 0+stat["S"]; print "stopped.value " 0+stat["T"]; print "interrupt.value " 0+stat["W"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "OpenBSD" ]; then # First line is header. Remove it. # shellcheck disable=SC2016 "$ps" -axo state= | sed '1d' | sed -e 's/^\(.\).*/\1/' | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "uninterruptible.value " 0+stat["D"]; print "idle.value " 0+stat["I"]; print "runnable.value " 0+stat["R"]; print "sleeping.value " 0+stat["S"]; print "stopped.value " 0+stat["T"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "NetBSD" ]; then # First line is header. Remove it. # shellcheck disable=SC2016 "$ps" -axo state= | sed '1d' | sed -e 's/^\(.\).*/\1/' | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "uninterruptible.value " 0+stat["D"]; print "idle.value " 0+stat["I"]; print "suspended.value " 0+stat["U"]; print "runnable.value " 0+stat["R"]; print "sleeping.value " 0+stat["S"]; print "stopped.value " 0+stat["T"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "Darwin" ]; then # First line is header. Remove it. # shellcheck disable=SC2016 "$ps" -axo state= | sed '1d' | sed -e 's/^\(.\).*/\1/' | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "uninterruptible.value " 0+stat["U"]; print "idle.value " 0+stat["I"]; print "runnable.value " 0+stat["R"]; print "sleeping.value " 0+stat["S"]; print "stopped.value " 0+stat["T"]; print "zombie.value " 0+stat["Z"]; }' elif [ "$OPERSYS" = "CYGWIN" ]; then # First line is header. Remove it. Also remove WINPID duplicates. # shellcheck disable=SC2016 "$ps" -aW | sed '1d' | cut -c 30-36 | sort -u | "$awk" ' { processes++; } END { print "processes.value " 0+processes; }' elif [ "$OPERSYS" = "HP-UX" ]; then # First line is header. Remove it. # shellcheck disable=SC2016 "$ps" -el | sed '1d' | "$awk" '{print $2}' | "$awk" ' { processes++; stat[$1]++ } END { print "processes.value " 0+processes; print "nonexistent.value " 0+stat["0"]; print "sleeping.value " 0+stat["S"]; print "waiting.value " 0+stat["W"]; print "runnable.value " 0+stat["R"]; print "intermediate.value " 0+stat["I"]; print "terminated.value " 0+stat["Z"]; print "stopped.value " 0+stat["T"]; print "growing.value " 0+stat["X"]; }' fi