bin/check-cpu.rb
#! /usr/bin/env ruby
#
# check-cpu
#
# DESCRIPTION:
# Check cpu usage
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
#
# USAGE:
# #YELLOW
#
# NOTES:
#
# LICENSE:
# Copyright 2014 Sonian, Inc. and contributors. <support@sensuapp.org>
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'sensu-plugin/check/cli'
require 'json'
#
# Check CPU
#
class CheckCPU < Sensu::Plugin::Check::CLI
CPU_METRICS = %i[user nice system idle iowait irq softirq steal guest guest_nice].freeze
option :less_than,
description: 'Change whether value is less than check',
short: '-l',
long: '--less_than',
default: false,
boolean: true
option :warn,
short: '-w WARN',
proc: proc(&:to_f),
default: 80
option :crit,
short: '-c CRIT',
proc: proc(&:to_f),
default: 100
option :sleep,
long: '--sleep SLEEP',
description: 'This sleep controls the interval between the initial poll for cpu utilization and the next data point, the longer the interval is the more accurate your data will be', # rubocop:disable Layout/LineLength
proc: proc(&:to_f),
default: 5
option :cache_file,
long: '--cache-file CACHEFILE',
default: nil
option :proc_path,
long: '--proc-path /proc',
proc: proc(&:to_s),
default: '/proc'
option :idle_metrics,
long: '--idle-metrics METRICS',
description: 'Treat the specified metrics as idle. Defaults to idle,iowait,steal,guest,guest_nice',
proc: proc { |x| x.split(/,/).map { |y| y.strip.to_sym } },
default: %i[idle iowait steal guest guest_nice]
CPU_METRICS.each do |metric|
option metric,
long: "--#{metric}",
description: "Check cpu #{metric} instead of total cpu usage",
boolean: true,
default: false
end
def acquire_cpu_stats
File.open("#{config[:proc_path]}/stat", 'r').each_line do |line|
info = line.split(/\s+/)
name = info.shift
return info.map(&:to_f) if name =~ /^cpu$/
end
end
def acquire_stats_with_sleeping(sec)
before = acquire_cpu_stats
sleep sec
after = acquire_cpu_stats
[before, after]
end
def acquire_stats_with_cache_file
before = JSON.parse(File.read(config[:cache_file]))
now = acquire_cpu_stats
[before, now]
end
def write_stats_to_cache_file(data)
File.write(config[:cache_file], data)
end
def acquire_stats(sec)
if config[:cache_file] && File.exist?(config[:cache_file])
(before, now) = acquire_stats_with_cache_file
else
(before, now) = acquire_stats_with_sleeping(sec)
end
write_stats_to_cache_file(now) if config[:cache_file]
[before, now]
end
def run
(cpu_stats_before, cpu_stats_now) = acquire_stats(config[:sleep])
# Some kernels don't have 'guest' and 'guest_nice' values
metrics = CPU_METRICS.slice(0, cpu_stats_now.length)
cpu_total_diff = 0.to_f
cpu_stats_diff = []
metrics.each_index do |i|
cpu_stats_diff[i] = cpu_stats_now[i] - cpu_stats_before[i]
cpu_total_diff += cpu_stats_diff[i]
end
cpu_stats = []
metrics.each_index do |i|
cpu_stats[i] = 100 * (cpu_stats_diff[i] / cpu_total_diff)
end
idle_diff = metrics.each_with_index.map { |metric, i| config[:idle_metrics].include?(metric) ? cpu_stats_diff[i] : 0.0 }.reduce(0.0, :+)
cpu_usage = 100 * (cpu_total_diff - idle_diff) / cpu_total_diff
checked_usage = cpu_usage
self.class.check_name 'CheckCPU TOTAL'
metrics.each do |metric|
if config[metric]
self.class.check_name "CheckCPU #{metric.to_s.upcase}"
checked_usage = cpu_stats[metrics.find_index(metric)]
end
end
msg = "total=#{(cpu_usage * 100).round / 100.0}"
cpu_stats.each_index { |i| msg += " #{metrics[i]}=#{(cpu_stats[i] * 100).round / 100.0}" }
message msg
if config[:less_than]
critical if checked_usage <= config[:crit]
warning if checked_usage <= config[:warn]
else
critical if checked_usage >= config[:crit]
warning if checked_usage >= config[:warn]
end
ok
end
end