Commit 435949eb55fc30edb208025f99b2bc31f1e110b3
0 parents
监控脚本
Showing
17 changed files
with
1382 additions
and
0 deletions
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
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 |