Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from Contegix/metric_process_thread_count
Process/Threads count metrics and check
- Loading branch information
Showing
7 changed files
with
414 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#! /usr/bin/env ruby | ||
# | ||
# check-threads-count.rb | ||
# | ||
# DESCRIPTION: | ||
# Counts the number of threads running on the system and alerts if that number is greater than the warning or critical values. | ||
# The default warning and critical count thresholds come from the ~32000 thread limit in older Linux kernels. | ||
# | ||
# OUTPUT: | ||
# check | ||
# | ||
# PLATFORMS: | ||
# Linux, Windows | ||
# | ||
# DEPENDENCIES: | ||
# gem: sensu-plugin | ||
# gem: sys-proctable | ||
# | ||
# USAGE: | ||
# The check will return an UNKNOWN if the sys-proctable version is not new enough to support it. | ||
# | ||
# NOTES: | ||
# sys-proctable > 0.9.5 is required for counting threads | ||
# | ||
# LICENSE: | ||
# Copyright (c) 2015 Contegix LLC | ||
# Richard Chatteron richard.chatterton@contegix.com | ||
# Released under the same terms as Sensu (the MIT license); see LICENSE | ||
# for details. | ||
# | ||
|
||
require 'sensu-plugin/check/cli' | ||
require 'sys/proctable' | ||
|
||
# | ||
# Check Threads Count | ||
# | ||
class ThreadsCount < Sensu::Plugin::Check::CLI | ||
option :warn, | ||
description: 'Produce a warning if the total number of threads is greater than this value.', | ||
short: '-w WARN', | ||
default: 30_000, | ||
proc: proc(&:to_i) | ||
|
||
option :crit, | ||
description: 'Produce a critical if the total number of threads is greater than this value.', | ||
short: '-c CRIT', | ||
default: 32_000, | ||
proc: proc(&:to_i) | ||
|
||
PROCTABLE_MSG = 'sys-proctable version newer than 0.9.5 is required for counting threads with -t or --threads' | ||
|
||
# Exit with an unknown if sys-proctable is not high enough to support counting threads. | ||
def check_proctable_version | ||
Gem.loaded_specs['sys-proctable'].version > Gem::Version.create('0.9.5') | ||
end | ||
|
||
# Takes a value to be tested as an integer. If a new Integer instance cannot be created from it, return 1. | ||
# See the comments on get_process_threads() for why 1 is returned. | ||
def test_int(i) | ||
return Integer(i) rescue return 1 | ||
end | ||
|
||
# Takes a process struct from Sys::ProcTable.ps() as an argument | ||
# Attempts to use the Linux thread count field :nlwp first, then tries the Windows field :thread_count. | ||
# Returns the number of processes in those fields. | ||
# Otherwise, returns 1 as all processes are assumed to have at least one thread. | ||
def get_process_threads(p) | ||
if p.respond_to?(:nlwp) | ||
return test_int(p.nlwp) | ||
elsif p.respond_to?(:thread_count) | ||
return test_int(p.thread_count) | ||
else | ||
return 1 | ||
end | ||
end | ||
|
||
def count_threads | ||
ps_table = Sys::ProcTable.ps | ||
ps_table.reduce(0) do |sum, p| | ||
sum + get_process_threads(p) | ||
end | ||
end | ||
|
||
# Main function | ||
def run | ||
if !check_proctable_version | ||
unknown PROCTABLE_MSG unless check_proctable_version | ||
else | ||
threads = count_threads | ||
critical "#{threads} threads running, over threshold #{config[:crit]}" if threads > config[:crit] | ||
warning "#{threads} threads running, over threshold #{config[:warn]}" if threads > config[:warn] | ||
ok "#{threads} threads running" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#! /usr/bin/env ruby | ||
# | ||
# metric-processes-threads-count.rb | ||
# | ||
# DESCRIPTION: | ||
# Counts the number of processes running on the system (and optionally, the number of running threads) and outputs it in metric format. | ||
# Can alternatively count the number of processes/threads matching a certain substring. | ||
# | ||
# OUTPUT: | ||
# metric data | ||
# | ||
# PLATFORMS: | ||
# Linux, Windows | ||
# | ||
# DEPENDENCIES: | ||
# gem: sensu-plugin | ||
# gem: sys-proctable | ||
# | ||
# USAGE: | ||
# Pass [-t|--threads] to count the number of running threads in addition to processes. | ||
# The check will return an UNKNOWN if the sys-proctable version is not new enough to support counting threads. | ||
# | ||
# NOTES: | ||
# sys-proctable > 0.9.5 is required for counting threads (-t, --threads) | ||
# | ||
# LICENSE: | ||
# Copyright (c) 2015 Contegix LLC | ||
# Richard Chatteron richard.chatterton@contegix.com | ||
# Released under the same terms as Sensu (the MIT license); see LICENSE | ||
# for details. | ||
# | ||
|
||
require 'sensu-plugin/metric/cli' | ||
require 'sys/proctable' | ||
|
||
# | ||
# Processes and Threads Count Metrics | ||
# | ||
class ProcessesThreadsCount < Sensu::Plugin::Metric::CLI::Graphite | ||
option :scheme, | ||
description: 'Scheme for metric output', | ||
short: '-s SCHEME', | ||
long: '--scheme SCHEME', | ||
default: 'system' | ||
|
||
option :threads, | ||
description: 'If specified, count the number of threads running on the system in addition to processes. Note: Requires sys-proctables > 0.9.5', | ||
short: '-t', | ||
long: '--threads', | ||
boolean: true, | ||
default: false | ||
|
||
PROCTABLE_MSG = 'sys-proctable version newer than 0.9.5 is required for counting threads with -t or --threads' | ||
|
||
# Exit with an unknown if sys-proctable is not high enough to support counting threads. | ||
def check_proctable_version | ||
Gem.loaded_specs['sys-proctable'].version > Gem::Version.create('0.9.5') | ||
end | ||
|
||
# Takes a value to be tested as an integer. If a new Integer instance cannot be created from it, return 1. | ||
# See the comments on get_process_threads() for why 1 is returned. | ||
def test_int(i) | ||
return Integer(i) rescue return 1 | ||
end | ||
|
||
# Takes a process struct from Sys::ProcTable.ps() as an argument | ||
# Attempts to use the Linux thread count field :nlwp first, then tries the Windows field :thread_count. | ||
# Returns the number of processes in those fields. | ||
# Otherwise, returns 1 as all processes are assumed to have at least one thread. | ||
def get_process_threads(p) | ||
if p.respond_to?(:nlwp) | ||
return test_int(p.nlwp) | ||
elsif p.respond_to?(:thread_count) | ||
return test_int(p.thread_count) | ||
else | ||
return 1 | ||
end | ||
end | ||
|
||
def count_threads(ps_table) | ||
ps_table.reduce(0) do |sum, p| | ||
sum + get_process_threads(p) | ||
end | ||
end | ||
|
||
# Main function | ||
def run | ||
if config[:threads] | ||
unknown PROCTABLE_MSG unless check_proctable_version | ||
end | ||
ps_table = Sys::ProcTable.ps | ||
processes = ps_table.length | ||
threads = count_threads(ps_table) if config[:threads] | ||
|
||
timestamp = Time.now.to_i | ||
output "#{[config[:scheme], 'process_count'].join('.')} #{processes} #{timestamp}" | ||
if config[:threads] | ||
output "#{[config[:scheme], 'thread_count'].join('.')} #{threads} #{timestamp}" | ||
end | ||
ok | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,4 @@ | |
module SensuPluginsProcessChecks | ||
# Gem version | ||
VERSION = '0.0.1.alpha.3' | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#!/usr/bin/env ruby | ||
# | ||
# check-threads-count_spec | ||
# | ||
# DESCRIPTION: | ||
# Tests for check-threads-count.rb | ||
# | ||
# OUTPUT: | ||
# | ||
# PLATFORMS: | ||
# | ||
# DEPENDENCIES: | ||
# | ||
# USAGE: | ||
# bundle install | ||
# rake spec | ||
# | ||
# NOTES: | ||
# This test suite mocks up a process table to be returned by Sys::ProcTable.ps() | ||
# | ||
# LICENSE: | ||
# Copyright 2015 Contegix, LLC. | ||
# Released under the same terms as Sensu (the MIT license); see LICENSE for details. | ||
# | ||
require_relative './plugin_stub.rb' | ||
require_relative './spec_helper.rb' | ||
require_relative '../bin/check-threads-count.rb' | ||
|
||
RSpec.configure do |c| | ||
c.before { allow($stdout).to receive(:puts) } | ||
c.before { allow($stderr).to receive(:puts) } | ||
end | ||
|
||
describe ThreadsCount, 'count_threads' do | ||
# Here, we mock Sys::ProcTable.ps() to return an array of structs with only the property this class cares about. | ||
# | ||
it 'should be able to count threads from ProcTable structs with :nlwp fields' do | ||
nlwp_entry = Struct.new(:nlwp) | ||
table = [nlwp_entry.new(3), nlwp_entry.new(1), nlwp_entry.new(6)] | ||
allow(Sys::ProcTable).to receive(:ps).and_return(table) | ||
threadscount = ThreadsCount.new | ||
expect(threadscount.count_threads).to eq(10) | ||
end | ||
|
||
it 'should be able to count threads from ProcTable structs with :thread_count fields' do | ||
tc_entry = Struct.new(:thread_count) | ||
table = [tc_entry.new(3), tc_entry.new(1), tc_entry.new(6)] | ||
allow(Sys::ProcTable).to receive(:ps).and_return(table) | ||
threadscount = ThreadsCount.new | ||
expect(threadscount.count_threads).to eq(10) | ||
end | ||
|
||
end | ||
|
||
describe ThreadsCount, 'run' do | ||
|
||
it 'returns unknown if check_proctable_version returns false' do | ||
threadscount = ThreadsCount.new | ||
allow(threadscount).to receive(:count_threads).and_return(0) | ||
allow(threadscount).to receive(:check_proctable_version).and_return(false) | ||
expect(threadscount).to receive(:unknown) | ||
threadscount.run | ||
end | ||
|
||
it 'returns critical if count_threads returns more than the critical threshold' do | ||
threadscount = ThreadsCount.new | ||
threadscount.config[:warn] = 10 | ||
threadscount.config[:crit] = 15 | ||
allow(threadscount).to receive(:count_threads).and_return(20) | ||
expect(threadscount).to receive(:critical) | ||
expect(-> { threadscount.run }).to raise_error SystemExit | ||
end | ||
|
||
it 'returns warning if count_threads returns more than the warning threshold' do | ||
threadscount = ThreadsCount.new | ||
threadscount.config[:warn] = 10 | ||
threadscount.config[:crit] = 30 | ||
allow(threadscount).to receive(:count_threads).and_return(20) | ||
expect(threadscount).to receive(:warning) | ||
expect(-> { threadscount.run }).to raise_error SystemExit | ||
end | ||
|
||
it 'returns ok if count_threads returns less than the critical or warning thresholds' do | ||
threadscount = ThreadsCount.new | ||
threadscount.config[:warn] = 10 | ||
threadscount.config[:crit] = 20 | ||
allow(threadscount).to receive(:count_threads).and_return(5) | ||
expect(threadscount).to receive(:ok) | ||
threadscount.run | ||
end | ||
|
||
end |
Oops, something went wrong.