Commit 435949eb55fc30edb208025f99b2bc31f1e110b3

Authored by root
0 parents

监控脚本

check-cpu.rb 0 → 100755
  1 +++ a/check-cpu.rb
  1 +#! /usr/bin/env ruby
  2 +#
  3 +# check-cpu
  4 +#
  5 +# DESCRIPTION:
  6 +# Check cpu usage
  7 +#
  8 +# OUTPUT:
  9 +# plain text
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +# #YELLOW
  19 +#
  20 +# NOTES:
  21 +#
  22 +# LICENSE:
  23 +# Copyright 2014 Sonian, Inc. and contributors. <support@sensuapp.org>
  24 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  25 +# for details.
  26 +#
  27 +
  28 +require 'sensu-plugin/check/cli'
  29 +require 'json'
  30 +
  31 +#
  32 +# Check CPU
  33 +#
  34 +class CheckCPU < Sensu::Plugin::Check::CLI
  35 + CPU_METRICS = [:user, :nice, :system, :idle, :iowait, :irq, :softirq, :steal, :guest, :guest_nice].freeze
  36 +
  37 + option :less_than,
  38 + description: 'Change whether value is less than check',
  39 + short: '-l',
  40 + long: '--less_than',
  41 + default: false,
  42 + boolean: true
  43 +
  44 + option :warn,
  45 + short: '-w WARN',
  46 + proc: proc(&:to_f),
  47 + default: 80
  48 +
  49 + option :crit,
  50 + short: '-c CRIT',
  51 + proc: proc(&:to_f),
  52 + default: 100
  53 +
  54 + option :sleep,
  55 + long: '--sleep SLEEP',
  56 + proc: proc(&:to_f),
  57 + default: 1
  58 +
  59 + option :cache_file,
  60 + long: '--cache-file CACHEFILE',
  61 + default: nil
  62 +
  63 + option :proc_path,
  64 + long: '--proc-path /proc',
  65 + proc: proc(&:to_s),
  66 + default: '/proc'
  67 +
  68 + option :idle_metrics,
  69 + long: '--idle-metrics METRICS',
  70 + description: 'Treat the specified metrics as idle. Defaults to idle,iowait,steal,guest,guest_nice',
  71 + proc: proc { |x| x.split(/,/).map { |y| y.strip.to_sym } },
  72 + default: [:idle, :iowait, :steal, :guest, :guest_nice]
  73 +
  74 + CPU_METRICS.each do |metric|
  75 + option metric,
  76 + long: "--#{metric}",
  77 + description: "Check cpu #{metric} instead of total cpu usage",
  78 + boolean: true,
  79 + default: false
  80 + end
  81 +
  82 + def acquire_cpu_stats
  83 + File.open("#{config[:proc_path]}/stat", 'r').each_line do |line|
  84 + info = line.split(/\s+/)
  85 + name = info.shift
  86 + return info.map(&:to_f) if name =~ /^cpu$/
  87 + end
  88 + end
  89 +
  90 + def acquire_stats_with_sleeping(sec)
  91 + before = acquire_cpu_stats
  92 + sleep sec
  93 + after = acquire_cpu_stats
  94 +
  95 + [before, after]
  96 + end
  97 +
  98 + def acquire_stats_with_cache_file
  99 + before = JSON.parse(File.read(config[:cache_file]))
  100 + now = acquire_cpu_stats
  101 +
  102 + [before, now]
  103 + end
  104 +
  105 + def write_stats_to_cache_file(data)
  106 + File.write(config[:cache_file], data)
  107 + end
  108 +
  109 + def acquire_stats(sec)
  110 + if config[:cache_file] && File.exist?(config[:cache_file])
  111 + (before, now) = acquire_stats_with_cache_file
  112 + else
  113 + (before, now) = acquire_stats_with_sleeping(sec)
  114 + end
  115 +
  116 + write_stats_to_cache_file(now) if config[:cache_file]
  117 +
  118 + [before, now]
  119 + end
  120 +
  121 + def run
  122 + (cpu_stats_before, cpu_stats_now) = acquire_stats(config[:sleep])
  123 +
  124 + # Some kernels don't have 'guest' and 'guest_nice' values
  125 + metrics = CPU_METRICS.slice(0, cpu_stats_now.length)
  126 +
  127 + cpu_total_diff = 0.to_f
  128 + cpu_stats_diff = []
  129 + metrics.each_index do |i|
  130 + cpu_stats_diff[i] = cpu_stats_now[i] - cpu_stats_before[i]
  131 + cpu_total_diff += cpu_stats_diff[i]
  132 + end
  133 +
  134 + cpu_stats = []
  135 + metrics.each_index do |i|
  136 + cpu_stats[i] = 100 * (cpu_stats_diff[i] / cpu_total_diff)
  137 + end
  138 +
  139 + idle_diff = metrics.each_with_index.map { |metric, i| config[:idle_metrics].include?(metric) ? cpu_stats_diff[i] : 0.0 }.reduce(0.0, :+)
  140 +
  141 + cpu_usage = 100 * (cpu_total_diff - idle_diff) / cpu_total_diff
  142 + checked_usage = cpu_usage
  143 +
  144 + self.class.check_name 'CheckCPU TOTAL'
  145 + metrics.each do |metric|
  146 + if config[metric]
  147 + self.class.check_name "CheckCPU #{metric.to_s.upcase}"
  148 + checked_usage = cpu_stats[metrics.find_index(metric)]
  149 + end
  150 + end
  151 +
  152 + msg = "total=#{(cpu_usage * 100).round / 100.0}"
  153 + cpu_stats.each_index { |i| msg += " #{metrics[i]}=#{(cpu_stats[i] * 100).round / 100.0}" }
  154 +
  155 + message msg
  156 +
  157 + if config[:less_than]
  158 + critical if checked_usage <= config[:crit]
  159 + warning if checked_usage <= config[:warn]
  160 + else
  161 + critical if checked_usage >= config[:crit]
  162 + warning if checked_usage >= config[:warn]
  163 + end
  164 + ok
  165 + end
  166 +end
check-cpu.sh 0 → 100755
  1 +++ a/check-cpu.sh
  1 +#!/bin/bash
  2 +#
  3 +# Check CPU usage
  4 +#
  5 +# ===
  6 +#
  7 +# Examples:
  8 +#
  9 +# check-cpu.sh -w 85 -c 95
  10 +#
  11 +# Date: 2014-09-12
  12 +# Author: Jun Ichikawa <jun1ka0@gmail.com>
  13 +#
  14 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  15 +# for details.
  16 +
  17 +# get arguments
  18 +while getopts ':w:c:h' OPT; do
  19 + case $OPT in
  20 + w) WARN=$OPTARG;;
  21 + c) CRIT=$OPTARG;;
  22 + h) hlp="yes";;
  23 + *) unknown="yes";;
  24 + esac
  25 +done
  26 +
  27 +PROC_PATH=${PROC_PATH:-'/proc'}
  28 +
  29 +# usage
  30 +HELP="
  31 + usage: $0 [ -w value -c value -p -h ]
  32 +
  33 + -w --> Warning percentage < value
  34 + -c --> Critical percentage < value
  35 + -h --> print this help screen
  36 +"
  37 +
  38 +if [ "$hlp" = "yes" ]; then
  39 + echo "$HELP"
  40 + exit 0
  41 +fi
  42 +
  43 +cpuusage1=(`cat /proc/stat | head -1`)
  44 +if [ ${#cpuusage1} -eq 0 ]; then
  45 + echo "CRITICAL - CPU UNKNOWN"
  46 + exit 2
  47 +fi
  48 +sleep 1
  49 +cpuusage2=(`cat $PROC_PATH/stat | head -1`)
  50 +if [ ${#cpuusage2} -eq 0 ]; then
  51 + echo "CRITICAL - CPU UNKNOWN"
  52 + exit 2
  53 +fi
  54 +
  55 +WARN=${WARN:=90}
  56 +CRIT=${CRIT:=95}
  57 +
  58 +cpu_diff=(0)
  59 +total=0
  60 +usage_diff=0
  61 +for i in `seq 1 9`
  62 +do
  63 + cpu_diff=("${cpu_diff[@]}" `echo "${cpuusage2[$i]}-${cpuusage1[$i]}" | bc`)
  64 + total=`echo "$total+${cpu_diff[$i]}" | bc`
  65 + if [ $i -ne "4" ]; then
  66 + usage_diff=`echo "$usage_diff+${cpu_diff[$i]}" | bc`
  67 + else
  68 + idl=$cpu_diff[$i]
  69 + fi
  70 +done
  71 +cpu_usage=`echo "scale=2; 100*$usage_diff/$total" | bc`
  72 +
  73 +if [ "$(echo "${cpu_usage} > ${CRIT}" | bc)" -eq 1 ]; then
  74 + echo "CPU CRITICAL - ${cpu_usage}% is greater than critical point.[${CRIT}]"
  75 + exit 2
  76 +fi
  77 +
  78 +if [ "$(echo "${cpu_usage} > ${WARN}" | bc)" -eq 1 ]; then
  79 + echo "CPU WARNING - ${cpu_usage}% is greater than warning point.[${WARN}]"
  80 + exit 1
  81 +fi
  82 +
  83 +echo "CPU OK - Usage:${cpu_usage}"
  84 +exit 0
check-disk.sh 0 → 100755
  1 +++ a/check-disk.sh
  1 +#!/bin/bash
  2 +
  3 +while getopts 'w:c:h:' OPT
  4 +do
  5 + case $OPT in
  6 + w) WARN=$OPTARG;;
  7 + c) CRIT=$OPTARG;;
  8 + h) hlp="yes";;
  9 + *) unknown="yes";;
  10 + esac
  11 +done
  12 +
  13 +# usage
  14 +HELP="
  15 + usage: $0 [ -w value -c value -h ]
  16 +
  17 + -w --> Warning percentage < value
  18 + -c --> Critical percentage < value
  19 + -h --> print this help screen
  20 +"
  21 +hlp=${hlp:=no}
  22 +if [ ${hlp} == "yes" ]
  23 +then
  24 + echo ${HELP}
  25 + exit 0
  26 +fi
  27 +
  28 +WARN=${WARN:=90}
  29 +CRIT=${CRIT:=95}
  30 +
  31 +disk_message=$(df -h | awk 'NR>1')
  32 +
  33 +warn_flag=$(echo "$disk_message" | awk -v warn=${WARN} 'int($5)>warn' | wc -l)
  34 +crit_flag=$(echo "$disk_message" | awk -v crit=${CRIT} 'int($5)>crit' | wc -l)
  35 +
  36 +if [ ${crit_flag} -ge 1 ]
  37 +then
  38 + echo "$disk_message" | awk -v crit=${CRIT} 'int($5)>crit{print "CRITICAL: disk "$NF" used "$5}'
  39 + exit 2
  40 +elif [ ${warn_flag} -ge 1 ]
  41 +then
  42 + echo "$disk_message" | awk -v warn=${WARN} 'int($5)>warn{print "WARNING: disk "$NF" used "$5}'
  43 + exit 1
  44 +else
  45 + echo "OK: all disk is ok"
  46 + exit 0
  47 +fi
check-io.sh 0 → 100755
  1 +++ a/check-io.sh
  1 +#!/bin/bash
  2 +
  3 +while getopts 'w:c:h:' OPT
  4 +do
  5 + case $OPT in
  6 + w) WARN=$OPTARG;;
  7 + c) CRIT=$OPTARG;;
  8 + h) hlp="yes";;
  9 + *) unknown="yes";;
  10 + esac
  11 +done
  12 +
  13 +# usage
  14 +HELP="
  15 + usage: $0 [ -w value -c value -h ]
  16 +
  17 + -w --> Warning percentage < value
  18 + -c --> Critical percentage < value
  19 + -h --> print this help screen
  20 +"
  21 +hlp=${hlp:=no}
  22 +if [ ${hlp} == "yes" ]
  23 +then
  24 + echo ${HELP}
  25 +fi
  26 +
  27 +WARN=${WARN:=90}
  28 +CRIT=${CRIT:=95}
  29 +
  30 +io_message=$(iostat -x 1 1 | egrep [0-9] | awk 'NR>2')
  31 +
  32 +warn_flag=$(echo "$io_message" | awk -v warn=${WARN} '$NF>warn' | wc -l)
  33 +crit_flag=$(echo "$io_message" | awk -v crit=${CRIT} '$NF>crit' | wc -l)
  34 +
  35 +if [ ${crit_flag} -ge 1 ]
  36 +then
  37 + echo "$io_message" | awk -v crit=${CRIT} '$NF>crit{print "CRITICAL: disk "$1" io used "$NF"%"}'
  38 + exit 2
  39 +elif [ ${warn_flag} -ge 1 ]
  40 +then
  41 + echo "$io_message" | awk -v warn=${WARN} '$NF>warn{print "WARNING: disk "$1" io used "$NF"%"}'
  42 + exit 1
  43 +else
  44 + echo "OK: all disk io is ok"
  45 + exit 0
  46 +fi
check-load.rb 0 → 100755
  1 +++ a/check-load.rb
  1 +#! /usr/bin/env ruby
  2 +#
  3 +# check-load
  4 +#
  5 +# DESCRIPTION:
  6 +#
  7 +# OUTPUT:
  8 +# plain text
  9 +#
  10 +# PLATFORMS:
  11 +# Linux, BSD, Solaris, etc
  12 +#
  13 +# DEPENDENCIES:
  14 +# gem: sensu-plugin
  15 +#
  16 +# USAGE:
  17 +# ./bin/check-load.rb --help
  18 +# NOTES:
  19 +#
  20 +# LICENSE:
  21 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  22 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  23 +# for details.
  24 +#
  25 +
  26 +require 'sensu-plugin/check/cli'
  27 +require_relative '../lib/sensu-plugins-load-checks/load-average.rb'
  28 +
  29 +class CheckLoad < Sensu::Plugin::Check::CLI
  30 + option :warn,
  31 + short: '-w L1,L5,L15',
  32 + long: '--warn L1,L5,L15',
  33 + description: 'Load WARNING threshold, 1/5/15 min average',
  34 + proc: proc { |a| a.split(',').map(&:to_f) },
  35 + default: [2.75, 2.5, 2.0]
  36 +
  37 + option :crit,
  38 + short: '-c L1,L5,L15',
  39 + long: '--crit L1,L5,L15',
  40 + description: 'Load CRITICAL threshold, 1/5/15 min average',
  41 + proc: proc { |a| a.split(',').map(&:to_f) },
  42 + default: [3.5, 3.25, 3.0]
  43 +
  44 + def run
  45 + data = LoadAverage.new
  46 + unknown 'Could not read load average from /proc or `uptime`' if data.failed?
  47 +
  48 + message "Per core load average (#{data.cpu_count} CPU): #{data.load_avg}"
  49 +
  50 + critical if data.exceed?(config[:crit])
  51 + warning if data.exceed?(config[:warn])
  52 + ok
  53 + end
  54 +end
check-memory-percent.rb 0 → 100755
  1 +++ a/check-memory-percent.rb
  1 +#!/usr/bin/env ruby
  2 +
  3 +bin_dir = File.expand_path(File.dirname(__FILE__))
  4 +shell_script_path = File.join(bin_dir, File.basename($PROGRAM_NAME, '.rb') + '.sh')
  5 +
  6 +exec shell_script_path, *ARGV, unsetenv_others: true
check-memory-percent.sh 0 → 100755
  1 +++ a/check-memory-percent.sh
  1 +#!/usr/bin/env bash
  2 +#
  3 +# Evaluate free system memory from Linux based systems based on percentage
  4 +# This was forked from Sensu Community Plugins
  5 +#
  6 +# Date: 2007-11-12
  7 +# Author: Thomas Borger - ESG
  8 +# Date: 2012-04-02
  9 +# Modified: Norman Harman - norman.harman@mutualmobile.com
  10 +# Date: 2013-9-30
  11 +# Modified: Mario Harvey - Zumetrics
  12 +# Date: 2015-01-10
  13 +# Modified Ollie Armstrong <ollie@armstrong.io>
  14 +# Date: 2016-02-15
  15 +# Modified: J. Brandt Buckley <brandt.buckley@sendgrid.com>
  16 +
  17 +# set lang
  18 +LANG=C
  19 +
  20 +# get arguments
  21 +
  22 +# #RED
  23 +while getopts 'w:c:hp' OPT; do
  24 + case $OPT in
  25 + w) WARN=$OPTARG;;
  26 + c) CRIT=$OPTARG;;
  27 + h) hlp="yes";;
  28 + p) perform="yes";;
  29 + *) unknown="yes";;
  30 + esac
  31 +done
  32 +
  33 +# usage
  34 +HELP="
  35 + usage: $0 [ -w value -c value -p -h ]
  36 +
  37 + -w --> Warning Percentage < value
  38 + -c --> Critical Percentage < value
  39 + -p --> print out performance data
  40 + -h --> print this help screen
  41 +"
  42 +
  43 +if [ "$hlp" = "yes" ]; then
  44 + echo "$HELP"
  45 + exit 0
  46 +fi
  47 +
  48 +WARN=${WARN:=80}
  49 +CRIT=${CRIT:=90}
  50 +
  51 +#Get total memory available on machine
  52 +TotalMem=$(free -m | grep Mem | awk '{ print $2 }')
  53 +#Determine amount of free memory on the machine
  54 +set -o pipefail
  55 +FreeMem=$(free -m | grep buffers/cache | awk '{ print $4 }')
  56 +if [ $? -ne 0 ];
  57 + then
  58 + FreeMem=$(free -m | grep Mem | awk '{ print $7 }')
  59 +fi
  60 +#Get percentage of free memory
  61 +FreePer=$(awk -v total="$TotalMem" -v free="$FreeMem" 'BEGIN { printf("%-10f\n", (free / total) * 100) }' | cut -d. -f1)
  62 +#Get actual memory usage percentage by subtracting free memory percentage from 100
  63 +UsedPer=$((100-$FreePer))
  64 +
  65 +
  66 +if [ "$UsedPer" = "" ]; then
  67 + echo "MEM UNKNOWN -"
  68 + exit 3
  69 +fi
  70 +
  71 +if [ "$perform" = "yes" ]; then
  72 + output="system memory usage: $UsedPer% | free memory="$UsedPer"%;$WARN;$CRIT;0"
  73 +else
  74 + output="system memory usage: $UsedPer%"
  75 +fi
  76 +
  77 +if (( $UsedPer >= $CRIT )); then
  78 + echo "MEM CRITICAL - $output"
  79 + exit 2
  80 +elif (( $UsedPer >= $WARN )); then
  81 + echo "MEM WARNING - $output"
  82 + exit 1
  83 +else
  84 + echo "MEM OK - $output"
  85 + exit 0
  86 +fi
check-process.sh 0 → 100755
  1 +++ a/check-process.sh
  1 +#!/bin/bash
  2 +
  3 +while getopts 'n:p:h' OPT
  4 +do
  5 + case $OPT in
  6 + n) name=$OPTARG;;
  7 + p) port=$OPTARG;;
  8 + h) hlp="yes";;
  9 + *) unknown="yes";;
  10 + esac
  11 +done
  12 +
  13 +# usage
  14 +HELP="
  15 + usage: $0 [ -n process name -p process port -h ]
  16 +
  17 + -n --> process name < value
  18 + -p --> process port < value
  19 + -h --> print this help screen
  20 +"
  21 +hlp=${hlp:=no}
  22 +if [ ${hlp} == "yes" ] || [ "${name}" == "" ]
  23 +then
  24 + echo "${HELP}"
  25 + exit 0
  26 +fi
  27 +
  28 +function getpid(){
  29 + pid=$(sudo ps -ef | grep "${name}" | grep -v grep | grep -v $0 | awk 'NR==1{print $2}' )
  30 +}
  31 +
  32 +if [ "${name}" == "" ]
  33 +then
  34 + exit 0
  35 +else
  36 + process_flag=$(sudo ps -ef | grep ${name} | grep -v grep | grep -v $0 | wc -l)
  37 +fi
  38 +
  39 +if [ "${port}" == "" ]
  40 +then
  41 + port_flag=1
  42 +else
  43 + port_flag=$(sudo netstat -lntp | grep ":${port} " | wc -l)
  44 +fi
  45 +
  46 +if [ ${process_flag} -ge 1 ] && [ ${port_flag} -ge 1 ]
  47 +then
  48 + echo "Ok: ${name} is ok,port is ${port}."
  49 + exit 0
  50 +else
  51 + echo "ERROR: ${name} is error,port is ${port}."
  52 + exit 2
  53 +fi
metrics-cpu-pcnt-usage.rb 0 → 100755
  1 +++ a/metrics-cpu-pcnt-usage.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +#
  4 +# cpu-pct-usage-metrics
  5 +#
  6 +# DESCRIPTION:
  7 +#
  8 +# OUTPUT:
  9 +# metric data
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +#
  19 +# NOTES:
  20 +#
  21 +# LICENSE:
  22 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  23 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  24 +# for details.
  25 +#
  26 +require 'sensu-plugin/metric/cli'
  27 +require 'socket'
  28 +
  29 +#
  30 +# CPU Graphite
  31 +#
  32 +class CpuGraphite < Sensu::Plugin::Metric::CLI::Graphite
  33 + option :scheme,
  34 + description: 'Metric naming scheme, text to prepend to metric',
  35 + short: '-s SCHEME',
  36 + long: '--scheme SCHEME',
  37 + default: "#{Socket.gethostname}.cpu"
  38 +
  39 + option :proc_path,
  40 + long: '--proc-path /proc',
  41 + proc: proc(&:to_s),
  42 + default: '/proc'
  43 +
  44 + def acquire_proc_stats
  45 + cpu_metrics = %w(user nice system idle iowait irq softirq steal guest)
  46 + File.open("#{config[:proc_path]}/stat", 'r').each_line do |line|
  47 + info = line.split(/\s+/)
  48 + next if info.empty?
  49 + name = info.shift
  50 +
  51 + # we are matching TOTAL stats and returning a hash of values
  52 + if name =~ /^cpu$/
  53 + # return the CPU metrics sample as a hash
  54 + # filter out nil values, as some kernels don't have a 'guest' value
  55 + return Hash[cpu_metrics.zip(info.map(&:to_i))].reject { |_key, value| value.nil? }
  56 + end
  57 + end
  58 + end
  59 +
  60 + def sum_cpu_metrics(metrics)
  61 + # #YELLOW
  62 + metrics.values.reduce { |sum, metric| sum + metric } # rubocop:disable SingleLineBlockParams
  63 + end
  64 +
  65 + def run
  66 + cpu_sample1 = acquire_proc_stats
  67 + sleep(1)
  68 + cpu_sample2 = acquire_proc_stats
  69 + cpu_metrics = cpu_sample2.keys
  70 +
  71 + # we will sum all jiffy counts read in acquire_proc_stats
  72 + cpu_total1 = sum_cpu_metrics(cpu_sample1)
  73 + cpu_total2 = sum_cpu_metrics(cpu_sample2)
  74 + # total cpu usage in last second in CPU jiffs (1/100 s)
  75 + cpu_total_diff = cpu_total2 - cpu_total1
  76 + # per CPU metric diff
  77 + cpu_sample_diff = Hash[cpu_sample2.map { |k, v| [k, v - cpu_sample1[k]] }]
  78 +
  79 + cpu_metrics.each do |metric|
  80 + metric_val = sprintf('%.02f', (cpu_sample_diff[metric] / cpu_total_diff.to_f) * 100)
  81 + output "#{config[:scheme]}.#{metric}", metric_val
  82 + end
  83 + ok
  84 + end
  85 +end
metrics-disk-usage.rb 0 → 100755
  1 +++ a/metrics-disk-usage.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +#
  4 +# disk-usage-metrics
  5 +#
  6 +# DESCRIPTION:
  7 +# This plugin uses df to collect disk capacity metrics
  8 +# disk-usage-metrics.rb looks at /proc/stat which doesnt hold capacity metricss.
  9 +#
  10 +# OUTPUT:
  11 +# metric data
  12 +#
  13 +# PLATFORMS:
  14 +# Linux
  15 +#
  16 +# DEPENDENCIES:
  17 +# gem: sensu-plugin
  18 +# gem: socket
  19 +#
  20 +# USAGE:
  21 +#
  22 +# NOTES:
  23 +# Based on disk-capacity-metrics.rb by bhenerey and nstielau
  24 +# The difference here being how the key is defined in graphite and the
  25 +# size we emit to graphite(now using megabytes). Also i dropped inode info.
  26 +# Using this as an example
  27 +# Filesystem Size Used Avail Use% Mounted on
  28 +# /dev/mapper/precise64-root 79G 3.5G 72G 5% /
  29 +# /dev/sda1 228M 25M 192M 12% /boot
  30 +# /dev/sdb1 99G 2G 97G 2% /media/sda1
  31 +# The keys with this plugin will be
  32 +# disk_usage.root, disk_usage.root.boot, and disk_usage.root.media.sda1
  33 +# instead of disk.dev.mapper.precise64-root, disk.sda1, and disk.sda2
  34 +#
  35 +# Use --flatten option to reduce graphite "tree" by using underscores rather
  36 +# then dots for subdirs. Also eliminates 'root' on mounts other than '/'.
  37 +# Keys with --flatten option would be
  38 +# disk_usage.root, disk_usage.boot, and disk_usage.media_sda1
  39 +#
  40 +# Mountpoints can be specifically included or ignored using -i or -I options:
  41 +# e.g. disk-usage-metric.rb -i ^/boot,^/media
  42 +#
  43 +# LICENSE:
  44 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  45 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  46 +# for details.
  47 +#
  48 +
  49 +require 'sensu-plugin/metric/cli'
  50 +require 'socket'
  51 +
  52 +#
  53 +# Disk Usage Metrics
  54 +#
  55 +class DiskUsageMetrics < Sensu::Plugin::Metric::CLI::Graphite
  56 + option :scheme,
  57 + description: 'Metric naming scheme, text to prepend to .$parent.$child',
  58 + long: '--scheme SCHEME',
  59 + default: "#{Socket.gethostname}.disk_usage"
  60 +
  61 + option :ignore_mnt,
  62 + description: 'Ignore mounts matching pattern(s)',
  63 + short: '-i MNT[,MNT]',
  64 + long: '--ignore-mount',
  65 + proc: proc { |a| a.split(',') }
  66 +
  67 + option :include_mnt,
  68 + description: 'Include only mounts matching pattern(s)',
  69 + short: '-I MNT[,MNT]',
  70 + long: '--include-mount',
  71 + proc: proc { |a| a.split(',') }
  72 +
  73 + option :flatten,
  74 + description: 'Output mounts with underscore rather than dot',
  75 + short: '-f',
  76 + long: '--flatten',
  77 + boolean: true,
  78 + default: false
  79 +
  80 + option :local,
  81 + description: 'Only check local filesystems (df -l option)',
  82 + short: '-l',
  83 + long: '--local',
  84 + boolean: true,
  85 + default: false
  86 +
  87 + option :block_size,
  88 + description: 'Set block size for sizes printed',
  89 + short: '-B BLOCK_SIZE',
  90 + long: '--block-size BLOCK_SIZE',
  91 + default: 'M'
  92 +
  93 + # Main function
  94 + #
  95 + def run
  96 + delim = config[:flatten] == true ? '_' : '.'
  97 + # Get disk usage from df with used and avail in megabytes
  98 + # #YELLOW
  99 + `df -PB#{config[:block_size]} #{config[:local] ? '-l' : ''}`.split("\n").drop(1).each do |line|
  100 + _, _, used, avail, used_p, mnt = line.split
  101 +
  102 + unless %r{/sys[/|$]|/dev[/|$]|/run[/|$]} =~ mnt
  103 + next if config[:ignore_mnt] && config[:ignore_mnt].find { |x| mnt.match(x) }
  104 + next if config[:include_mnt] && !config[:include_mnt].find { |x| mnt.match(x) }
  105 + mnt = if config[:flatten]
  106 + mnt.eql?('/') ? 'root' : mnt.gsub(/^\//, '')
  107 + else
  108 + # If mnt is only / replace that with root if its /tmp/foo
  109 + # replace first occurance of / with root.
  110 + mnt.length == 1 ? 'root' : mnt.gsub(/^\//, 'root.')
  111 + end
  112 + # Fix subsequent slashes
  113 + mnt = mnt.gsub '/', delim
  114 + output [config[:scheme], mnt, 'used'].join('.'), used.gsub(config[:block_size], '')
  115 + output [config[:scheme], mnt, 'avail'].join('.'), avail.gsub(config[:block_size], '')
  116 + output [config[:scheme], mnt, 'used_percentage'].join('.'), used_p.delete('%')
  117 + end
  118 + end
  119 + ok
  120 + end
  121 +end
metrics-iostat-extended.rb 0 → 100755
  1 +++ a/metrics-iostat-extended.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +#
  4 +# metrics-iostat-extended
  5 +#
  6 +# DESCRIPTION:
  7 +# This plugin collects iostat data for a specified disk or all disks.
  8 +# Output is in Graphite format. See `man iostat` for detailed
  9 +# explaination of each field.
  10 +#
  11 +# OUTPUT:
  12 +# metric data
  13 +#
  14 +# PLATFORMS:
  15 +# Linux
  16 +#
  17 +# DEPENDENCIES:
  18 +# gem: sensu-plugin
  19 +# gem: socket
  20 +#
  21 +# USAGE:
  22 +# Collect metrics for all disks
  23 +# metrics-iostat-extended.rb
  24 +#
  25 +# Collect metrics for /dev/sda for 3 seconds
  26 +# metrics-iostat-extended.rb -d /dev/sda -i 3
  27 +#
  28 +# NOTES:
  29 +# The iostat command must be installed. On Debian/Redhat systems
  30 +# iostat is part of the sysstat package.
  31 +#
  32 +# LICENSE:
  33 +# Peter Fern <ruby@0xc0dedbad.com>
  34 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  35 +# for details.
  36 +#
  37 +
  38 +require 'sensu-plugin/metric/cli'
  39 +require 'open3'
  40 +require 'socket'
  41 +
  42 +class IOStatExtended < Sensu::Plugin::Metric::CLI::Graphite
  43 + option :scheme,
  44 + description: 'Metric naming scheme, text to prepend to .$parent.$child',
  45 + long: '--scheme SCHEME',
  46 + default: "#{Socket.gethostname}.iostat"
  47 +
  48 + option :disk,
  49 + description: 'Disk to gather stats for',
  50 + short: '-d DISK',
  51 + long: '--disk DISK',
  52 + required: false
  53 +
  54 + option :excludedisk,
  55 + description: 'List of disks to exclude',
  56 + short: '-x DISK[,DISK]',
  57 + long: '--exclude-disk',
  58 + proc: proc { |a| a.split(',') }
  59 +
  60 + option :interval,
  61 + description: 'Period over which statistics are calculated (in seconds)',
  62 + short: '-i SECONDS',
  63 + long: '--interval SECONDS',
  64 + default: 1
  65 +
  66 + option :mappernames,
  67 + description: 'Display the registered device mapper names for any device mapper devices. Useful for viewing LVM2 statistics',
  68 + short: '-N',
  69 + long: '--show-dm-names',
  70 + boolean: true
  71 +
  72 + def parse_results(raw)
  73 + stats = {}
  74 + key = nil
  75 + headers = nil
  76 + stage = :initial
  77 + raw.each_line do |line|
  78 + line.chomp!
  79 + next if line.empty?
  80 +
  81 + case line
  82 + when /^(avg-cpu):/
  83 + stage = :cpu
  84 + key = Regexp.last_match[1]
  85 + headers = line.gsub(/%/, 'pct_').split(/\s+/)
  86 + headers.shift
  87 + next
  88 + when /^(Device):/
  89 + stage = :device
  90 + headers = line.gsub(/%/, 'pct_').split(/\s+/).map { |h| h.gsub(/\//, '_per_') }
  91 + headers.shift
  92 + next
  93 + end
  94 + next if stage == :initial
  95 +
  96 + fields = line.split(/\s+/)
  97 +
  98 + key = fields.shift if stage == :device
  99 + fields.shift if stage == :cpu
  100 + stats[key] = Hash[headers.zip(fields.map(&:to_f))]
  101 + end
  102 + stats
  103 + end
  104 +
  105 + def run
  106 + cmd = 'iostat'
  107 + args = ['-x', config[:interval].to_s, '2']
  108 + args.push('-N') if config[:mappernames]
  109 + args.push(File.basename(config[:disk])) if config[:disk]
  110 +
  111 + exclude_disk = if config[:excludedisk]
  112 + config[:excludedisk].map { |d| File.basename(d) }
  113 + else
  114 + []
  115 + end
  116 +
  117 + stdin, stdout, stderr = Open3.popen3(cmd, *args, unsetenv_others: true)
  118 + stdin.close
  119 + stderr.close
  120 + stats = parse_results(stdout.gets(nil))
  121 + stdout.close
  122 +
  123 + timestamp = Time.now.to_i
  124 +
  125 + stats.each do |disk, metrics|
  126 + next if exclude_disk.include? disk
  127 + metrics.each do |metric, value|
  128 + output [config[:scheme], disk, metric].join('.'), value, timestamp
  129 + end
  130 + end
  131 + ok
  132 + end
  133 +end
metrics-load.rb 0 → 100755
  1 +++ a/metrics-load.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +# <script name>
  4 +#
  5 +# DESCRIPTION:
  6 +# This plugin uses uptime to collect load metrics
  7 +# Basically copied from sensu-community-plugins/plugins/system/vmstat-metrics.rb
  8 +#
  9 +# Load per processor
  10 +# ------------------
  11 +#
  12 +# Optionally, with `--per-core`, this plugin will calculate load per
  13 +# processor from the raw load average by dividing load average by the number
  14 +# of processors.
  15 +#
  16 +# The number of CPUs is determined by reading `/proc/cpuinfo`. This makes the
  17 +# feature Linux specific. Other OSs can be supported by adding OS # detection
  18 +# and a method to determine the number of CPUs.
  19 +#
  20 +# OUTPUT:
  21 +# metric data
  22 +#
  23 +# PLATFORMS:
  24 +# Linux, BSD, Solaris, etc
  25 +#
  26 +# DEPENDENCIES:
  27 +# gem: sensu-plugin
  28 +# gem: socket
  29 +#
  30 +# USAGE:
  31 +#
  32 +# NOTES:
  33 +#
  34 +# LICENSE:
  35 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  36 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  37 +# for details.
  38 +#
  39 +
  40 +require 'sensu-plugin/metric/cli'
  41 +require_relative '../lib/sensu-plugins-load-checks/load-average.rb'
  42 +require 'socket'
  43 +
  44 +class LoadStat < Sensu::Plugin::Metric::CLI::Graphite
  45 + option :scheme,
  46 + description: 'Metric naming scheme, text to prepend to .$parent.$child',
  47 + long: '--scheme SCHEME',
  48 + default: Socket.gethostname.to_s
  49 +
  50 + def run
  51 + data = LoadAverage.new
  52 + unknown 'Could not read load average from /proc or `uptime`' if data.failed?
  53 +
  54 + timestamp = Time.now.to_i
  55 + metrics = {
  56 + load_avg: {
  57 + one: data.load_avg[0].round(2),
  58 + five: data.load_avg[1].round(2),
  59 + fifteen: data.load_avg[2].round(2)
  60 + }
  61 + }
  62 +
  63 + metrics.each do |parent, children|
  64 + children.each do |child, value|
  65 + output [config[:scheme], parent, child].join('.'), value, timestamp
  66 + end
  67 + end
  68 + ok
  69 + end
  70 +end
metrics-memory-percent.rb 0 → 100755
  1 +++ a/metrics-memory-percent.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +#
  4 +# metrics-memory-percent
  5 +#
  6 +# DESCRIPTION:
  7 +#
  8 +# OUTPUT:
  9 +# metric data
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +# ./metrics-memory-percent.rb
  19 +#
  20 +# LICENSE:
  21 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  22 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  23 +# for details.
  24 +#
  25 +
  26 +require 'sensu-plugin/metric/cli'
  27 +require 'socket'
  28 +
  29 +class MemoryGraphite < Sensu::Plugin::Metric::CLI::Graphite
  30 + option :scheme,
  31 + description: 'Metric naming scheme, text to prepend to metric',
  32 + short: '-s SCHEME',
  33 + long: '--scheme SCHEME',
  34 + default: "#{Socket.gethostname}.memory_percent"
  35 +
  36 + def run
  37 + # Based on memory-metrics.rb
  38 +
  39 + # Metrics borrowed from hoardd: https://github.com/coredump/hoardd
  40 +
  41 + mem = metrics_hash
  42 +
  43 + mem.each do |k, v|
  44 + output "#{config[:scheme]}.#{k}", v
  45 + end
  46 +
  47 + ok
  48 + end
  49 +
  50 + def metrics_hash
  51 + mem = {}
  52 + memp = {}
  53 +
  54 + meminfo_output.each_line do |line|
  55 + mem['total'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^MemTotal/
  56 + mem['free'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^MemFree/
  57 + mem['buffers'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Buffers/
  58 + mem['cached'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Cached/
  59 + mem['swapTotal'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^SwapTotal/
  60 + mem['swapFree'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^SwapFree/
  61 + mem['dirty'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Dirty/
  62 + end
  63 +
  64 + mem['swapUsed'] = mem['swapTotal'] - mem['swapFree']
  65 + mem['used'] = mem['total'] - mem['free']
  66 + mem['usedWOBuffersCaches'] = mem['used'] - (mem['buffers'] + mem['cached'])
  67 + mem['freeWOBuffersCaches'] = mem['free'] + (mem['buffers'] + mem['cached'])
  68 +
  69 + # to prevent division by zero
  70 + swptot = if mem['swapTotal'].zero?
  71 + 1
  72 + else
  73 + mem['swapTotal']
  74 + end
  75 +
  76 + mem.each do |k, _v|
  77 + # with percentages, used and free are exactly complementary
  78 + # no need to have both
  79 + # the one to drop here is "used" because "free" will
  80 + # stack up neatly to 100% with all the others (except swapUsed)
  81 + # #YELLOW
  82 + memp[k] = 100.0 * mem[k] / mem['total'] if k != 'total' && k !~ /swap/ && k != 'used'
  83 +
  84 + # with percentages, swapUsed and swapFree are exactly complementary
  85 + # no need to have both
  86 + memp[k] = 100.0 * mem[k] / swptot if k != 'swapTotal' && k =~ /swap/ && k != 'swapFree'
  87 + end
  88 +
  89 + memp
  90 + end
  91 +
  92 + def meminfo_output
  93 + File.open('/proc/meminfo', 'r')
  94 + end
  95 +end
metrics-memory.rb 0 → 100755
  1 +++ a/metrics-memory.rb
  1 +#! /usr/bin/env ruby
  2 +# encoding: UTF-8
  3 +#
  4 +# metrics-memory
  5 +#
  6 +# DESCRIPTION:
  7 +#
  8 +# OUTPUT:
  9 +# metric data
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +# ./metrics-memory.rb
  19 +#
  20 +# LICENSE:
  21 +# Copyright 2012 Sonian, Inc <chefs@sonian.net>
  22 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  23 +# for details.
  24 +#
  25 +
  26 +require 'sensu-plugin/metric/cli'
  27 +require 'socket'
  28 +
  29 +class MemoryGraphite < Sensu::Plugin::Metric::CLI::Graphite
  30 + option :scheme,
  31 + description: 'Metric naming scheme, text to prepend to metric',
  32 + short: '-s SCHEME',
  33 + long: '--scheme SCHEME',
  34 + default: "#{Socket.gethostname}.memory"
  35 +
  36 + def run
  37 + # Metrics borrowed from hoardd: https://github.com/coredump/hoardd
  38 +
  39 + mem = metrics_hash
  40 +
  41 + mem.each do |k, v|
  42 + output "#{config[:scheme]}.#{k}", v
  43 + end
  44 +
  45 + ok
  46 + end
  47 +
  48 + def metrics_hash
  49 + mem = {}
  50 + meminfo_output.each_line do |line|
  51 + mem['total'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^MemTotal/
  52 + mem['free'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^MemFree/
  53 + mem['buffers'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Buffers/
  54 + mem['cached'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Cached/
  55 + mem['swapTotal'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^SwapTotal/
  56 + mem['swapFree'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^SwapFree/
  57 + mem['dirty'] = line.split(/\s+/)[1].to_i * 1024 if line =~ /^Dirty/
  58 + end
  59 +
  60 + mem['swapUsed'] = mem['swapTotal'] - mem['swapFree']
  61 + mem['used'] = mem['total'] - mem['free']
  62 + mem['usedWOBuffersCaches'] = mem['used'] - (mem['buffers'] + mem['cached'])
  63 + mem['freeWOBuffersCaches'] = mem['free'] + (mem['buffers'] + mem['cached'])
  64 + mem['swapUsedPercentage'] = 100 * mem['swapUsed'] / mem['swapTotal'] if mem['swapTotal'] > 0
  65 +
  66 + mem
  67 + end
  68 +
  69 + def meminfo_output
  70 + File.open('/proc/meminfo', 'r')
  71 + end
  72 +end
metrics-netif.rb 0 → 100755
  1 +++ a/metrics-netif.rb
  1 +#! /usr/bin/env ruby
  2 +#
  3 +# netif-metrics
  4 +#
  5 +# DESCRIPTION:
  6 +# Network interface throughput
  7 +#
  8 +# OUTPUT:
  9 +# metric data
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +# #YELLOW
  19 +#
  20 +# NOTES:
  21 +#
  22 +# LICENSE:
  23 +# Copyright 2014 Sonian, Inc. and contributors. <support@sensuapp.org>
  24 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  25 +# for details.
  26 +#
  27 +
  28 +require 'sensu-plugin/metric/cli'
  29 +require 'socket'
  30 +
  31 +#
  32 +# Netif Metrics
  33 +#
  34 +class NetIFMetrics < Sensu::Plugin::Metric::CLI::Graphite
  35 + option :scheme,
  36 + description: 'Metric naming scheme, text to prepend to .$parent.$child',
  37 + long: '--scheme SCHEME',
  38 + default: Socket.gethostname.to_s
  39 +
  40 + option :interval,
  41 + description: 'Interval to collect metrics over',
  42 + long: '--interval INTERVAL',
  43 + default: 1
  44 +
  45 + option :average_key,
  46 + description: 'This key is used to `grep` for a key that corresponds to average. useful for different locales',
  47 + long: '--average-key',
  48 + default: 'Average'
  49 +
  50 + def run
  51 + sar = `/usr/bin/sar -n DEV #{config[:interval]} 1 | grep #{config[:average_key]} | grep -v IFACE`
  52 + if sar.nil? || sar.empty?
  53 + unknown 'sar is not installed or in $PATH'
  54 + end
  55 + sar.each_line do |line|
  56 + stats = line.split(/\s+/)
  57 + unless stats.empty?
  58 + stats.shift
  59 + nic = stats.shift
  60 + output "#{config[:scheme]}.#{nic}.rx_kB_per_sec", stats[2].to_f if stats[3]
  61 + output "#{config[:scheme]}.#{nic}.tx_kB_per_sec", stats[3].to_f if stats[3]
  62 + end
  63 + end
  64 +
  65 + ok
  66 + end
  67 +end
metrics-netstat-tcp.rb 0 → 100755
  1 +++ a/metrics-netstat-tcp.rb
  1 +#! /usr/bin/env ruby
  2 +#
  3 +# metrics-netstat-tcp
  4 +#
  5 +# DESCRIPTION:
  6 +# Fetch metrics on TCP socket states from netstat. This is particularly useful
  7 +# on high-traffic web or proxy servers with large numbers of short-lived TCP
  8 +# connections coming and going.
  9 +#
  10 +# OUTPUT:
  11 +# metric data
  12 +#
  13 +# PLATFORMS:
  14 +# Linux
  15 +#
  16 +# DEPENDENCIES:
  17 +# gem: sensu-plugin
  18 +#
  19 +# USAGE:
  20 +# $ ./metrics-netstat-tcp.rb --scheme servers.hostname
  21 +# servers.hostname.UNKNOWN 0 1350496466
  22 +# servers.hostname.ESTABLISHED 235 1350496466
  23 +# servers.hostname.SYN_SENT 0 1350496466
  24 +# servers.hostname.SYN_RECV 1 1350496466
  25 +# servers.hostname.FIN_WAIT1 0 1350496466
  26 +# servers.hostname.FIN_WAIT2 53 1350496466
  27 +# servers.hostname.TIME_WAIT 10640 1350496466
  28 +# servers.hostname.CLOSE 0 1350496466
  29 +# servers.hostname.CLOSE_WAIT 7 1350496466
  30 +# servers.hostname.LAST_ACK 1 1350496466
  31 +# servers.hostname.LISTEN 16 1350496466
  32 +# servers.hostname.CLOSING 0 1350496466
  33 +#
  34 +# NOTES:
  35 +# - Code for parsing Linux /proc/net/tcp from Anthony Goddard's ruby-netstat:
  36 +# https://github.com/agoddard/ruby-netstat
  37 +#
  38 +# LICENSE:
  39 +# Copyright 2012 Joe Miller <https://github.com/joemiller>
  40 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  41 +# for details.
  42 +#
  43 +
  44 +require 'sensu-plugin/metric/cli'
  45 +require 'socket'
  46 +
  47 +TCP_STATES = {
  48 + '00' => 'UNKNOWN', # Bad state ... Impossible to achieve ...
  49 + 'FF' => 'UNKNOWN', # Bad state ... Impossible to achieve ...
  50 + '01' => 'ESTABLISHED',
  51 + '02' => 'SYN_SENT',
  52 + '03' => 'SYN_RECV',
  53 + '04' => 'FIN_WAIT1',
  54 + '05' => 'FIN_WAIT2',
  55 + '06' => 'TIME_WAIT',
  56 + '07' => 'CLOSE',
  57 + '08' => 'CLOSE_WAIT',
  58 + '09' => 'LAST_ACK',
  59 + '0A' => 'LISTEN',
  60 + '0B' => 'CLOSING'
  61 +}.freeze
  62 +
  63 +#
  64 +# Netstat TCP Metrics
  65 +#
  66 +class NetstatTCPMetrics < Sensu::Plugin::Metric::CLI::Graphite
  67 + option :scheme,
  68 + description: 'Metric naming scheme, text to prepend to metric',
  69 + short: '-s SCHEME',
  70 + long: '--scheme SCHEME',
  71 + default: "#{Socket.gethostname}.tcp"
  72 +
  73 + option :port,
  74 + description: 'Port you wish to get metrics for',
  75 + short: '-p PORT',
  76 + long: '--port PORT',
  77 + proc: proc(&:to_i)
  78 +
  79 + option :disabletcp6,
  80 + description: 'Disable tcp6 check',
  81 + short: '-d',
  82 + long: '--disabletcp6',
  83 + boolean: true
  84 +
  85 + def netstat(protocol, pattern, state_counts)
  86 + File.open('/proc/net/' + protocol).each do |line|
  87 + line.strip!
  88 + if m = line.match(pattern) # rubocop:disable AssignmentInCondition
  89 + connection_state = m[5]
  90 + connection_port = m[2].to_i(16)
  91 + connection_state = TCP_STATES[connection_state]
  92 + if config[:port] && config[:port] == connection_port
  93 + state_counts[connection_state] += 1
  94 + elsif !config[:port]
  95 + state_counts[connection_state] += 1
  96 + end
  97 + end
  98 + end
  99 + state_counts
  100 + end
  101 +
  102 + def run
  103 + timestamp = Time.now.to_i
  104 + state_counts = Hash.new(0)
  105 + TCP_STATES.each_pair { |_hex, name| state_counts[name] = 0 }
  106 +
  107 + tcp4_pattern = /^\s*\d+:\s+(.{8}):(.{4})\s+(.{8}):(.{4})\s+(.{2})/
  108 + state_counts = netstat('tcp', tcp4_pattern, state_counts)
  109 +
  110 + unless config[:disabletcp6]
  111 + tcp6_pattern = /^\s*\d+:\s+(.{32}):(.{4})\s+(.{32}):(.{4})\s+(.{2})/
  112 + state_counts = netstat('tcp6', tcp6_pattern, state_counts)
  113 + end
  114 +
  115 + state_counts.each do |state, count|
  116 + graphite_name = config[:port] ? "#{config[:scheme]}.#{config[:port]}.#{state}" :
  117 + "#{config[:scheme]}.#{state}"
  118 + output graphite_name.to_s, count, timestamp
  119 + end
  120 + ok
  121 + end
  122 +end
metrics-numastat.rb 0 → 100755
  1 +++ a/metrics-numastat.rb
  1 +#!/usr/bin/env ruby
  2 +#
  3 +# metrics-numastat
  4 +#
  5 +# DESCRIPTION:
  6 +# Simple wrapper around `numastat` for getting per-NUMA-node memory stats.
  7 +#
  8 +# OUTPUT:
  9 +# metric data
  10 +#
  11 +# PLATFORMS:
  12 +# Linux
  13 +#
  14 +# DEPENDENCIES:
  15 +# gem: sensu-plugin
  16 +#
  17 +# USAGE:
  18 +#
  19 +# NOTES:
  20 +#
  21 +# LICENSE:
  22 +# Copyright 2016 Mitsutoshi Aoe
  23 +# Released under the same terms as Sensu (the MIT license); see LICENSE
  24 +# for details.
  25 +#
  26 +
  27 +require 'socket'
  28 +require 'sensu-plugin/metric/cli'
  29 +
  30 +class NumastatMetrics < Sensu::Plugin::Metric::CLI::Graphite
  31 + option :scheme,
  32 + description: 'Metric naming scheme, text to prepend to metric',
  33 + short: '-s SCHEME',
  34 + long: '--scheme SCHEME',
  35 + default: "#{Socket.gethostname}.numastat"
  36 +
  37 + def run
  38 + begin
  39 + output = `/usr/bin/numastat`
  40 + rescue Errno::ENOENT => err
  41 + unknown err
  42 + end
  43 +
  44 + nodes = []
  45 + output.each_line do |line|
  46 + nodes = line.split(' ') if nodes.empty?
  47 + next unless /^([^\s]+)\s+(.+)$/ =~ line
  48 + key = Regexp.last_match[1]
  49 + vals = Regexp.last_match[2]
  50 + next if key.nil? || vals.nil?
  51 + nodes.zip(vals.split(' ')).each do |node, val|
  52 + output "#{config[:scheme]}.#{node}.#{key}", val
  53 + end
  54 + end
  55 +
  56 + ok
  57 + end
  58 +end