2
\$\begingroup\$

This script uses information from /proc/stat for counting current cpu usage. More precisely, it counts with these lines:

     user      nice    system   idle        iowait  irq softirq steal guest guest_nice
cpu  19955147  137056  4371909  2272109978  319877  0   141535  0     0     0
cpu0 10069218  72491   2275676  1135817742  177751  0   64482   0     0     0
cpu1 9885928   64564   2096232  1136292236  142125  0   77052   0     0     0

All of the numbers reported in this file are aggregates since the system first booted. So we can use them for counting the total CPU utilization and the vaule CPU spent in active time since boot. I use this algorithm:

  cpu_total=$(( user + nice + system + idle + iowait + irq + softirq + steal ))
  cpu_activ=$(( user + nice + system + irq + softirq + steal ))

But this isn't the achieve we are looking for. To get a more real-time utilization, we simply repeat the steps above with some small sleep interval in between. And then we are able to count cpu_inpercent() using this algorithm:

cpu_inpercent= 100 * [(cpu_activ_second_run - cpu_activ_first_run) : (cpu_total_second_run - cpu_total_first_run)]

Related to above information the script has to do collect_data() twice. According to run it saves data into two associative arrays cycle_1 and cycle_2 for the finall counting.

I saw several scripts based on "cpu" line which aggregates the numbers in all of the other "cpuN" lines. But as i know there could be an imbalance issue caused by a single-threaded application. For this reason I added usage checks for all cpu.

Desired output for servers with single CPU:

total_cpu_usage=48% | total_cpu=48%;85%;95%;0;0

(total_cpu=value;warning;critical;min;max)

Desired output for the other servers:

total_cpu_usage=1% | total_cpu=1%;85%;95%;0;0 cpu_0=0%;85%;95%;0;0 cpu_1=0%;85%;95%;0;0

And exit an exit code (count_returned_code())

(0=ok; 1=warning; 2=critical)

The script is here. Any suggestions are welcomed.

#!/usr/bin/env bash

set -o errexit -o pipefail

warning="85"
critical="95"

declare -A cycle_1
declare -A cycle_2

run="1"
count_cpu_stats() {
  read -r user nice system idle iowait irq softirq steal _ _ <<< "${stat_row[@]}"

  cpu_total=$(( user + nice + system + idle + iowait + irq + softirq + steal ))
  cpu_activ=$(( user + nice + system + irq + softirq + steal ))

  eval cycle_${run}["${stat_row[0]}"_total]="$cpu_total"
  eval cycle_${run}["${stat_row[0]}"_activ]="$cpu_activ"
}

collect_data() {
  while read -a stat_row; do
    if [[ ${stat_row[0]:0:3} = cpu ]]; then
      count_cpu_stats
    fi
  done < /proc/stat
}

# Never decrease the value!
returned_code="0"
count_returned_code() {
  code="$(( (cpu_inpercent > warning) + (cpu_inpercent > critical) ))"

  if [[ $code -gt $returned_code ]];then
    returned_code="$code"
  fi
}

count_cpu_total() {
  cpu_inpercent="$(( 100 *                        \
    ( cycle_2[cpu_activ] - cycle_1[cpu_activ] ) / \
    ( cycle_2[cpu_total] - cycle_1[cpu_total] )   \
  ))"

  total_cpu="${cpu_inpercent}"
  count_returned_code
}

collect_data; sleep 1; ((run++))
collect_data

returned_text=""
suffix="%;${warning}%;${critical}%;0;0 "
if [[ ${#cycle_1[*]} -eq ${#cycle_2[*]} ]]; then

  # Divide all collected statitic values by two to get number of read rows.
  # And subtract one which represents the line aggregates the numbers in all of the other "cpuN" lines.
  cpu_count=$(( (${#cycle_1[*]} / 2) - 1 ))

  if [[ $cpu_count -eq 1 ]]; then
    count_cpu_total
  else
    count_cpu_total

    cpu_number=0
    while [[ $cpu_number -ne $cpu_count ]]; do
      cpu_inpercent="$(( 100 *                                                          \
        ( ${cycle_2[cpu${cpu_number}_activ]} - ${cycle_1[cpu${cpu_number}_activ]} ) /   \
        ( ${cycle_2[cpu${cpu_number}_total]} - ${cycle_1[cpu${cpu_number}_total]} )     \
      ))"

      count_returned_code

      returned_text+="cpu_${cpu_number}=${cpu_inpercent}${suffix}"
      cpu_number=$(( cpu_number + 1 ))
    done
  fi
else
  exit 3
fi

echo "total_cpu_usage=${total_cpu}% | total_cpu=${total_cpu}${suffix}${returned_text}"
exit $returned_code

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.