Skip to content
Snippets Groups Projects
check_memory 6.16 KiB
#!/bin/bash
# ======================================================================
#
# Check RAM usage
#
# requirements:
# - bc
#
# DOC: https://access.redhat.com/solutions/406773 
# explains /proc/meminfo
#
# SYNTAX:
# check_memory [-w [int] -c [int] -s [int]]
#   -w  Warning level for RAM usage [%]; default: 75
#   -c  Critical level for RAM usage; default: 90
#   -s  Critical level for SWAP usage; default: 5
#
# ----------------------------------------------------------------------
# 2020-03-16  v1.0  <axel.hahn@iml.unibe.ch>
# 2020-03-25  v1.1  <axel.hahn@iml.unibe.ch>  added slab; fix usage based on MemAvailable
# 2020-04-28  v1.2  <axel.hahn@iml.unibe.ch>  allow small swap usage before critical; update output RAM + Swap usage
# 2020-07-08  v1.3  <axel.hahn@iml.unibe.ch> FIX: set "ph." instead "ps."
# 2020-07-16  v1.4  <axel.hahn@iml.unibe.ch> FIX: add unit MB in the performance data (see #3939)
# 2021-03-24  v1.5  <axel.hahn@iml.unibe.ch> increase Swap critical limit 5 --> 50
# 2022-03-09  v1.6  <axel.hahn@iml.unibe.ch> show most ram intensive processes
# 2022-03-10  v1.7  <axel.hahn@iml.unibe.ch> add cli param -p; update help
# 2023-02-13  v1.8  <axel.hahn@unibe.ch>     shell fixes
# 2023-07-28  v1.9  <axel.hahn@unibe.ch>     update help page
# 2023-09-14  v1.10 <axel.hahn@unibe.ch>     fix sort: write failed: 'standard output': Broken pipe
# ======================================================================


. "$(dirname $0)/inc_pluginfunctions"

self_APPVERSION=1.10

# ----------------------------------------------------------------------
# FUNCTIONS
# ----------------------------------------------------------------------

# get a memory status value
# /proc/meminfo conatains values in kB - it is divided by 1024
# --> return values are MB
function getMemvalue(){
    echo $( grep "^$1:" /proc/meminfo | awk '{ print $2 }' ) / 1024 | bc
}

# show help text
function showHelp(){
    local _self; _self=$(basename $0)
cat <<EOF
$( ph.showImlHelpHeader )

Check memory usage incl. free, used and total memory.
On higher memory usage the process table with top 5 top consumers will 
be shown.

This plugin sends performancedata.

SYNTAX:
$(basename $0) [-w WARN_LIMIT] [-c CRITICAL_LIMIT] [-s SWAP_LIMIT] [-p PROCESS_LIMIT] [-h]

OPTIONS:
    -w VALUE   Warning level for RAM usage [%]; default: 75
    -c VALUE   Critical level for RAM usage; default: 90

    -s VALUE   Critical level for SWAP usage; default: 50
    -p VALUE   show process info with highest memory consumption if 
               usage is > NN %; default: 50

    -h or --help   show this help.

PARAMETERS:

    none

EXAMPLE:
$(basename $0) -w 90 -c 95 -p 70

EOF
}
# ----------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------

case "$1" in
    "--help"|"-h")
        showHelp
        exit 0
        ;;
    *)
esac

# --- check required tools
ph.require bc

# ----------------------------------------------------------------------
# set default / override from command line params
typeset -i iWarnLimit;                  iWarnLimit=$(     ph.getValueWithParam 75 w "$@")
typeset -i iCriticalLimit;              iCriticalLimit=$( ph.getValueWithParam 90 c "$@")
typeset -i iCriticalSwap;               iCriticalSwap=$(  ph.getValueWithParam 50 s "$@")
typeset -i iMinRamUsageToShowProcesses; iMinRamUsageToShowProcesses=$(  ph.getValueWithParam 50 p "$@")

# ----------------------------------------------------------------------
# read values

# --- RAM
typeset -i ramTotal; ramTotal=$(    getMemvalue MemTotal)
typeset -i ramAvail; ramAvail=$(    getMemvalue MemAvailable)
typeset -i ramUsed;  ramUsed=$ramTotal-$ramAvail

typeset -i ramFree;     ramFree=$(     getMemvalue MemFree)
typeset -i ramBuffers;  ramBuffers=$(  getMemvalue Buffers)
typeset -i ramCached;   ramCached=$(   getMemvalue Cached)
typeset -i ramSReclaim; ramSReclaim=$( getMemvalue SReclaimable)

typeset -i ramUsage;    ramUsage=$(echo "($ramUsed) *100 / $ramTotal " | bc)

# --- Swap
typeset -i swapTotal;  swapTotal=$(   getMemvalue SwapTotal)
typeset -i swapFree;   swapFree=$(    getMemvalue SwapFree)
typeset -i swapCached; swapCached=$(  getMemvalue SwapCached)

typeset -i swapUsage=0
if [ $swapTotal -gt 0 ]; then
    swapUsage=$(echo "($swapCached)*100 / $swapTotal " | bc)
fi


# ----------------------------------------------------------------------
# set status
ph.setStatusByLimit $ramUsage $iWarnLimit $iCriticalLimit
# if [ $swapCached -gt 0 ]; then
if [ $swapUsage -ge $iCriticalSwap ]; then
    ph.setStatus "critical"
fi

if [ $swapTotal -gt 0 ]; then
    ph.status "RAM usage $ramUsage % of $ramTotal MB .. SWAP usage $swapCached MB = $swapUsage % of $swapTotal MB total"
else
    ph.status "RAM usage $ramUsage % of $ramTotal MB (machine has no Swap)"
fi

# ----------------------------------------------------------------------
# output

# --- show details
echo
grep -E     "^(Mem|Cache|Buffers|Swap|Slab|SReclaimable)" "/proc/meminfo"


# v1.6: show most consuming processes if usage is > nn %
if [ $ramUsage -gt $iMinRamUsageToShowProcesses ]; then
  echo
  echo "RAM usage is higher $iMinRamUsageToShowProcesses percent ... showing most consuming processes:"
  ps aux | head -1
  
  # sort: write failed: 'standard output': Broken pipe
  # ps aux | sort -nrk 4 | head -n 5
  ps aux | sort -nrk 4 | sed -n "1,5p"
fi 

# --- performance data
ph.perfadd "memory-total"    "${ramTotal}MB"    "" "" 0 ${ramTotal}
ph.perfadd "memory-used"     "${ramUsed}MB"     "" "" 0 ${ramTotal}
ph.perfadd "memory-avail"    "${ramAvail}MB"    "" "" 0 ${ramTotal}

ph.perfadd "memory-free"     "${ramFree}MB"     "" "" 0 ${ramTotal}
ph.perfadd "memory-buffers"  "${ramBuffers}MB"  "" "" 0 ${ramTotal}
ph.perfadd "memory-cached"   "${ramCached}MB"   "" "" 0 ${ramTotal}
ph.perfadd "memory-sreclaim" "${ramSReclaim}MB" "" "" 0 ${ramTotal}

# add swap performance data only if swap is available
if [ $swapTotal -gt 0 ]; then
    ph.perfadd "swap-total"      "${swapTotal}MB"   "" "" 0 ${swapTotal}
    ph.perfadd "swap-free"       "${swapFree}MB"    "" "" 0 ${swapTotal}
    ph.perfadd "swap-cached"     "${swapCached}MB"  "" "" 0 ${swapTotal}
fi

ph.exit

# ----------------------------------------------------------------------