Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
sensu-plugins-process-checks/bin/metrics-process-status.rb
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
executable file
143 lines (124 sloc)
3.56 KB
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
#! /usr/bin/env ruby | |
# | |
# proc-status-metrics | |
# | |
# DESCRIPTION: | |
# For all processes owned by a user AND/OR matching a provided process | |
# name substring, return selected memory metrics from /proc/[PID]/status | |
# | |
# OUTPUT: | |
# metric data | |
# | |
# PLATFORMS: | |
# Linux | |
# | |
# DEPENDENCIES: | |
# gem: sensu-plugin | |
# | |
# USAGE: | |
# | |
# NOTES: | |
# - This check names the metrics after the full process name | |
# string as found in /proc/[PID]/cmdline, so data will be lost if | |
# you have multiple processes with identical cmdlines. | |
# - A process that changes its cmdline but still matches the search | |
# query will be duplicated as multiple discovered processes. | |
# - We make some assumptions in parsing /proc/[PID]/status, this will | |
# mostly only work with the memory-related stats. | |
# | |
# LICENSE: | |
# Copyright (c) 2014 Cozy Services Ltd. opensource@cozy.co | |
# Matt Greensmith mgreensmith@cozy.co | |
# Released under the same terms as Sensu (the MIT license); see LICENSE | |
# for details. | |
# | |
require 'sensu-plugin/metric/cli' | |
require 'socket' | |
# | |
# String | |
# monkeypatch for helping validate PID strings | |
# | |
class String | |
# if its and integer, set it to a string | |
def integer? | |
to_i.to_s == self | |
end | |
end | |
# | |
# Proc Status | |
# | |
# /proc/[PID]/status memory metrics plugin | |
# | |
class ProcStatus < Sensu::Plugin::Metric::CLI::Graphite | |
option :user, | |
description: 'Query processes owned by a user', | |
short: '-u USER', | |
long: '--user USER' | |
option :processname, | |
description: 'Process name substring to match against, not a regex.', | |
short: '-p PROCESSNAME', | |
long: '--process-name PROCESSNAME' | |
option :scheme, | |
description: 'Metric naming scheme', | |
long: '--scheme SCHEME', | |
default: "#{Socket.gethostname}.proc" | |
option :metrics, | |
description: 'Memory metrics to collect from /proc/[PID]/status, comma-separated', | |
short: '-m METRICS', | |
long: '--metrics METRICS', | |
default: 'VmSize,VmRSS,VmSwap' | |
# Build search command | |
# | |
def pgrep_command | |
pgrep_command = 'pgrep ' | |
pgrep_command << "-u #{config[:user]} " if config[:user] | |
pgrep_command << "-f #{config[:processname]} " if config[:processname] | |
pgrep_command << '2<&1' | |
end | |
# Acquire process_pids | |
# | |
# @param pgrep_output [String] | |
# | |
def acquire_valid_pids(pgrep_output) | |
res = pgrep_output.split("\n").map(&:strip) | |
pids = res.select(&:integer?) | |
pids | |
end | |
# Acquire the sate for the supplied PID | |
# | |
# @param pid [String] | |
# | |
def acquire_stats_for_pid(pid) | |
return nil unless ::File.exist?(::File.join('/proc', pid, 'cmdline')) | |
cmdline_raw = `cat /proc/#{pid}/cmdline` | |
cmdline = cmdline_raw.strip.gsub(/[^[:alnum:]]/, '_') | |
metric_names = config[:metrics].split(',') | |
proc_status_lines = `cat /proc/#{pid}/status`.split("\n") | |
out = { cmdline.to_s => {} } | |
metric_names.each do |m| | |
line = proc_status_lines.find { |x| /^#{m}/.match(x) } | |
val = line ? line.split("\t")[1].to_i : nil | |
out[cmdline.to_s][m] = val | |
end | |
out | |
end | |
# Main functino | |
# | |
def run | |
raise 'You must supply -u USER or -p PROCESSNAME' unless config[:user] || config[:processname] | |
metrics = {} | |
pgrep_output = `#{pgrep_command}` | |
pids = acquire_valid_pids(pgrep_output) | |
pids.each do |p| | |
data = acquire_stats_for_pid(p) | |
metrics.merge!(data) unless data.nil? | |
end | |
timestamp = Time.now.to_i | |
metrics.each do |proc_name, stats| | |
stats.each do |stat_name, value| | |
output [config[:scheme], proc_name, stat_name].join('.'), value, timestamp | |
end | |
end | |
ok | |
end | |
end |