Ruby plugins: apply style changes as suggested by "rubocop --fix-layout"

This commit is contained in:
Lars Kruse 2020-08-25 16:52:39 +02:00
parent 26c29daa2b
commit b0b39b018e
30 changed files with 1447 additions and 1384 deletions

View File

@ -1,48 +1,53 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# netstat_bsd_m revision 1 (Feb 2012) =begin
#
# This plugin shows various statistics from 'netstat -m' netstat_bsd_m revision 1 (Feb 2012)
#
# Required privileges: none This plugin shows various statistics from 'netstat -m'
#
# OS: Required privileges: none
# Supposed: BSD
# Tested: FreeBSD 8.2 OS:
# Supposed: BSD
# Author: Artem Sheremet <dot.doom@gmail.com> Tested: FreeBSD 8.2
#
Author: Artem Sheremet <dot.doom@gmail.com>
#%# family=auto #%# family=auto
#%# capabilities=autoconf suggest #%# capabilities=autoconf suggest
=end
# original filename # original filename
PLUGIN_NAME = 'netstat_bsd_m_' PLUGIN_NAME = 'netstat_bsd_m_'
class String class String
def escape def escape
self.gsub /[^\w]/, '_' self.gsub /[^\w]/, '_'
end end
unless method_defined? :start_with? unless method_defined? :start_with?
def start_with?(str) def start_with?(str)
self[0...str.size] == str self[0...str.size] == str
end end
end end
end end
def netstat_m(filter = nil) def netstat_m(filter = nil)
Hash[`netstat -m`.split($/).map { |line| Hash[`netstat -m`.split($/).map { |line|
if line =~ /^([\d\/K]+) (.*) \(([\w\/+]+)\)$/ if line =~ /^([\d\/K]+) (.*) \(([\w\/+]+)\)$/
# 7891K/22385K/30276K bytes allocated to network (current/cache/total) # 7891K/22385K/30276K bytes allocated to network (current/cache/total)
values, desc, names = $1, $2, $3 values, desc, names = $1, $2, $3
[desc, names.split('/').zip(values.split '/')] if filter.nil? or desc.escape == filter [desc, names.split('/').zip(values.split '/')] if filter.nil? or desc.escape == filter
elsif line =~ /^(\d+) (.*)$/ elsif line =~ /^(\d+) (.*)$/
# 12327 requests for I/O initiated by sendfile # 12327 requests for I/O initiated by sendfile
value, desc = $1, $2 value, desc = $1, $2
[desc, [[ :value, value ]]] if filter.nil? or desc.escape == filter [desc, [[:value, value]]] if filter.nil? or desc.escape == filter
end end
}.compact] }.compact]
end end
stat_name = File.basename($0, '.*').escape stat_name = File.basename($0, '.*').escape
@ -50,47 +55,47 @@ stat_name.slice! 0, PLUGIN_NAME.size if stat_name.start_with? PLUGIN_NAME
case ARGV.first case ARGV.first
when 'autoconf' when 'autoconf'
puts `uname -s`.include?('FreeBSD') ? 'yes' : 'no' puts `uname -s`.include?('FreeBSD') ? 'yes' : 'no'
when 'suggest' when 'suggest'
puts netstat_m.keys.map(&:escape).join $/ puts netstat_m.keys.map(&:escape).join $/
when 'config' when 'config'
data = netstat_m(stat_name) data = netstat_m(stat_name)
if data.empty? if data.empty?
warn "no data for <#{stat_name}>. Try running with 'suggest'" warn "no data for <#{stat_name}>. Try running with 'suggest'"
else else
desc, values = data.first desc, values = data.first
stack = values.size > 1 stack = values.size > 1
first = true first = true
puts <<CONFIG puts <<~CONFIG
graph_title Netstat: #{desc} graph_title Netstat: #{desc}
graph_category network graph_category network
graph_vlabel current graph_vlabel current
graph_order #{values.map { |name, _| name.to_s.escape }.join ' '} graph_order #{values.map { |name, _| name.to_s.escape }.join ' '}
CONFIG CONFIG
puts values.map { |name, _| puts values.map { |name, _|
esc_name = name.to_s.escape esc_name = name.to_s.escape
"#{esc_name}.draw " + if %w(total max).include? name "#{esc_name}.draw " + if %w(total max).include? name
'LINE' 'LINE'
elsif stack elsif stack
if first if first
first = false first = false
'AREA' 'AREA'
else else
'STACK' 'STACK'
end end
else else
'LINE2' 'LINE2'
end + "\n#{esc_name}.label #{name}" end + "\n#{esc_name}.label #{name}"
}.join $/ }.join $/
end end
when nil # fetch when nil # fetch
data = netstat_m(stat_name) data = netstat_m(stat_name)
unless data.empty? unless data.empty?
puts data.first.last.map { |name, value| puts data.first.last.map { |name, value|
value = value.to_i * 1024 if value.end_with? 'K' value = value.to_i * 1024 if value.end_with? 'K'
"#{name.to_s.escape}.value #{value}" "#{name.to_s.escape}.value #{value}"
}.join $/ }.join $/
end end
else else
warn "unrecognized argument <#{ARGV.first}>" warn "unrecognized argument <#{ARGV.first}>"
end end

View File

@ -28,137 +28,138 @@ DEFAULT_CACHE = { :start => 0 }
$debug_mode = ARGV.first == 'debug' $debug_mode = ARGV.first == 'debug'
if $debug_mode if $debug_mode
log_info = DEFAULT_CACHE log_info = DEFAULT_CACHE
else else
begin begin
log_info = YAML.load IO.read(CACHE_FILE) log_info = YAML.load IO.read(CACHE_FILE)
rescue rescue
log_info = DEFAULT_CACHE log_info = DEFAULT_CACHE
end end
if File.size(LOG_FILE) < log_info[:start] if File.size(LOG_FILE) < log_info[:start]
# logrotate? # logrotate?
log_info = DEFAULT_CACHE log_info = DEFAULT_CACHE
end end
end end
if ARGV.first == 'reset' if ARGV.first == 'reset'
log_info = { :start => File.size(LOG_FILE)-1 } log_info = { :start => File.size(LOG_FILE) - 1 }
puts 'Log reset' puts 'Log reset'
end end
new_data = '' new_data = ''
File.open(LOG_FILE, 'rb') do |flog| File.open(LOG_FILE, 'rb') do |flog|
flog.seek(log_info[:start]) flog.seek(log_info[:start])
new_data = flog.read new_data = flog.read
end end
KNOWN_LOG_TYPES = [ KNOWN_LOG_TYPES = [
# each element is an instance of Array. 1st item: error description, others: text to search log for # each element is an instance of Array. 1st item: error description, others: text to search log for
['EJAB-1482 Crash when waiting for item', ['EJAB-1482 Crash when waiting for item',
['wait_for_']], ['wait_for_']],
['EJAB-1483 ODBC sup failure (wrong PID?)', ['EJAB-1483 ODBC sup failure (wrong PID?)',
['ejabberd_odbc_sup']], ['ejabberd_odbc_sup']],
['EJAB-1483 ODBC sup wrong PID failure echo', ['EJAB-1483 ODBC sup wrong PID failure echo',
["mod_pubsub_odbc,'-unsubscribe"]], ["mod_pubsub_odbc,'-unsubscribe"]],
['DNS failure', ['DNS failure',
['You should check your DNS configuration']], ['You should check your DNS configuration']],
['Database unavailable/too slow', ['Database unavailable/too slow',
['Database was not available or too slow']], ['Database was not available or too slow']],
['State machine terminated: timeout', ['State machine terminated: timeout',
['State machine', ['State machine',
'terminating', 'terminating',
'Reason for', 'Reason for',
'timeout']], 'timeout']],
['The auth module returned an error', ['The auth module returned an error',
['The authentication module', ['The authentication module',
'returned an error']], 'returned an error']],
['MySQL disconnected', ['MySQL disconnected',
['mysql', ['mysql',
'Received unknown signal, exiting']], 'Received unknown signal, exiting']],
['Connecting to MySQL: failed', ['Connecting to MySQL: failed',
['mysql', ['mysql',
'Failed connecting to']], 'Failed connecting to']],
['Timeout while running a hook', ['Timeout while running a hook',
['ejabberd_hooks', ['ejabberd_hooks',
'timeout']], 'timeout']],
['SQL transaction restarts exceeded', ['SQL transaction restarts exceeded',
['SQL transaction restarts exceeded']], ['SQL transaction restarts exceeded']],
['Unexpected info', ['Unexpected info',
['nexpected info']], ['nexpected info']],
['Other sql_cmd timeout', ['Other sql_cmd timeout',
['sql_cmd']], ['sql_cmd']],
['System limit hit: ports', # check with length(erlang:ports())., set in ejabberdctl config file ['System limit hit: ports', # check with length(erlang:ports())., set in ejabberdctl config file
['system_limit', ['system_limit',
'open_port']], 'open_port']],
['Other system limit hit', # processes? check with erlang:system_info(process_count)., erlang:system_info(process_limit)., set in ejabberdctl cfg ['Other system limit hit', # processes? check with erlang:system_info(process_count)., erlang:system_info(process_limit)., set in ejabberdctl cfg
['system_limit']], ['system_limit']],
['Generic server terminating', ['Generic server terminating',
['Generic server', ['Generic server',
'terminating']], 'terminating']],
['Mnesia table shrinked', ['Mnesia table shrinked',
['shrinking table']], ['shrinking table']],
['Admin access failed', ['Admin access failed',
['Access of', ['Access of',
'failed with error']], 'failed with error']],
['MySQL sock timedout', ['MySQL sock timedout',
['mysql_', ['mysql_',
': Socket', ': Socket',
'timedout']], 'timedout']],
['Configuration error', ['Configuration error',
['{badrecord,config}']], ['{badrecord,config}']],
['Strange vCard error (vhost)', ['Strange vCard error (vhost)',
['error found when trying to get the vCard']], ['error found when trying to get the vCard']],
['Mnesia is overloaded', ['Mnesia is overloaded',
['Mnesia is overloaded']], ['Mnesia is overloaded']],
['MySQL: init failed recv data', ['MySQL: init failed recv data',
['mysql_conn: init failed receiving data']], ['mysql_conn: init failed receiving data']],
['TCP Error', ['TCP Error',
['Failed TCP']] ['Failed TCP']]
] ]
def log_type(text) def log_type(text)
KNOWN_LOG_TYPES.find_index { |entry| KNOWN_LOG_TYPES.find_index { |entry|
entry[1].all? { |substr| text.include? substr } entry[1].all? { |substr| text.include? substr }
} }
end end
new_data.split("\n=").each { |report| new_data.split("\n=").each { |report|
next if report.empty? next if report.empty?
report =~ /\A(\w+) REPORT==== (.*) ===\n(.*)\z/m
type, time, text = $1, $2, $3
next unless type and time and text
log_info[type] = (log_info[type] || 0) + 1 report =~ /\A(\w+) REPORT==== (.*) ===\n(.*)\z/m
if sub_type = log_type(text) type, time, text = $1, $2, $3
log_info[sub_type] = (log_info[sub_type] || 0) + 1 next unless type and time and text
elsif $debug_mode
warn "Unparsed log entry #{type}: #{text} at #{time}" log_info[type] = (log_info[type] || 0) + 1
end if sub_type = log_type(text)
log_info[sub_type] = (log_info[sub_type] || 0) + 1
elsif $debug_mode
warn "Unparsed log entry #{type}: #{text} at #{time}"
end
} }
log_info[:start] += new_data.size log_info[:start] += new_data.size
File.open(CACHE_FILE, 'w') { |f| f.write log_info.to_yaml } unless $debug_mode File.open(CACHE_FILE, 'w') { |f| f.write log_info.to_yaml } unless $debug_mode
if ARGV.first == 'config' if ARGV.first == 'config'
puts <<CONFIG puts <<~CONFIG
graph_title Ejabberd Log graph_title Ejabberd Log
graph_vlabel total graph_vlabel total
graph_category chat graph_category chat
graph_args -l 0 graph_args -l 0
CONFIG CONFIG
end end
(KNOWN_LOG_TYPES + %w(ERROR WARNING INFO DEBUG)).each.with_index { |log_type, index| (KNOWN_LOG_TYPES + %w(ERROR WARNING INFO DEBUG)).each.with_index { |log_type, index|
label, index = if log_type.is_a? Array label, index = if log_type.is_a? Array
[log_type.first, index] [log_type.first, index]
else else
[log_type, log_type] [log_type, log_type]
end end
if ARGV.first == 'config' if ARGV.first == 'config'
puts "T#{index}.label #{label}" puts "T#{index}.label #{label}"
puts "T#{index}.draw LINE" puts "T#{index}.draw LINE"
else else
puts "T#{index}.value #{log_info[index] or 0}" puts "T#{index}.value #{log_info[index] or 0}"
end end
} }

View File

@ -1,37 +1,42 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# mongrel_memory - A munin plugin for OpenSolaris to monitor memory size of
# each individual mongrel process =begin
# Copyright (C) 2009 Matthias Marschall - mm@agileweboperations.com
# mongrel_memory - A munin plugin for OpenSolaris to monitor memory size of
# Based on: each individual mongrel process
# mongrel_process_memory - A munin plugin to monitor memory size of Copyright (C) 2009 Matthias Marschall - mm@agileweboperations.com
# each individual mongrel process
# Copyright (C) 2007 Ben VandenBos and Avvo, Inc. Based on:
# mongrel_process_memory - A munin plugin to monitor memory size of
# This program is free software; you can redistribute it and/or modify each individual mongrel process
# it under the terms of the GNU General Public License version 2 Copyright (C) 2007 Ben VandenBos and Avvo, Inc.
# as published by the Free Software Foundation.
# This program is free software; you can redistribute it and/or modify
# This program is distributed in the hope that it will be useful, it under the terms of the GNU General Public License version 2
# but WITHOUT ANY WARRANTY; without even the implied warranty of as published by the Free Software Foundation.
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# You should have received a copy of the GNU General Public License along MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# with this program; if not, write to the Free Software Foundation, Inc., GNU General Public License for more details.
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# You should have received a copy of the GNU General Public License along
# Author: Ben VandenBos with this program; if not, write to the Free Software Foundation, Inc.,
# Contributors: Adam Jacob (<adam@hjksolutions.com>) 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Ryan Woodrum
# Matthias Marschall (mm@agileweboperations.com) Author: Ben VandenBos
# Contributors: Adam Jacob (<adam@hjksolutions.com>)
Ryan Woodrum
Matthias Marschall (mm@agileweboperations.com)
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
module Munin module Munin
class MongrelProcessMemory class MongrelProcessMemory
def run def run
pid_port_map = get_pids() pid_port_map = get_pids()
port_list = Hash.new port_list = Hash.new
@ -48,8 +53,8 @@ module Munin
pids += `pgrep ruby`.split("\n") pids += `pgrep ruby`.split("\n")
pids.each { |pid| pids.each { |pid|
l = `pargs -l #{pid}` l = `pargs -l #{pid}`
l =~ /-p (\d+)/ l =~ /-p (\d+)/
h[pid] = $1 if $1 h[pid] = $1 if $1
} }
h h
end end
@ -57,7 +62,6 @@ module Munin
def autoconf def autoconf
get_pids().length > 0 get_pids().length > 0
end end
end end
end end

View File

@ -1,36 +1,40 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# mongrel_process_memory - A munin plugin to monitor memory size of =begin
# each individual mongrel process
# Copyright (C) 2007 Ben VandenBos and Avvo, Inc. mongrel_process_memory - A munin plugin to monitor memory size of
# each individual mongrel process
# This program is free software; you can redistribute it and/or modify Copyright (C) 2007 Ben VandenBos and Avvo, Inc.
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# Author: Ben VandenBos 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Contributors: Adam Jacob (<adam@hjksolutions.com>)
# Ryan Woodrum Author: Ben VandenBos
# Contributors: Adam Jacob (<adam@hjksolutions.com>)
Ryan Woodrum
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
module Munin module Munin
class MongrelProcessMemory class MongrelProcessMemory
def run def run
h = get_pids() h = get_pids()
ps_output = "" ps_output = ""
#I have no doubt that this is a terrible way of doing this. # I have no doubt that this is a terrible way of doing this.
h.each do |k, v| h.each do |k, v|
ps_output = ps_output + `ps --no-heading l #{k}` ps_output = ps_output + `ps --no-heading l #{k}`
end end
@ -59,8 +63,8 @@ module Munin
pids = `pgrep mongrel_rails` pids = `pgrep mongrel_rails`
pids.each { |p| pids.each { |p|
l = `ps #{p}` l = `ps #{p}`
l =~ /-p (\d+)/ l =~ /-p (\d+)/
h[p] = $1 h[p] = $1
} }
h h
end end
@ -68,7 +72,6 @@ module Munin
def autoconf def autoconf
pids.length > 0 pids.length > 0
end end
end end
end end

View File

@ -18,8 +18,8 @@ require 'open-uri'
def get_conf def get_conf
# Default values # Default values
conf = {:host => '127.0.0.1', :port => 8000, conf = { :host => '127.0.0.1', :port => 8000,
:username => 'admin', :password => 'hackme' } :username => 'admin', :password => 'hackme' }
conf.keys.each do |key| conf.keys.each do |key|
env_key = sprintf('icecast_%s', key) env_key = sprintf('icecast_%s', key)
conf[key] = ENV[env_key] if ENV.has_key?(env_key) conf[key] = ENV[env_key] if ENV.has_key?(env_key)
@ -31,8 +31,8 @@ def get_data(conf)
begin begin
data = Hpricot(open(sprintf('http://%s:%s/admin/stats', data = Hpricot(open(sprintf('http://%s:%s/admin/stats',
conf[:host], conf[:port]), conf[:host], conf[:port]),
:http_basic_authentication=>[conf[:username], :http_basic_authentication => [conf[:username],
conf[:password]])) conf[:password]]))
rescue OpenURI::HTTPError rescue OpenURI::HTTPError
puts "Cannot connect: HTTP connection error" puts "Cannot connect: HTTP connection error"
exit 1 exit 1
@ -43,7 +43,7 @@ end
def get_values(data) def get_values(data)
vals = {} vals = {}
[:sources, :clients].each do |key| [:sources, :clients].each do |key|
elem = data/key elem = data / key
if elem.nil? if elem.nil?
vals[key] = 0 vals[key] = 0
else else

View File

@ -8,12 +8,12 @@
require 'socket' require 'socket'
if ARGV[0] == 'config' if ARGV[0] == 'config'
puts "graph_title Connected players" puts "graph_title Connected players"
puts "graph_vlabel players" puts "graph_vlabel players"
puts "players.label players" puts "players.label players"
puts "graph_info Number of players connected to Minecraft" puts "graph_info Number of players connected to Minecraft"
puts "graph_category games" puts "graph_category games"
exit exit
end end
host = ENV['host'] host = ENV['host']

View File

@ -1,25 +1,30 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Plugin to monitor the number of connections blocked by moblock. =begin
#
# Requirements: Plugin to monitor the number of connections blocked by moblock.
#
# Moblock up and running with generated log files going to /var/log/moblock Requirements:
#
# Parameters supported: Moblock up and running with generated log files going to /var/log/moblock
#
# config Parameters supported:
# autoconf
# config
# Configurable variables autoconf
#
# logfile - Override default moblock logfile Configurable variables
#
# Magic markers logfile - Override default moblock logfile
#
Magic markers
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
# #
# Initialize vars # Initialize vars
# #
@ -54,7 +59,7 @@ end
# #
# Grep moblock logs for stats # Grep moblock logs for stats
# #
def fetch(debug=false) def fetch(debug = false)
num_in = %x{cat #{$logfile} | grep --extended-regexp 'IN: ' | wc -l} num_in = %x{cat #{$logfile} | grep --extended-regexp 'IN: ' | wc -l}
num_out = %x{cat #{$logfile} | grep --extended-regexp 'OUT: ' | wc -l} num_out = %x{cat #{$logfile} | grep --extended-regexp 'OUT: ' | wc -l}
num_total = num_in.to_i + num_out.to_i num_total = num_in.to_i + num_out.to_i
@ -80,12 +85,12 @@ end
# Handle command line args # Handle command line args
# #
case ARGV.first case ARGV.first
when 'config' when 'config'
config config
when 'debug' when 'debug'
fetch true fetch true
when 'autoconf' when 'autoconf'
autoconf autoconf
else else
fetch fetch
end end

View File

@ -1,49 +1,54 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for MSSQL - transaction monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for MSSQL - transaction monitoring
# Date: 2011-05-18
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-18
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems Prerequistes:
# 3) ruby-dbi 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems
# Usage: 3) ruby-dbi
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/mssql_transaction.rb /etc/munin/plugins/mssql_transaction.rb 2) chmod to allow executable to others
# 3) create symbolic link in /etc/munin/plugins
# Parameters: ln -s /usr/share/munin/plugins/mssql_transaction.rb /etc/munin/plugins/mssql_transaction.rb
# autoconf
# config (required) Parameters:
# autoconf
# Config variables: config (required)
# sqluser : mssql user who has view server state privilege
# sqlpass : password for the mssql user Config variables:
# dsn : datasource name as defined in /etc/odbc.ini sqluser : mssql user who has view server state privilege
# instance: instance to monitor sqlpass : password for the mssql user
# dsn : datasource name as defined in /etc/odbc.ini
instance: instance to monitor
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'dbi' require 'dbi'
@ -56,7 +61,7 @@ instance = 'AdventureWorks'
# Queries # Queries
# #
# #
dbh = DBI.connect("DBI:ODBC:#{dsn}",sqluser,sqlpass) dbh = DBI.connect("DBI:ODBC:#{dsn}", sqluser, sqlpass)
instance_name_query = "SELECT distinct instance_name instance_name_query = "SELECT distinct instance_name
FROM sys.dm_os_performance_counters FROM sys.dm_os_performance_counters
@ -69,10 +74,10 @@ transaction_query = "select cntr_value from sys.dm_os_performance_counters
and object_name = 'SQLServer:Databases' and object_name = 'SQLServer:Databases'
and instance_name = ?" and instance_name = ?"
all_instance_names = Array.new all_instance_names = Array.new
sth = dbh.execute(instance_name_query) sth = dbh.execute(instance_name_query)
sth.fetch do |row| sth.fetch do |row|
all_instance_names.push(row[0].strip) all_instance_names.push(row[0].strip)
end end
sth.finish sth.finish
@ -80,33 +85,33 @@ sth.finish
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1 if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1000 -r --lower-limit 0" puts "graph_args --base 1000 -r --lower-limit 0"
puts "graph_title MSSQL Transactions/s" puts "graph_title MSSQL Transactions/s"
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows transactions/s" puts "graph_info This graph shows transactions/s"
puts "graph_vlabel transactions/s" puts "graph_vlabel transactions/s"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
all_instance_names.sort.each do |s| all_instance_names.sort.each do |s|
puts "#{s}.label #{s}" puts "#{s}.label #{s}"
puts "#{s}.info INSTANCE: #{s}" puts "#{s}.info INSTANCE: #{s}"
puts "#{s}.type DERIVE" puts "#{s}.type DERIVE"
puts "#{s}.draw LINE1" puts "#{s}.draw LINE1"
end end
exit 0 exit 0
end end
# #
@ -114,11 +119,11 @@ end
# #
sth = dbh.prepare(transaction_query) sth = dbh.prepare(transaction_query)
all_instance_names.sort.each do |k| all_instance_names.sort.each do |k|
sth.execute(k) sth.execute(k)
sth.fetch do |row| sth.fetch do |row|
# since type is DERIVE, need to convert value to integer then to string # since type is DERIVE, need to convert value to integer then to string
puts "#{k.to_s}.value #{row[0].to_i.to_s}" puts "#{k.to_s}.value #{row[0].to_i.to_s}"
end end
end end
sth.finish sth.finish
dbh.disconnect dbh.disconnect

View File

@ -1,48 +1,53 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for MSSQL - Buffer cache hit ratio monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for MSSQL - Buffer cache hit ratio monitoring
# Date: 2011-05-19
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-19
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems Prerequistes:
# 3) ruby-dbi 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems
# Usage: 3) ruby-dbi
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/mssql_buffercachehitratio.rb /etc/munin/plugins/mssql_buffercachehitratio.rb 2) chmod to allow executable to others
# 3) create symbolic link in /etc/munin/plugins
# Parameters: ln -s /usr/share/munin/plugins/mssql_buffercachehitratio.rb /etc/munin/plugins/mssql_buffercachehitratio.rb
# autoconf
# config (required) Parameters:
# autoconf
# Config variables: config (required)
# sqluser : mssql user who has view server state privilege
# sqlpass : password for the mssql user Config variables:
# dsn : datasource name as defined in /etc/odbc.ini sqluser : mssql user who has view server state privilege
# sqlpass : password for the mssql user
dsn : datasource name as defined in /etc/odbc.ini
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'dbi' require 'dbi'
@ -54,7 +59,7 @@ dsn = 'TESTSQL'
# Queries # Queries
# #
# #
dbh = DBI.connect("DBI:ODBC:#{dsn}",sqluser,sqlpass) dbh = DBI.connect("DBI:ODBC:#{dsn}", sqluser, sqlpass)
buffercachehitratio_query = "select (a.cntr_value * 1.0 / b.cntr_value) * 100.0 buffercachehitratio_query = "select (a.cntr_value * 1.0 / b.cntr_value) * 100.0
from sys.dm_os_performance_counters a from sys.dm_os_performance_counters a
@ -70,36 +75,36 @@ buffercachehitratio_query = "select (a.cntr_value * 1.0 / b.cntr_value) * 100.0
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1 if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1000 -r --lower-limit 0" puts "graph_args --base 1000 -r --lower-limit 0"
puts "graph_title MSSQL Buffer Cache Hit Ratio " puts "graph_title MSSQL Buffer Cache Hit Ratio "
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows Buffer Cache Hit Ratio" puts "graph_info This graph shows Buffer Cache Hit Ratio"
puts "graph_vlabel %" puts "graph_vlabel %"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
puts "bc_hitratio.label BufferCacheHitRatio" puts "bc_hitratio.label BufferCacheHitRatio"
puts "bc_hitratio.info BufferCacheHitRatio" puts "bc_hitratio.info BufferCacheHitRatio"
puts "bc_hitratio.type GAUGE" puts "bc_hitratio.type GAUGE"
puts "bc_hitratio.draw LINE1" puts "bc_hitratio.draw LINE1"
exit 0 exit 0
end end
sth = dbh.execute(buffercachehitratio_query) sth = dbh.execute(buffercachehitratio_query)
sth.fetch do |row| sth.fetch do |row|
puts "bc_hitratio.value #{row[0].strip.to_s}" puts "bc_hitratio.value #{row[0].strip.to_s}"
end end
sth.finish sth.finish
dbh.disconnect dbh.disconnect

View File

@ -1,49 +1,54 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for MSSQL - Data file size monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for MSSQL - Data file size monitoring
# Date: 2011-05-19
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-19
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems Prerequistes:
# 3) ruby-dbi 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems
# Usage: 3) ruby-dbi
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/mssql_datafilesizes.rb /etc/munin/plugins/mssql_datafilesizes.rb 2) chmod to allow executable to others
# 3) create symbolic link in /etc/munin/plugins
# Parameters: ln -s /usr/share/munin/plugins/mssql_datafilesizes.rb /etc/munin/plugins/mssql_datafilesizes.rb
# autoconf
# config (required) Parameters:
# autoconf
# Config variables: config (required)
# sqluser : mssql user who has view server state privilege
# sqlpass : password for the mssql user Config variables:
# dsn : datasource name as defined in /etc/odbc.ini sqluser : mssql user who has view server state privilege
# instance: instance to monitor sqlpass : password for the mssql user
# dsn : datasource name as defined in /etc/odbc.ini
instance: instance to monitor
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'dbi' require 'dbi'
@ -56,7 +61,7 @@ instance = 'AdventureWorks'
# Queries # Queries
# #
# #
dbh = DBI.connect("DBI:ODBC:#{dsn}",sqluser,sqlpass) dbh = DBI.connect("DBI:ODBC:#{dsn}", sqluser, sqlpass)
instance_name_query = "SELECT distinct instance_name instance_name_query = "SELECT distinct instance_name
FROM sys.dm_os_performance_counters FROM sys.dm_os_performance_counters
@ -67,10 +72,10 @@ transaction_query = "select cntr_value/1024.0 from sys.dm_os_performance_counter
and object_name = 'SQLServer:Databases' and object_name = 'SQLServer:Databases'
and instance_name = ?" and instance_name = ?"
all_instance_names = Array.new all_instance_names = Array.new
sth = dbh.execute(instance_name_query) sth = dbh.execute(instance_name_query)
sth.fetch do |row| sth.fetch do |row|
all_instance_names.push(row[0].strip) all_instance_names.push(row[0].strip)
end end
sth.finish sth.finish
@ -78,33 +83,33 @@ sth.finish
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1 if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1024k -r --lower-limit 0" puts "graph_args --base 1024k -r --lower-limit 0"
puts "graph_title MSSQL DB File Sizes" puts "graph_title MSSQL DB File Sizes"
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows DB File Sizes (MB)" puts "graph_info This graph shows DB File Sizes (MB)"
puts "graph_vlabel MB" puts "graph_vlabel MB"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
all_instance_names.sort.each do |s| all_instance_names.sort.each do |s|
puts "#{s}.label #{s}" puts "#{s}.label #{s}"
puts "#{s}.info INSTANCE: #{s}" puts "#{s}.info INSTANCE: #{s}"
puts "#{s}.type GAUGE" puts "#{s}.type GAUGE"
puts "#{s}.draw LINE1" puts "#{s}.draw LINE1"
end end
exit 0 exit 0
end end
# #
@ -112,10 +117,10 @@ end
# #
sth = dbh.prepare(transaction_query) sth = dbh.prepare(transaction_query)
all_instance_names.sort.each do |k| all_instance_names.sort.each do |k|
sth.execute(k) sth.execute(k)
sth.fetch do |row| sth.fetch do |row|
puts "#{k.to_s}.value #{row[0].to_s}" puts "#{k.to_s}.value #{row[0].to_s}"
end end
end end
sth.finish sth.finish
dbh.disconnect dbh.disconnect

View File

@ -1,49 +1,54 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for MSSQL - log files monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for MSSQL - log files monitoring
# Date: 2011-05-19
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-19
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems Prerequistes:
# 3) ruby-dbi 1) /etc/odbc.ini and /etc/freetds.conf
# 2) rubygems
# Usage: 3) ruby-dbi
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/mssql_logfilesizes.rb /etc/munin/plugins/mssql_logfilesizes.rb 2) chmod to allow executable to others
# 3) create symbolic link in /etc/munin/plugins
# Parameters: ln -s /usr/share/munin/plugins/mssql_logfilesizes.rb /etc/munin/plugins/mssql_logfilesizes.rb
# autoconf
# config (required) Parameters:
# autoconf
# Config variables: config (required)
# sqluser : mssql user who has view server state privilege
# sqlpass : password for the mssql user Config variables:
# dsn : datasource name as defined in /etc/odbc.ini sqluser : mssql user who has view server state privilege
# instance: instance to monitor sqlpass : password for the mssql user
# dsn : datasource name as defined in /etc/odbc.ini
instance: instance to monitor
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'dbi' require 'dbi'
@ -56,7 +61,7 @@ instance = 'AdventureWorks'
# Queries # Queries
# #
# #
dbh = DBI.connect("DBI:ODBC:#{dsn}",sqluser,sqlpass) dbh = DBI.connect("DBI:ODBC:#{dsn}", sqluser, sqlpass)
instance_name_query = "SELECT distinct instance_name instance_name_query = "SELECT distinct instance_name
FROM sys.dm_os_performance_counters FROM sys.dm_os_performance_counters
@ -67,10 +72,10 @@ logfilesize_query = "SELECT cntr_value/1024.0 from sys.dm_os_performance_counter
AND object_name = 'SQLServer:Databases' AND object_name = 'SQLServer:Databases'
AND instance_name = ?" AND instance_name = ?"
all_instance_names = Array.new all_instance_names = Array.new
sth = dbh.execute(instance_name_query) sth = dbh.execute(instance_name_query)
sth.fetch do |row| sth.fetch do |row|
all_instance_names.push(row[0].strip) all_instance_names.push(row[0].strip)
end end
sth.finish sth.finish
@ -78,41 +83,41 @@ sth.finish
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1 if all_instance_names.length > 1 && sqluser.length > 1 && sqlpass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1024k -r --lower-limit 0" puts "graph_args --base 1024k -r --lower-limit 0"
puts "graph_title MSSQL DB Log File Sizes" puts "graph_title MSSQL DB Log File Sizes"
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows DB Log File Sizes (MB)" puts "graph_info This graph shows DB Log File Sizes (MB)"
puts "graph_vlabel MB" puts "graph_vlabel MB"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
all_instance_names.sort.each do |s| all_instance_names.sort.each do |s|
puts "#{s}.label #{s}" puts "#{s}.label #{s}"
puts "#{s}.info INSTANCE: #{s}" puts "#{s}.info INSTANCE: #{s}"
puts "#{s}.type GAUGE" puts "#{s}.type GAUGE"
puts "#{s}.draw LINE1" puts "#{s}.draw LINE1"
end end
exit 0 exit 0
end end
sth = dbh.prepare(logfilesize_query) sth = dbh.prepare(logfilesize_query)
all_instance_names.sort.each do |k| all_instance_names.sort.each do |k|
sth.execute(k) sth.execute(k)
sth.fetch do |row| sth.fetch do |row|
puts "#{k.to_s}.value #{row[0].to_s}" puts "#{k.to_s}.value #{row[0].to_s}"
end end
end end
sth.finish sth.finish
dbh.disconnect dbh.disconnect

View File

@ -45,7 +45,7 @@ require 'net/http'
class TPAdslStats class TPAdslStats
def initialize(host, user, password) def initialize(host, user, password)
Net::HTTP.start( host ) do |http| Net::HTTP.start(host) do |http|
req = Net::HTTP::Get.new('/statsadsl.html') req = Net::HTTP::Get.new('/statsadsl.html')
req.basic_auth user, password req.basic_auth user, password
response = http.request(req) response = http.request(req)

View File

@ -1,22 +1,26 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# netstat_s revision 6 (Nov 2013) =begin
#
# This plugin shows various statistics from 'netstat -s' netstat_s revision 6 (Nov 2013)
#
# Required privileges: none This plugin shows various statistics from 'netstat -s'
#
# OS: Required privileges: none
# Supposed: BSD, Linux (only a few items, see netstat_multi for more)
# Tested: FreeBSD: 8.2, 8.3, 9.1 OS:
# Linux : Debian 6 (kernel 2.6.32), Arch (kernel 3.11.6), CentOS 6 Supposed: BSD, Linux (only a few items, see netstat_multi for more)
# Tested: FreeBSD: 8.2, 8.3, 9.1
# Author: Artem Sheremet <dot.doom@gmail.com> Linux : Debian 6 (kernel 2.6.32), Arch (kernel 3.11.6), CentOS 6
#
Author: Artem Sheremet <dot.doom@gmail.com>
#%# family=auto #%# family=auto
#%# capabilities=autoconf suggest #%# capabilities=autoconf suggest
=end
# original filename # original filename
PLUGIN_NAME = 'netstat_s_' PLUGIN_NAME = 'netstat_s_'
@ -24,348 +28,348 @@ $os = `uname -s`.strip.downcase.to_sym
$debug_mode = ARGV.first == 'debug' $debug_mode = ARGV.first == 'debug'
class String class String
def escape def escape
self.gsub /[^\w]/, '_' self.gsub /[^\w]/, '_'
end end
unless method_defined? :start_with? unless method_defined? :start_with?
def start_with?(str) def start_with?(str)
self[0...str.size] == str self[0...str.size] == str
end end
end end
unless method_defined? :lines unless method_defined? :lines
def lines def lines
self.split($/).to_enum self.split($/).to_enum
end end
end end
end end
class Graph class Graph
def initialize(name, protocol, parse_expr) def initialize(name, protocol, parse_expr)
@name, @protocol, @parse_expr = name, protocol, parse_expr @name, @protocol, @parse_expr = name, protocol, parse_expr
end end
def config def config
config_options = [] config_options = []
# first, build a list of multigraphs (one graph per unit) # first, build a list of multigraphs (one graph per unit)
# Hash key is unit, and the value is array of labels # Hash key is unit, and the value is array of labels
multigraphs = {} multigraphs = {}
@parse_expr.each { |expr, descr| @parse_expr.each { |expr, descr|
next unless descr # no label - skip this entry next unless descr # no label - skip this entry
descr.each { |entry|
labels_array = (multigraphs[entry[0]] ||= [])
labels_array.push [entry[1], entry[2]]
}
}
multigraphs.each_pair { |unit, labels_and_negatives| descr.each { |entry|
# now just add options to the config labels_array = (multigraphs[entry[0]] ||= [])
labels_array.push [entry[1], entry[2]]
}
}
config_options.concat [ multigraphs.each_pair { |unit, labels_and_negatives|
"multigraph #{name(unit)}", # now just add options to the config
"graph_title Netstat: #{@protocol}: #{@name}#{" (#{unit})" if multigraphs.size > 1}",
"graph_category network",
"graph_order #{labels_and_negatives.map { |label, _negative| label.escape }.join(' ')}"
]
config_options.push "graph_args --base 1024" if unit == :bytes config_options.concat [
has_negatives = false "multigraph #{name(unit)}",
"graph_title Netstat: #{@protocol}: #{@name}#{" (#{unit})" if multigraphs.size > 1}",
"graph_category network",
"graph_order #{labels_and_negatives.map { |label, _negative| label.escape }.join(' ')}"
]
labels_and_negatives.each { |label, negative| config_options.push "graph_args --base 1024" if unit == :bytes
label_esc = label.escape has_negatives = false
has_negatives = true unless negative == nil
if negative == true labels_and_negatives.each { |label, negative|
# the value has no opposite and is negative label_esc = label.escape
config_options.concat [ has_negatives = true unless negative == nil
"#{label_esc}.graph no",
"#{label_esc}_neg.type DERIVE",
"#{label_esc}_neg.min 0",
"#{label_esc}_neg.draw LINE",
"#{label_esc}_neg.label #{label}",
"#{label_esc}_neg.negative #{label_esc}"
]
else
config_options.concat [
"#{label_esc}.type DERIVE",
"#{label_esc}.min 0",
"#{label_esc}.draw LINE",
"#{label_esc}.label #{label}"
]
end
if negative == false if negative == true
# the value has no opposite and is positive # the value has no opposite and is negative
config_options.concat [ config_options.concat [
"#{label_esc}_neg.graph off", "#{label_esc}.graph no",
"#{label_esc}.negative #{label_esc}_neg" "#{label_esc}_neg.type DERIVE",
] "#{label_esc}_neg.min 0",
elsif negative "#{label_esc}_neg.draw LINE",
negative_esc = negative.escape "#{label_esc}_neg.label #{label}",
config_options.concat [ "#{label_esc}_neg.negative #{label_esc}"
"#{label_esc}.negative #{negative_esc}", ]
"#{negative_esc}.graph no" else
] config_options.concat [
end "#{label_esc}.type DERIVE",
} "#{label_esc}.min 0",
"#{label_esc}.draw LINE",
"#{label_esc}.label #{label}"
]
end
config_options.push "graph_vlabel per second#{" in (-) / out (+)" if has_negatives}" if negative == false
} # the value has no opposite and is positive
config_options.concat [
"#{label_esc}_neg.graph off",
"#{label_esc}.negative #{label_esc}_neg"
]
elsif negative
negative_esc = negative.escape
config_options.concat [
"#{label_esc}.negative #{negative_esc}",
"#{negative_esc}.graph no"
]
end
}
config_options config_options.push "graph_vlabel per second#{" in (-) / out (+)" if has_negatives}"
end }
def fetch(data) config_options
output_data = [] end
# first build a set of multigraphs, one per unit. def fetch(data)
# Hash key is unit, and the value is a hash of 'escaped label' => 'value' output_data = []
multigraphs = {}
@parse_expr.each { |expr, descr|
next unless descr # no label - skip this entry
index = data.index { |line| line =~ expr }
if index
data.delete_at index
$~[1..-1].zip(descr).each { |value, info|
unit, label = info
(multigraphs[unit] ||= {})[label.escape] = value
}
else
warn "no line found for #{expr}, #{descr}" if $debug_mode
end
}
multigraphs.each_pair { |unit, values| # first build a set of multigraphs, one per unit.
output_data.push "multigraph #{name(unit)}" # Hash key is unit, and the value is a hash of 'escaped label' => 'value'
output_data += values.map { |label, value| "#{label}.value #{value}" } multigraphs = {}
} @parse_expr.each { |expr, descr|
next unless descr # no label - skip this entry
output_data index = data.index { |line| line =~ expr }
end if index
data.delete_at index
$~[1..-1].zip(descr).each { |value, info|
unit, label = info
(multigraphs[unit] ||= {})[label.escape] = value
}
else
warn "no line found for #{expr}, #{descr}" if $debug_mode
end
}
def name(unit) multigraphs.each_pair { |unit, values|
"#{PLUGIN_NAME}#{@protocol}_#{@name.escape}_#{unit}" output_data.push "multigraph #{name(unit)}"
end output_data += values.map { |label, value| "#{label}.value #{value}" }
}
output_data
end
def name(unit)
"#{PLUGIN_NAME}#{@protocol}_#{@name.escape}_#{unit}"
end
end end
def graphs_for(protocol) def graphs_for(protocol)
case protocol case protocol
# Order of the graps in each section is important for parsing. # Order of the graps in each section is important for parsing.
# At the same time, it is not important for munin, so we are OK placing it in parsing order here. # At the same time, it is not important for munin, so we are OK placing it in parsing order here.
when 'tcp' when 'tcp'
$os == :linux ? [ $os == :linux ? [
Graph.new('sent', protocol, [ Graph.new('sent', protocol, [
# Description of the elements of arrays below: # Description of the elements of arrays below:
# 0: regexp to parse the line # 0: regexp to parse the line
# 1: Array<Array[3]> for each matching group in the regular expression. # 1: Array<Array[3]> for each matching group in the regular expression.
# 0: unit name # 0: unit name
# 1: label # 1: label
# 2 (optional): negative label # 2 (optional): negative label
# It could be reasonable to add more elements as warning and critical values. # It could be reasonable to add more elements as warning and critical values.
[ /(\d+) segments send out$/, [ [ :segments, 'total' ] ] ], [/(\d+) segments send out$/, [[:segments, 'total']]],
[ /(\d+) segments retransmitted$/, [ [ :segments, 'retransmitted' ] ] ] [/(\d+) segments retransmitted$/, [[:segments, 'retransmitted']]]
]), ]),
Graph.new('received', protocol, [ Graph.new('received', protocol, [
[ /(\d+) segments received$/, [ [ :segments, 'total' ] ] ], [/(\d+) segments received$/, [[:segments, 'total']]],
[ /(\d+) bad segments received.$/, [ [ :segments, 'bad' ] ] ] [/(\d+) bad segments received.$/, [[:segments, 'bad']]]
]), ]),
Graph.new('connections', protocol, [ Graph.new('connections', protocol, [
[ /(\d+) active connections openings$/, [ [ :connections, 'active openings' ] ] ], [/(\d+) active connections openings$/, [[:connections, 'active openings']]],
[ /(\d+) passive connection openings$/, [ [ :connections, 'passive openings' ] ] ], [/(\d+) passive connection openings$/, [[:connections, 'passive openings']]],
[ /(\d+) failed connection attempts$/, [ [ :connections, 'failed attempts' ] ] ], [/(\d+) failed connection attempts$/, [[:connections, 'failed attempts']]],
[ /(\d+) connection resets received$/, [ [ :connections, 'RST received' ] ] ], [/(\d+) connection resets received$/, [[:connections, 'RST received']]],
[ /(\d+) connections established$/, [ [ :connections, 'established' ] ] ], [/(\d+) connections established$/, [[:connections, 'established']]],
[ /(\d+) resets sent$/, [ [ :connections, 'RST sent' ] ] ] [/(\d+) resets sent$/, [[:connections, 'RST sent']]]
]), ]),
Graph.new('timeouts', protocol, [ Graph.new('timeouts', protocol, [
[ /(\d+) timeouts after SACK recovery$/, [ [ :segments, 'after SACK recovery' ] ] ], [/(\d+) timeouts after SACK recovery$/, [[:segments, 'after SACK recovery']]],
[ /(\d+) other TCP timeouts$/, [ [ :segments, 'other TCP' ] ] ], [/(\d+) other TCP timeouts$/, [[:segments, 'other TCP']]],
[ /(\d+) timeouts in loss state$/, [ [ :segments, 'in a loss state' ] ] ] [/(\d+) timeouts in loss state$/, [[:segments, 'in a loss state']]]
]) ])
] : [ ] : [
Graph.new('sent', protocol, [ Graph.new('sent', protocol, [
[ /(\d+) packets sent$/, [ [ :packets, 'total' ] ] ], [/(\d+) packets sent$/, [[:packets, 'total']]],
[ /(\d+) data packets \((\d+) bytes\)$/, [ [ :packets, 'data' ], [ :bytes, 'data' ] ] ], [/(\d+) data packets \((\d+) bytes\)$/, [[:packets, 'data'], [:bytes, 'data']]],
[ /(\d+) data packets \((\d+) bytes\) retransmitted$/, [ [ :packets, 'retransmitted' ], [ :bytes, 'retransmitted' ] ] ], [/(\d+) data packets \((\d+) bytes\) retransmitted$/, [[:packets, 'retransmitted'], [:bytes, 'retransmitted']]],
[ /(\d+) data packets unnecessarily retransmitted$/, [ [ :packets, 'unnecessarily retransmitted' ] ] ], [/(\d+) data packets unnecessarily retransmitted$/, [[:packets, 'unnecessarily retransmitted']]],
[ /(\d+) resends initiated by MTU discovery$/, [ [ :packets, 'resends initiated by MTU discovery' ] ] ], [/(\d+) resends initiated by MTU discovery$/, [[:packets, 'resends initiated by MTU discovery']]],
[ /(\d+) ack-only packets \((\d+) delayed\)$/, [ [ :packets, 'ack-only' ], [ :packets, 'ack-only delayed' ] ] ], [/(\d+) ack-only packets \((\d+) delayed\)$/, [[:packets, 'ack-only'], [:packets, 'ack-only delayed']]],
[ /(\d+) URG only packets$/, [ [ :packets, 'URG only' ] ] ], [/(\d+) URG only packets$/, [[:packets, 'URG only']]],
[ /(\d+) window probe packets$/, [ [ :packets, 'window probe' ] ] ], [/(\d+) window probe packets$/, [[:packets, 'window probe']]],
[ /(\d+) window update packets$/, [ [ :packets, 'window update' ] ] ], [/(\d+) window update packets$/, [[:packets, 'window update']]],
[ /(\d+) control packets$/, [ [ :packets, 'control' ] ] ] [/(\d+) control packets$/, [[:packets, 'control']]]
]), ]),
Graph.new('received', protocol, [ Graph.new('received', protocol, [
[ /(\d+) packets received$/, [ [ :packets, 'total' ] ] ], [/(\d+) packets received$/, [[:packets, 'total']]],
[ /(\d+) acks \(for (\d+) bytes\)$/, [ [ :packets, 'acks' ], [ :bytes, 'acks' ] ] ], [/(\d+) acks \(for (\d+) bytes\)$/, [[:packets, 'acks'], [:bytes, 'acks']]],
[ /(\d+) duplicate acks$/, [ [ :packets, 'duplicate acks' ] ] ], [/(\d+) duplicate acks$/, [[:packets, 'duplicate acks']]],
[ /(\d+) acks for unsent data$/, [ [ :packets, 'acks for unsent data' ] ] ], [/(\d+) acks for unsent data$/, [[:packets, 'acks for unsent data']]],
[ /(\d+) packets \((\d+) bytes\) received in-sequence$/, [ [ :packets, 'in-sequence' ], [ :bytes, 'in-sequence' ] ] ], [/(\d+) packets \((\d+) bytes\) received in-sequence$/, [[:packets, 'in-sequence'], [:bytes, 'in-sequence']]],
[ /(\d+) completely duplicate packets \((\d+) bytes\)$/, [ [ :packets, 'completely duplicate' ], [ :bytes, 'completely duplicate' ] ] ], [/(\d+) completely duplicate packets \((\d+) bytes\)$/, [[:packets, 'completely duplicate'], [:bytes, 'completely duplicate']]],
[ /(\d+) old duplicate packets$/, [ [ :packets, 'old duplicate' ] ] ], [/(\d+) old duplicate packets$/, [[:packets, 'old duplicate']]],
[ /(\d+) packets with some dup\. data \((\d+) bytes duped\)$/, [ [ :packets, 'some dup. data' ], [ :bytes, 'partial dups' ] ] ], [/(\d+) packets with some dup\. data \((\d+) bytes duped\)$/, [[:packets, 'some dup. data'], [:bytes, 'partial dups']]],
[ /(\d+) out-of-order packets \((\d+) bytes\)$/, [ [ :packets, 'out-of-order' ], [ :bytes, 'out-of-order' ] ] ], [/(\d+) out-of-order packets \((\d+) bytes\)$/, [[:packets, 'out-of-order'], [:bytes, 'out-of-order']]],
[ /(\d+) packets \((\d+) bytes\) of data after window$/, [ [ :packets, 'data after window' ], [ :bytes, 'data after window' ] ] ], [/(\d+) packets \((\d+) bytes\) of data after window$/, [[:packets, 'data after window'], [:bytes, 'data after window']]],
[ /(\d+) window probes$/, [ [ :packets, 'window probes' ] ] ], [/(\d+) window probes$/, [[:packets, 'window probes']]],
[ /(\d+) window update packets$/, [ [ :packets, 'window update' ] ] ], [/(\d+) window update packets$/, [[:packets, 'window update']]],
[ /(\d+) packets received after close$/, [ [ :packets, 'after close' ] ] ], [/(\d+) packets received after close$/, [[:packets, 'after close']]],
[ /(\d+) discarded for bad checksums$/, [ [ :packets, 'bad checksums' ] ] ], [/(\d+) discarded for bad checksums$/, [[:packets, 'bad checksums']]],
[ /(\d+) discarded for bad header offset fields?$/, [ [ :packets, 'bad header offset flds' ] ] ], [/(\d+) discarded for bad header offset fields?$/, [[:packets, 'bad header offset flds']]],
[ /(\d+) discarded because packet too short$/, [ [ :packets, 'too short' ] ] ], [/(\d+) discarded because packet too short$/, [[:packets, 'too short']]],
[ /(\d+) discarded due to memory problems$/, [ [ :packets, 'discarded: memory problems' ] ] ], [/(\d+) discarded due to memory problems$/, [[:packets, 'discarded: memory problems']]],
[ /(\d+) ignored RSTs in the windows$/, [ [ :packets, 'ignored RSTs in windows' ] ] ], [/(\d+) ignored RSTs in the windows$/, [[:packets, 'ignored RSTs in windows']]],
[ /(\d+) segments updated rtt \(of (\d+) attempts\)$/, [ [ :packets, 'RTT: updated' ], [ :packets, 'RTT: attempts to update' ] ] ] [/(\d+) segments updated rtt \(of (\d+) attempts\)$/, [[:packets, 'RTT: updated'], [:packets, 'RTT: attempts to update']]]
]), ]),
Graph.new('connections', protocol, [ Graph.new('connections', protocol, [
[ /(\d+) connection requests$/, [ [ :connections, 'requests' ] ] ], [/(\d+) connection requests$/, [[:connections, 'requests']]],
[ /(\d+) connection accepts$/, [ [ :connections, 'accepts' ] ] ], [/(\d+) connection accepts$/, [[:connections, 'accepts']]],
[ /(\d+) bad connection attempts$/, [ [ :connections, 'bad attempts' ] ] ], [/(\d+) bad connection attempts$/, [[:connections, 'bad attempts']]],
[ /(\d+) listen queue overflows$/, [ [ :connections, 'listen queue overflows' ] ] ], [/(\d+) listen queue overflows$/, [[:connections, 'listen queue overflows']]],
[ /(\d+) connections established \(including accepts\)$/, [ [ :connections, 'established' ] ] ], [/(\d+) connections established \(including accepts\)$/, [[:connections, 'established']]],
[ /(\d+) connections closed \(including (\d+) drops\)$/, [ [ :connections, 'closed' ], [ :connections, 'dropped' ] ] ], [/(\d+) connections closed \(including (\d+) drops\)$/, [[:connections, 'closed'], [:connections, 'dropped']]],
[ /(\d+) connections updated cached RTT on close$/, [ [ :connections, 'closed & upd cached RTT' ] ] ], [/(\d+) connections updated cached RTT on close$/, [[:connections, 'closed & upd cached RTT']]],
[ /(\d+) connections updated cached RTT variance on close$/, [ [ :connections, 'closed & upd cached RTT variance' ] ] ], [/(\d+) connections updated cached RTT variance on close$/, [[:connections, 'closed & upd cached RTT variance']]],
[ /(\d+) connections updated cached ssthresh on close$/, [ [ :connections, 'closed & upd cached ssthresh' ] ] ], [/(\d+) connections updated cached ssthresh on close$/, [[:connections, 'closed & upd cached ssthresh']]],
[ /(\d+) embryonic connections dropped$/, [ [ :connections, 'embryonic dropped' ] ] ] [/(\d+) embryonic connections dropped$/, [[:connections, 'embryonic dropped']]]
]), ]),
Graph.new('timeouts', protocol, [ Graph.new('timeouts', protocol, [
[ /(\d+) retransmit timeouts$/, [ [ :connections, 'retransmit' ] ] ], [/(\d+) retransmit timeouts$/, [[:connections, 'retransmit']]],
[ /(\d+) connections dropped by rexmit timeout$/, [ [ :connections, 'retransmit: dropped' ] ] ], [/(\d+) connections dropped by rexmit timeout$/, [[:connections, 'retransmit: dropped']]],
[ /(\d+) persist timeouts$/, [ [ :connections, 'persist' ] ] ], [/(\d+) persist timeouts$/, [[:connections, 'persist']]],
[ /(\d+) connections dropped by persist timeout$/, [ [ :connections, 'persist: dropped' ] ] ], [/(\d+) connections dropped by persist timeout$/, [[:connections, 'persist: dropped']]],
[ /(\d+) Connections \(fin_wait_2\) dropped because of timeout$/, [ [ :connections, 'fin_wait_2: dropped' ] ] ], [/(\d+) Connections \(fin_wait_2\) dropped because of timeout$/, [[:connections, 'fin_wait_2: dropped']]],
[ /(\d+) keepalive timeouts$/, [ [ :connections, 'keepalive' ] ] ], [/(\d+) keepalive timeouts$/, [[:connections, 'keepalive']]],
[ /(\d+) keepalive probes sent$/, [ [ :connections, 'keepalive: probes sent' ] ] ], [/(\d+) keepalive probes sent$/, [[:connections, 'keepalive: probes sent']]],
[ /(\d+) connections dropped by keepalive$/, [ [ :connections, 'keepalive: dropped' ] ] ] [/(\d+) connections dropped by keepalive$/, [[:connections, 'keepalive: dropped']]]
]), ]),
Graph.new('correct predictions', protocol, [ Graph.new('correct predictions', protocol, [
[ /(\d+) correct ACK header predictions$/, [ [ :predictions, 'ACK header' ] ] ], [/(\d+) correct ACK header predictions$/, [[:predictions, 'ACK header']]],
[ /(\d+) correct data packet header predictions$/, [ [ :predictions, 'data packet header' ] ] ] [/(\d+) correct data packet header predictions$/, [[:predictions, 'data packet header']]]
]), ]),
Graph.new('SYN', protocol, [ Graph.new('SYN', protocol, [
[ /(\d+) syncache entries added$/, [ [ :entries, 'cache added' ] ] ], [/(\d+) syncache entries added$/, [[:entries, 'cache added']]],
[ /(\d+) cookies sent$/, [ [ :entries, 'cookies sent' ] ] ], [/(\d+) cookies sent$/, [[:entries, 'cookies sent']]],
[ /(\d+) cookies received$/, [ [ :entries, 'cookies received' ] ] ], [/(\d+) cookies received$/, [[:entries, 'cookies received']]],
[ /(\d+) retransmitted$/, [ [ :entries, 'retransmitted' ] ] ], [/(\d+) retransmitted$/, [[:entries, 'retransmitted']]],
[ /(\d+) dupsyn$/, [ [ :entries, 'duplicates' ] ] ], [/(\d+) dupsyn$/, [[:entries, 'duplicates']]],
[ /(\d+) dropped$/, [ [ :entries, 'dropped' ] ] ], [/(\d+) dropped$/, [[:entries, 'dropped']]],
[ /(\d+) completed$/, [ [ :entries, 'completed' ] ] ], [/(\d+) completed$/, [[:entries, 'completed']]],
[ /(\d+) bucket overflow$/, [ [ :entries, 'bucket overflow' ] ] ], [/(\d+) bucket overflow$/, [[:entries, 'bucket overflow']]],
[ /(\d+) cache overflow$/, [ [ :entries, 'cache overflow' ] ] ], [/(\d+) cache overflow$/, [[:entries, 'cache overflow']]],
[ /(\d+) reset$/, [ [ :entries, 'reset' ] ] ], [/(\d+) reset$/, [[:entries, 'reset']]],
[ /(\d+) stale$/, [ [ :entries, 'stale' ] ] ], [/(\d+) stale$/, [[:entries, 'stale']]],
[ /(\d+) aborted$/, [ [ :entries, 'aborted' ] ] ], [/(\d+) aborted$/, [[:entries, 'aborted']]],
[ /(\d+) badack$/, [ [ :entries, 'bad ACK' ] ] ], [/(\d+) badack$/, [[:entries, 'bad ACK']]],
[ /(\d+) unreach$/, [ [ :entries, 'unreachable' ] ] ], [/(\d+) unreach$/, [[:entries, 'unreachable']]],
[ /(\d+) zone failures$/, [ [ :entries, 'zone failures' ] ] ], [/(\d+) zone failures$/, [[:entries, 'zone failures']]],
[ /(\d+) hostcache entries added$/, [ [ :entries, 'hostcache added' ] ] ], [/(\d+) hostcache entries added$/, [[:entries, 'hostcache added']]],
[ /(\d+) bucket overflow$/, [ [ :entries, 'hostcache overflow' ] ] ] [/(\d+) bucket overflow$/, [[:entries, 'hostcache overflow']]]
]), ]),
Graph.new('SACK', protocol, [ Graph.new('SACK', protocol, [
[ /(\d+) SACK recovery episodes$/, [ [ :packets, 'recovery episodes' ] ] ], [/(\d+) SACK recovery episodes$/, [[:packets, 'recovery episodes']]],
[ /(\d+) segment rexmits in SACK recovery episodes$/, [ [ :packets, 'segment rexmits' ] ] ], [/(\d+) segment rexmits in SACK recovery episodes$/, [[:packets, 'segment rexmits']]],
[ /(\d+) byte rexmits in SACK recovery episodes$/, [ [ :bytes, 'bytes rexmitted' ] ] ], [/(\d+) byte rexmits in SACK recovery episodes$/, [[:bytes, 'bytes rexmitted']]],
[ /(\d+) SACK options \(SACK blocks\) received$/, [ [ :packets, 'options blocks rcvd' ] ] ], [/(\d+) SACK options \(SACK blocks\) received$/, [[:packets, 'options blocks rcvd']]],
[ /(\d+) SACK options \(SACK blocks\) sent$/, [ [ :packets, 'options blocks sent' ] ] ], [/(\d+) SACK options \(SACK blocks\) sent$/, [[:packets, 'options blocks sent']]],
[ /(\d+) SACK scoreboard overflow$/, [ [ :packets, 'scoreboard overflow' ] ] ] [/(\d+) SACK scoreboard overflow$/, [[:packets, 'scoreboard overflow']]]
]), ]),
Graph.new('ECN', protocol, [ Graph.new('ECN', protocol, [
[ /(\d+) packets with ECN CE bit set$/, [ [ :packets, 'CE bit' ] ] ], [/(\d+) packets with ECN CE bit set$/, [[:packets, 'CE bit']]],
[ /(\d+) packets with ECN ECT\(0\) bit set$/, [ [ :packets, 'ECT(0) bit' ] ] ], [/(\d+) packets with ECN ECT\(0\) bit set$/, [[:packets, 'ECT(0) bit']]],
[ /(\d+) packets with ECN ECT\(1\) bit set$/, [ [ :packets, 'ECT(1) bit' ] ] ], [/(\d+) packets with ECN ECT\(1\) bit set$/, [[:packets, 'ECT(1) bit']]],
[ /(\d+) successful ECN handshakes$/, [ [ :packets, 'successful handshakes' ] ] ], [/(\d+) successful ECN handshakes$/, [[:packets, 'successful handshakes']]],
[ /(\d+) times ECN reduced the congestion window$/, [ [ :packets, 'congestion window reduced' ] ] ] [/(\d+) times ECN reduced the congestion window$/, [[:packets, 'congestion window reduced']]]
]) ])
] ]
when 'udp' when 'udp'
$os == :linux ? [ $os == :linux ? [] : [
] : [ Graph.new('received', protocol, [
Graph.new('received', protocol, [ [/(\d+) datagrams received$/, [[:packets, 'total']]],
[ /(\d+) datagrams received$/, [ [ :packets, 'total' ] ] ], [/(\d+) with incomplete header$/, [[:packets, 'incomplete header']]],
[ /(\d+) with incomplete header$/, [ [ :packets, 'incomplete header' ] ] ], [/(\d+) with bad data length field$/, [[:packets, 'bad data length field']]],
[ /(\d+) with bad data length field$/, [ [ :packets, 'bad data length field' ] ] ], [/(\d+) with bad checksum$/, [[:packets, 'bad checksum']]],
[ /(\d+) with bad checksum$/, [ [ :packets, 'bad checksum' ] ] ], [/(\d+) with no checksum$/, [[:packets, 'no checksum']]],
[ /(\d+) with no checksum$/, [ [ :packets, 'no checksum' ] ] ], [/(\d+) dropped due to no socket$/, [[:packets, 'dropped: no socket']]],
[ /(\d+) dropped due to no socket$/, [ [ :packets, 'dropped: no socket' ] ] ], [/(\d+) broadcast\/multicast datagrams undelivered$/, [[:packets, '*cast undelivered']]],
[ /(\d+) broadcast\/multicast datagrams undelivered$/, [ [ :packets, '*cast undelivered' ] ] ], [/(\d+) dropped due to full socket buffers$/, [[:packets, 'dropped: no buffers']]],
[ /(\d+) dropped due to full socket buffers$/, [ [ :packets, 'dropped: no buffers' ] ] ], [/(\d+) not for hashed pcb$/, [[:packets, 'not for hashed pcb']]],
[ /(\d+) not for hashed pcb$/, [ [ :packets, 'not for hashed pcb' ] ] ], [/(\d+) delivered$/, [[:packets, 'delivered']]]
[ /(\d+) delivered$/, [ [ :packets, 'delivered' ] ] ] ]),
]),
Graph.new('sent', protocol, [ Graph.new('sent', protocol, [
[ /(\d+) datagrams output$/, [ [ :packets, 'total' ] ] ], [/(\d+) datagrams output$/, [[:packets, 'total']]],
[ /(\d+) times multicast source filter matched$/, [ [ :packets, 'multicast src filter match' ] ] ] [/(\d+) times multicast source filter matched$/, [[:packets, 'multicast src filter match']]]
]) ])
] ]
when 'ip' when 'ip'
$os == :linux ? [ $os == :linux ? [] : [
] : [ Graph.new('received', protocol, [
Graph.new('received', protocol, [ [/(\d+) total packets received$/, [[:packets, 'total']]],
[ /(\d+) total packets received$/, [ [ :packets, 'total' ] ] ], [/(\d+) bad header checksums$/, [[:packets, 'bad header checksum']]],
[ /(\d+) bad header checksums$/, [ [ :packets, 'bad header checksum' ] ] ], [/(\d+) with size smaller than minimum$/, [[:packets, 'size smaller than min']]],
[ /(\d+) with size smaller than minimum$/, [ [ :packets, 'size smaller than min' ] ] ], [/(\d+) with data size < data length$/, [[:packets, 'data size < data length']]],
[ /(\d+) with data size < data length$/, [ [ :packets, 'data size < data length' ] ] ], [/(\d+) with ip length > max ip packet size$/, [[:packets, 'ip length > max ip packet sz']]],
[ /(\d+) with ip length > max ip packet size$/, [ [ :packets, 'ip length > max ip packet sz' ] ] ], [/(\d+) with header length < data size$/, [[:packets, 'header length < data size']]],
[ /(\d+) with header length < data size$/, [ [ :packets, 'header length < data size' ] ] ], [/(\d+) with data length < header length$/, [[:packets, 'data length < header length']]],
[ /(\d+) with data length < header length$/, [ [ :packets, 'data length < header length' ] ] ], [/(\d+) with bad options$/, [[:packets, 'bad options']]],
[ /(\d+) with bad options$/, [ [ :packets, 'bad options' ] ] ], [/(\d+) with incorrect version number$/, [[:packets, 'incorrect version']]],
[ /(\d+) with incorrect version number$/, [ [ :packets, 'incorrect version' ] ] ], [/(\d+) fragments? received$/, [[:packets, 'fragments']]],
[ /(\d+) fragments? received$/, [ [ :packets, 'fragments' ] ] ], [/(\d+) fragments? dropped \(dup or out of space\)$/, [[:packets, 'frags dropped: dup/out of spc']]],
[ /(\d+) fragments? dropped \(dup or out of space\)$/, [ [ :packets, 'frags dropped: dup/out of spc' ] ] ], [/(\d+) fragments? dropped after timeout$/, [[:packets, 'frags dropped: timeout']]],
[ /(\d+) fragments? dropped after timeout$/, [ [ :packets, 'frags dropped: timeout' ] ] ], [/(\d+) packets? reassembled ok$/, [[:packets, 'reassembled ok']]],
[ /(\d+) packets? reassembled ok$/, [ [ :packets, 'reassembled ok' ] ] ], [/(\d+) packets? for this host$/, [[:packets, 'for this host']]],
[ /(\d+) packets? for this host$/, [ [ :packets, 'for this host' ] ] ], [/(\d+) packets? for unknown\/unsupported protocol$/, [[:packets, 'for unknown/unsup protocol']]],
[ /(\d+) packets? for unknown\/unsupported protocol$/, [ [ :packets, 'for unknown/unsup protocol' ] ] ], [/(\d+) packets? forwarded \((\d+) packets fast forwarded\)$/, [[:packets, 'forwarded'], [:packets, 'fast forwarded']]],
[ /(\d+) packets? forwarded \((\d+) packets fast forwarded\)$/, [ [ :packets, 'forwarded' ], [ :packets, 'fast forwarded' ] ] ], [/(\d+) packets? not forwardable$/, [[:packets, 'not forwardable']]],
[ /(\d+) packets? not forwardable$/, [ [ :packets, 'not forwardable' ] ] ], [/(\d+) packets? received for unknown multicast group$/, [[:packets, 'unknown multicast grp']]]
[ /(\d+) packets? received for unknown multicast group$/, [ [ :packets, 'unknown multicast grp' ] ] ] ]),
]),
Graph.new('sent', protocol, [ Graph.new('sent', protocol, [
[ /(\d+) packets? sent from this host$/, [ [ :packets, 'total' ] ] ], [/(\d+) packets? sent from this host$/, [[:packets, 'total']]],
[ /(\d+) redirects? sent$/, [ [ :packets, 'redirect' ] ] ], [/(\d+) redirects? sent$/, [[:packets, 'redirect']]],
[ /(\d+) packets? sent with fabricated ip header$/, [ [ :packets, 'fabricated IP head' ] ] ], [/(\d+) packets? sent with fabricated ip header$/, [[:packets, 'fabricated IP head']]],
[ /(\d+) output packets? dropped due to no bufs, etc\.$/, [ [ :packets, 'dropped: no bufs, etc' ] ] ], [/(\d+) output packets? dropped due to no bufs, etc\.$/, [[:packets, 'dropped: no bufs, etc']]],
[ /(\d+) output packets? discarded due to no route$/, [ [ :packets, 'discarded: no route' ] ] ], [/(\d+) output packets? discarded due to no route$/, [[:packets, 'discarded: no route']]],
[ /(\d+) output datagrams? fragmented$/, [ [ :packets, 'fragmented' ] ] ], [/(\d+) output datagrams? fragmented$/, [[:packets, 'fragmented']]],
[ /(\d+) fragments? created$/, [ [ :packets, 'fragments created' ] ] ], [/(\d+) fragments? created$/, [[:packets, 'fragments created']]],
[ /(\d+) datagrams? that can't be fragmented$/, [ [ :packets, "can't be fragmented" ] ] ], [/(\d+) datagrams? that can't be fragmented$/, [[:packets, "can't be fragmented"]]],
[ /(\d+) tunneling packets? that can't find gif$/, [ [ :packets, 'tunneling, gif not found' ] ] ], [/(\d+) tunneling packets? that can't find gif$/, [[:packets, 'tunneling, gif not found']]],
[ /(\d+) datagrams? with bad address in header$/, [ [ :packets, 'bad address in header' ] ] ] [/(\d+) datagrams? with bad address in header$/, [[:packets, 'bad address in header']]]
]) ])
] ]
when 'arp' when 'arp'
$os == :linux ? [] : [ $os == :linux ? [] : [
Graph.new('packets', protocol, [ Graph.new('packets', protocol, [
# This is just a total, so ignore the value but keep regexp to avoid 'not parsed' warning. # This is just a total, so ignore the value but keep regexp to avoid 'not parsed' warning.
[ /(\d+) ARP packets? received$/ ], [/(\d+) ARP packets? received$/],
[ /(\d+) ARP requests? received$/, [ [ :packets, 'requests received' ] ] ], [/(\d+) ARP requests? received$/, [[:packets, 'requests received']]],
[ /(\d+) ARP repl(?:y|ies) received$/, [ [ :packets, 'replies received' ] ] ], [/(\d+) ARP repl(?:y|ies) received$/, [[:packets, 'replies received']]],
[ /(\d+) ARP requests? sent$/, [ [ :packets, 'requests', 'requests received' ] ] ], [/(\d+) ARP requests? sent$/, [[:packets, 'requests', 'requests received']]],
[ /(\d+) ARP repl(?:y|ies) sent$/, [ [ :packets, 'replies', 'replies received' ] ] ], [/(\d+) ARP repl(?:y|ies) sent$/, [[:packets, 'replies', 'replies received']]],
[ /(\d+) total packets? dropped due to no ARP entry$/, [ [ :packets, 'no entry' ] ] ] [/(\d+) total packets? dropped due to no ARP entry$/, [[:packets, 'no entry']]]
]), ]),
Graph.new('entries', protocol, [ Graph.new('entries', protocol, [
[ /(\d+) ARP entrys? timed out$/, [ [ :entries, 'timed out' ] ] ], [/(\d+) ARP entrys? timed out$/, [[:entries, 'timed out']]],
[ /(\d+) Duplicate IPs seen$/, [ [ :entries, 'duplicate IPs seen' ] ] ] [/(\d+) Duplicate IPs seen$/, [[:entries, 'duplicate IPs seen']]]
]) ])
] ]
end end
end end
proto_name = File.basename($0, '.*').escape proto_name = File.basename($0, '.*').escape
@ -374,31 +378,31 @@ proto_name.slice! 0, PLUGIN_NAME.size if proto_name.start_with? PLUGIN_NAME
proto_name = 'tcp' if proto_name.empty? proto_name = 'tcp' if proto_name.empty?
def netstat_s(protocol) def netstat_s(protocol)
if $os == :linux if $os == :linux
%w(tcp udp).include?(protocol) ? %w(tcp udp).include?(protocol) ?
`netstat -s --#{protocol}` : `netstat -s --#{protocol}` :
`netstat -s --raw` `netstat -s --raw`
else else
`netstat -sp #{protocol}` `netstat -sp #{protocol}`
end.lines.reject { |line| line =~ /^\w+:/ } end.lines.reject { |line| line =~ /^\w+:/ }
end end
case ARGV.first case ARGV.first
when 'autoconf' when 'autoconf'
puts [:linux, :freebsd].include?($os) ? 'yes' : 'no' puts [:linux, :freebsd].include?($os) ? 'yes' : 'no'
when 'suggest' when 'suggest'
puts $os == :linux ? %w(tcp) : %w(tcp udp ip arp) puts $os == :linux ? %w(tcp) : %w(tcp udp ip arp)
when 'config' when 'config'
graphs_for(proto_name).each { |graph| graphs_for(proto_name).each { |graph|
puts graph.config.join $/ puts graph.config.join $/
} }
else else
data = netstat_s(proto_name) data = netstat_s(proto_name)
graphs_for(proto_name).each { |graph| graphs_for(proto_name).each { |graph|
puts graph.fetch(data).join $/ puts graph.fetch(data).join $/
} }
warn "not parsed:\n#{data.join}" unless data.empty? if $debug_mode warn "not parsed:\n#{data.join}" unless data.empty? if $debug_mode
end end
# awful performance when scrolling through those regexps above # awful performance when scrolling through those regexps above

View File

@ -1,54 +1,59 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for PGA memory components monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for PGA memory components monitoring
# Date: 2011-05-13
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-13
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) env.ORACLE_HOME set in munin-node
# 2) rubygems Prerequistes:
# 3) oci8 - DBI gem for connecting to Oracle 1) env.ORACLE_HOME set in munin-node
# * instruction of installing oci8 is available here: 2) rubygems
# http://ruby-oci8.rubyforge.org/en/InstallBinaryPackage.html 3) oci8 - DBI gem for connecting to Oracle
# * instruction of installing oci8 is available here:
# Usage: http://ruby-oci8.rubyforge.org/en/InstallBinaryPackage.html
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/oracle_<sid>_pga.rb /etc/munin/plugins/oracle_<sid>_pga.rb 2) chmod to allow executable to others
# ** replace <sid> with your oralce sid 3) create symbolic link in /etc/munin/plugins
# ln -s /usr/share/munin/plugins/oracle_<sid>_pga.rb /etc/munin/plugins/oracle_<sid>_pga.rb
# Parameters: ** replace <sid> with your oralce sid
# autoconf
# config (required) Parameters:
# autoconf
# Configurable variables: config (required)
# orauser : oracle user who has select privilege to query v$pgastat view
# orapass : password for the oracle user Configurable variables:
# dbport : port used by the monitored instance (notice: numeric value) orauser : oracle user who has select privilege to query v$pgastat view
# dbname : database to be monitored orapass : password for the oracle user
# dbhost : host or ip address of db instance dbport : port used by the monitored instance (notice: numeric value)
# dbname : database to be monitored
# dbhost : host or ip address of db instance
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'oci8' require 'oci8'
@ -58,17 +63,16 @@ dbport = 1522
dbname = 'orcl' dbname = 'orcl'
dbhost = 'localhost' dbhost = 'localhost'
tnsname = "(DESCRIPTION = tnsname = "(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = #{dbhost})(PORT = #{dbport})) (ADDRESS = (PROTOCOL = TCP)(HOST = #{dbhost})(PORT = #{dbport}))
(CONNECT_DATA = (SID = #{dbname})))" (CONNECT_DATA = (SID = #{dbname})))"
def runQuery (name,query) def runQuery(name, query)
rows = $conn.exec(query) rows = $conn.exec(query)
puts "#{name}.value #{rows.fetch().to_s}" puts "#{name}.value #{rows.fetch().to_s}"
rows.close rows.close
end end
# #
# Queries # Queries
# #
@ -78,45 +82,44 @@ pga_target_query = "SELECT TO_CHAR(ROUND(decode(unit,'bytes',(value)/(1024*1024)
pga_query = "SELECT TO_CHAR(ROUND(decode(unit,'bytes',(value)/(1024*1024),value),2)) pga pga_query = "SELECT TO_CHAR(ROUND(decode(unit,'bytes',(value)/(1024*1024),value),2)) pga
from V$PGASTAT where name = 'total PGA inuse'" from V$PGASTAT where name = 'total PGA inuse'"
pga_components = { "pga_target" => pga_target_query, pga_components = { "pga_target" => pga_target_query,
"pga_in_use" => pga_query "pga_in_use" => pga_query }
}
# #
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if tnsname.length > 1 && orauser.length > 1 && orapass.length > 1 if tnsname.length > 1 && orauser.length > 1 && orapass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1024k -r --lower-limit 0" puts "graph_args --base 1024k -r --lower-limit 0"
puts "graph_title Oracle PGA from #{dbname}" puts "graph_title Oracle PGA from #{dbname}"
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows the PGA memory usage (in MB)" puts "graph_info This graph shows the PGA memory usage (in MB)"
puts "graph_vlabel MB" puts "graph_vlabel MB"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
pga_components.keys.each do |p| pga_components.keys.each do |p|
puts "#{p}.label #{p}" puts "#{p}.label #{p}"
puts "#{p}.info PGA: #{p}" puts "#{p}.info PGA: #{p}"
puts "#{p}.type GAUGE" puts "#{p}.type GAUGE"
puts "#{p}.draw LINE1" puts "#{p}.draw LINE1"
end end
exit 0 exit 0
end end
$conn = OCI8.new(orauser, orapass, tnsname) $conn = OCI8.new(orauser, orapass, tnsname)
pga_components.each do |pc, query| pga_components.each do |pc, query|
runQuery(pc, query) runQuery(pc, query)
end end
$conn.logoff $conn.logoff

View File

@ -1,53 +1,58 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
#
# Munin Plugin for SGA memory components monitoring =begin
#
# Author: Wilfred Chau <openapp.developer@gmail.com> Munin Plugin for SGA memory components monitoring
# Date: 2011-05-12
# Version: 1.0 Author: Wilfred Chau <openapp.developer@gmail.com>
# Date: 2011-05-12
# This program is free software; you can redistribute it and/or modify Version: 1.0
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation. This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# This program is distributed in the hope that it will be useful, as published by the Free Software Foundation.
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the This program is distributed in the hope that it will be useful,
# GNU General Public License for more details. but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# You should have received a copy of the GNU General Public License along GNU General Public License for more details.
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Prerequistes:
# 1) env.ORACLE_HOME set in munin-node
# 2) rubygems Prerequistes:
# 3) oci8 - DBI gem for connecting to Oracle 1) env.ORACLE_HOME set in munin-node
# * instruction of installing oci8 is available here: 2) rubygems
# http://ruby-oci8.rubyforge.org/en/InstallBinaryPackage.html 3) oci8 - DBI gem for connecting to Oracle
# * instruction of installing oci8 is available here:
# Usage: http://ruby-oci8.rubyforge.org/en/InstallBinaryPackage.html
# 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# 2) chmod to allow executable to others Usage:
# 3) create symbolic link in /etc/munin/plugins 1) copy this script to the munin install plugins directory (e.g. /usr/share/munin/plugins)
# ln -s /usr/share/munin/plugins/oracle_orcl_sga.rb /etc/munin/plugins/oracle_orcl_sga.rb 2) chmod to allow executable to others
# 3) create symbolic link in /etc/munin/plugins
# Parameters: ln -s /usr/share/munin/plugins/oracle_orcl_sga.rb /etc/munin/plugins/oracle_orcl_sga.rb
# autoconf
# config (required) Parameters:
# autoconf
# Configurable variables: config (required)
# orauser : oracle user who has select privilege to query v$sgastat view
# orapass : password for the oracle user Configurable variables:
# dbport : port used by the monitored instance (notice: numeric value) orauser : oracle user who has select privilege to query v$sgastat view
# dbname : database to be monitored orapass : password for the oracle user
# dbhost : host or ip address of db instance dbport : port used by the monitored instance (notice: numeric value)
# dbname : database to be monitored
# dbhost : host or ip address of db instance
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
require 'rubygems' require 'rubygems'
require 'oci8' require 'oci8'
@ -57,17 +62,16 @@ dbport = 1522
dbname = 'orcl' dbname = 'orcl'
dbhost = 'localhost' dbhost = 'localhost'
tnsname = "(DESCRIPTION = tnsname = "(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = #{dbhost})(PORT = #{dbport})) (ADDRESS = (PROTOCOL = TCP)(HOST = #{dbhost})(PORT = #{dbport}))
(CONNECT_DATA = (SID = #{dbname})))" (CONNECT_DATA = (SID = #{dbname})))"
def runQuery (name,query) def runQuery(name, query)
rows = $conn.exec(query) rows = $conn.exec(query)
puts "#{name}.value #{rows.fetch().to_s}" puts "#{name}.value #{rows.fetch().to_s}"
rows.close rows.close
end end
# #
# Queries # Queries
# #
@ -98,56 +102,54 @@ log_buffer_query = "SELECT TO_CHAR(ROUND(SUM(decode(pool, NULL,
decode(name, 'log_buffer', (bytes)/(1024*1024),0),0)),2)) sga_lbuffer decode(name, 'log_buffer', (bytes)/(1024*1024),0),0)),2)) sga_lbuffer
from V$SGASTAT" from V$SGASTAT"
memory_components = { "fixed_area" => fixed_area_query,
memory_components = { "fixed_area" => fixed_area_query,
"buffer_cache" => buffer_cache_query, "buffer_cache" => buffer_cache_query,
"java_pool" => java_pool_query, "java_pool" => java_pool_query,
"large_pool" => large_pool_query, "large_pool" => large_pool_query,
"log_buffer" => log_buffer_query, "log_buffer" => log_buffer_query,
"shared_pool" => shared_pool_query "shared_pool" => shared_pool_query }
}
# #
# autoconf # autoconf
# #
if ARGV[0] == "autoconf" if ARGV[0] == "autoconf"
if tnsname.length > 1 && orauser.length > 1 && orapass.length > 1 if tnsname.length > 1 && orauser.length > 1 && orapass.length > 1
puts "yes" puts "yes"
else else
puts "no" puts "no"
puts "Usage: #{__FILE__} autoconf|conf" puts "Usage: #{__FILE__} autoconf|conf"
end end
exit 0 exit 0
# #
# config definition # config definition
# #
elsif ARGV[0] == "config" elsif ARGV[0] == "config"
puts "graph_args --base 1024k -r --lower-limit 0" puts "graph_args --base 1024k -r --lower-limit 0"
puts "graph_title Oracle SGA from #{dbname}" puts "graph_title Oracle SGA from #{dbname}"
puts "graph_category db" puts "graph_category db"
puts "graph_info This graph shows the SGA memory usage (in MB)" puts "graph_info This graph shows the SGA memory usage (in MB)"
puts "graph_vlabel MB" puts "graph_vlabel MB"
puts "graph_scale no" puts "graph_scale no"
puts "graph_period second" puts "graph_period second"
memory_components.keys.each do |m| memory_components.keys.each do |m|
puts "#{m}.label #{m}" puts "#{m}.label #{m}"
puts "#{m}.info SGA: #{m}" puts "#{m}.info SGA: #{m}"
puts "#{m}.type GAUGE" puts "#{m}.type GAUGE"
# make sure fixed_area is at the bottom of the stack # make sure fixed_area is at the bottom of the stack
if ( m == 'fixed_area' ) if (m == 'fixed_area')
puts "#{m}.draw AREA" puts "#{m}.draw AREA"
else else
puts "#{m}.draw STACK" puts "#{m}.draw STACK"
end end
end end
exit 0 exit 0
end end
$conn = OCI8.new(orauser, orapass, tnsname) $conn = OCI8.new(orauser, orapass, tnsname)
memory_components.each do |mc, query| memory_components.each do |mc, query|
runQuery(mc, query) runQuery(mc, query)
end end
$conn.logoff $conn.logoff

View File

@ -14,18 +14,17 @@ require 'mysql'
require 'yaml' require 'yaml'
class Grapher class Grapher
def initialize(db_conf) def initialize(db_conf)
@db_conf = db_conf @db_conf = db_conf
end end
def config def config
puts <<-END_CONFIG puts <<~END_CONFIG
graph_title Delayed_Jobs Queue Size graph_title Delayed_Jobs Queue Size
graph_args -l 0 graph_args -l 0
graph_vlabel jobs to be run graph_vlabel jobs to be run
jobs.label jobs jobs.label jobs
jobs.type GAUGE jobs.type GAUGE
END_CONFIG END_CONFIG
end end
@ -39,7 +38,6 @@ jobs.type GAUGE
value = result.fetch_hash.values.first value = result.fetch_hash.values.first
puts "jobs.value #{value}" puts "jobs.value #{value}"
end end
end end
if __FILE__ == $0 if __FILE__ == $0

View File

@ -15,64 +15,62 @@
require 'rubygems' require 'rubygems'
require 'munin' require 'munin'
SERVICE = $0.split( '_' ).last SERVICE = $0.split('_').last
SERVICE_F = '/etc/services' SERVICE_F = '/etc/services'
PORT = /^[\d]+(\.[\d]+){0,1}$/ === SERVICE ? SERVICE : %x[grep #{SERVICE} #{SERVICE_F}].split( "\t\t" )[1].split( '/' )[0] PORT = /^[\d]+(\.[\d]+){0,1}$/ === SERVICE ? SERVICE : %x[grep #{SERVICE} #{SERVICE_F}].split("\t\t")[1].split('/')[0]
class PortMonit < Munin::Plugin class PortMonit < Munin::Plugin
graph_attributes "#{SERVICE} port usage, known as #{PORT}", graph_attributes "#{SERVICE} port usage, known as #{PORT}",
:category => 'network', :category => 'network',
:info => 'This graph shows connection split by the state of the socket.', :info => 'This graph shows connection split by the state of the socket.',
:vlabel => 'Current connections' :vlabel => 'Current connections'
declare_field :ESTABLISHED, declare_field :ESTABLISHED,
:label => 'Established', :draw => :AREA, :label => 'Established', :draw => :AREA,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :CLOSE_WAIT, declare_field :CLOSE_WAIT,
:label => 'Waiting close', :draw => :STACK, :label => 'Waiting close', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :TIME_WAIT, declare_field :TIME_WAIT,
:label => 'Waiting after close', :draw => :STACK, :label => 'Waiting after close', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :CLOSING, declare_field :CLOSING,
:label => 'Closing', :draw => :STACK, :label => 'Closing', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :LAST_ACK, declare_field :LAST_ACK,
:label => 'Waiting for acknowledgement', :draw => :STACK, :label => 'Waiting for acknowledgement', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :FIN_WAIT_1, declare_field :FIN_WAIT_1,
:label => 'Socket closed, connection shutting down', :draw => :STACK, :label => 'Socket closed, connection shutting down', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
declare_field :FIN_WAIT_2, declare_field :FIN_WAIT_2,
:label => 'Connection closed, Socket still waiting', :draw => :STACK, :label => 'Connection closed, Socket still waiting', :draw => :STACK,
:type => :GAUGE, :min => 0 :type => :GAUGE, :min => 0
def retrieve_values def retrieve_values
@_netstat = %x[netstat -n -P tcp | egrep "\.#{PORT} "].split("\n")
@_netstat = %x[netstat -n -P tcp | egrep "\.#{PORT} "].split( "\n" ) { :ESTABLISHED => count(@_netstat, 'ESTABLISHED'),
:CLOSE_WAIT => count(@_netstat, 'CLOSE_WAIT'),
:CLOSING => count(@_netstat, 'CLOSING'),
{ :ESTABLISHED => count( @_netstat, 'ESTABLISHED' ), :LAST_ACK => count(@_netstat, 'LAST_ACK'),
:CLOSE_WAIT => count( @_netstat, 'CLOSE_WAIT' ), :FIN_WAIT_1 => count(@_netstat, 'FIN_WAIT_1'),
:CLOSING => count( @_netstat, 'CLOSING' ), :FIN_WAIT_2 => count(@_netstat, 'FIN_WAIT_2'),
:LAST_ACK => count( @_netstat, 'LAST_ACK' ), :TIME_WAIT => count(@_netstat, 'TIME_WAIT') }
:FIN_WAIT_1 => count( @_netstat, 'FIN_WAIT_1' ),
:FIN_WAIT_2 => count( @_netstat, 'FIN_WAIT_2' ),
:TIME_WAIT => count( @_netstat, 'TIME_WAIT' ) }
end end
private private
def count( source, regex )
def count(source, regex)
@_result = 0 @_result = 0
source.each { |obj| @_result += 1 if obj.match( regex ) } source.each { |obj| @_result += 1 if obj.match(regex) }
return @_result return @_result
end end

View File

@ -24,10 +24,10 @@ passenger_rss = nil
`#{memory_stats_command}`.each_line do |line| `#{memory_stats_command}`.each_line do |line|
next unless /### Total private dirty RSS: (\d+\.\d+) MB/.match(line) next unless /### Total private dirty RSS: (\d+\.\d+) MB/.match(line)
passenger_rss = $~[1] unless apache_rss.nil? passenger_rss = $~[1] unless apache_rss.nil?
apache_rss ||= $~[1] apache_rss ||= $~[1]
end end
puts "apache_rss.value #{apache_rss}" puts "apache_rss.value #{apache_rss}"
puts "passenger_rss.value #{passenger_rss}" puts "passenger_rss.value #{passenger_rss}"

View File

@ -39,4 +39,3 @@ puts "max.value #{max}"
puts "count.value #{count}" puts "count.value #{count}"
puts "active.value #{active}" puts "active.value #{active}"
puts "queued.value #{queued.to_i}" puts "queued.value #{queued.to_i}"

View File

@ -1,27 +1,27 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
def output_config def output_config
puts <<-END puts <<~END
graph_category webserver graph_category webserver
graph_title status graph_title status
graph_vlabel count graph_vlabel count
graph_info This graph shows how much passenger process are working, available and how much queries are waiting. graph_info This graph shows how much passenger process are working, available and how much queries are waiting.
max.label max processes max.label max processes
max.draw AREA max.draw AREA
max.info Maximum processes allowed to run simultaneously. max.info Maximum processes allowed to run simultaneously.
sessions.label queued requests sessions.label queued requests
sessions.draw LINE2 sessions.draw LINE2
sessions.info Requests queued, waiting to be processed. sessions.info Requests queued, waiting to be processed.
running.label running processes running.label running processes
running.draw LINE1 running.draw LINE1
running.info The number of application instances that are currently alive. running.info The number of application instances that are currently alive.
active.label active processes active.label active processes
active.draw LINE1 active.draw LINE1
active.info The number of application instances that are currently processing requests. active.info The number of application instances that are currently processing requests.
waiting.label waiting requests waiting.label waiting requests
waiting.draw LINE2 waiting.draw LINE2
waiting.info Requests waiting to be queued. waiting.info Requests waiting to be queued.
END END
exit 0 exit 0
end end

View File

@ -31,7 +31,7 @@ user = ENV['user'] || 'user'
pwd = ENV['password'] || 'password' pwd = ENV['password'] || 'password'
url = ENV['url'] || 'http://127.0.0.1/control.php' url = ENV['url'] || 'http://127.0.0.1/control.php'
if ARGV[0]=="config" if ARGV[0] == "config"
print "EAccelerator Monitoring\n" print "EAccelerator Monitoring\n"
print "graph_title PHP Eaccelerator\n" print "graph_title PHP Eaccelerator\n"
print "graph_category webserver\n" print "graph_category webserver\n"
@ -47,58 +47,56 @@ if ARGV[0]=="config"
exit exit
end end
one_liners=0 one_liners = 0
three_liners=0 three_liners = 0
key="" key = ""
open(url, :http_basic_authentication=>[user, pwd]) do |f| open(url, :http_basic_authentication => [user, pwd]) do |f|
f.each do |line| f.each do |line|
if three_liners>0 if three_liners > 0
three_liners=three_liners+1 three_liners = three_liners + 1
if three_liners==2 if three_liners == 2
print "Memoryusagepercentage.value " print "Memoryusagepercentage.value "
end end
if three_liners==3 if three_liners == 3
print "Memoryusage.value " print "Memoryusage.value "
end end
if three_liners==4 if three_liners == 4
print "Memorymax.value " print "Memorymax.value "
end end
print line.gsub!(/[^0-9.]/s,"") print line.gsub!(/[^0-9.]/s, "")
print "\n" print "\n"
end end
if one_liners>0 if one_liners > 0
one_liners=one_liners+1 one_liners = one_liners + 1
print "#{key}.value " print "#{key}.value "
print line.gsub!(/[^0-9.]/s,"") print line.gsub!(/[^0-9.]/s, "")
print "\n" print "\n"
end end
if one_liners>1 if one_liners > 1
line="" line = ""
one_liners=0 one_liners = 0
end end
if three_liners>3 if three_liners > 3
line="" line = ""
three_liners=0 three_liners = 0
end end
if line =~ /Memory usage/ if line =~ /Memory usage/
key=line.gsub!(/(<[^>]*>)|\n|\t| /s,"") key = line.gsub!(/(<[^>]*>)|\n|\t| /s, "")
three_liners=three_liners+1 three_liners = three_liners + 1
end end
if line =~ /<td class="e">Free memory/ || line =~ /<td class="e">Cached scripts/ || line =~ /<td class="e">Removed scripts/ || line =~ /<td class="e">Cached keys/ if line =~ /<td class="e">Free memory/ || line =~ /<td class="e">Cached scripts/ || line =~ /<td class="e">Removed scripts/ || line =~ /<td class="e">Cached keys/
key=line.gsub!(/(<[^>]*>)|\n|\t| /s,"") key = line.gsub!(/(<[^>]*>)|\n|\t| /s, "")
one_liners=one_liners+1 one_liners = one_liners + 1
end end
end end
end end

View File

@ -1,51 +1,56 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# munin plugin to retrieve connection statistics from the web admin interface
# on a Linksys AG241v2 ADSL modem
# Makes use of the http://modemaddress/ADSLCStatus.htm page
#This plugin has only been tested on a Debian testing system =begin
# This modem also has some basic SNMP support so you can configure it munin plugin to retrieve connection statistics from the web admin interface
# as per the instructions on the munin wiki on a Linksys AG241v2 ADSL modem
# http://munin.projects.linpro.no/wiki/Using_SNMP_plugins Makes use of the http://modemaddress/ADSLCStatus.htm page
# By default the SNMP server is disabled, you can enable it in the web admin
# You will need to set up the "virtual node" configuration as detailed
# for snmp plugins
# Plugin will require some configuration in /etc/munin/plugin-conf.d/ag241_MODEMADDRESS This plugin has only been tested on a Debian testing system
# e.g.
# [ag241_vocume.stargate_*]
# env.user admin
# env.pass password
# #env.port 80
# Once you have the above config set you will need to symlink the plugin to This modem also has some basic SNMP support so you can configure it
# /etc/munin/plugins/ag241_MODEMADDRESS_syncrate as per the instructions on the munin wiki
# /etc/munin/plugins/ag241_MODEMADDRESS_attenutation http://munin.projects.linpro.no/wiki/Using_SNMP_plugins
# /etc/munin/plugins/ag241_MODEMADDRESS_noise By default the SNMP server is disabled, you can enable it in the web admin
# now restart munin-node. You will need to set up the "virtual node" configuration as detailed
# hopefully in 20-30mins you will have some nice graphs for snmp plugins
Plugin will require some configuration in /etc/munin/plugin-conf.d/ag241_MODEMADDRESS
e.g.
[ag241_vocume.stargate_*]
env.user admin
env.pass password
#env.port 80
#Some magical munin foo... Once you have the above config set you will need to symlink the plugin to
/etc/munin/plugins/ag241_MODEMADDRESS_syncrate
/etc/munin/plugins/ag241_MODEMADDRESS_attenutation
/etc/munin/plugins/ag241_MODEMADDRESS_noise
now restart munin-node.
hopefully in 20-30mins you will have some nice graphs
Some magical munin foo...
#%# family=manual #%# family=manual
#%# capabilities= #%# capabilities=
=end
# Require this module, it is part of the standard ruby lib AFAIK # Require this module, it is part of the standard ruby lib AFAIK
require 'net/http' require 'net/http'
#default parameters # default parameters
host = nil host = nil
port = ENV['port'] || 80 port = ENV['port'] || 80
user = ENV['user'] || 'admin' user = ENV['user'] || 'admin'
pass = ENV['pass'] || 'forhax' #don't remember what the default admin password was pass = ENV['pass'] || 'forhax' # don't remember what the default admin password was
stat = nil stat = nil
# Check executable "name" for parameter count # Check executable "name" for parameter count
params = $0.split('_') params = $0.split('_')
if params.size != 3 if params.size != 3
puts "Incorrect number of parameters" puts "Incorrect number of parameters"
exit 1 exit 1
end end
# first param after the plugin name is the host to query # first param after the plugin name is the host to query
@ -54,79 +59,79 @@ host = params[1]
stat = params[2] stat = params[2]
unless ENV['debug'].nil? unless ENV['debug'].nil?
puts "user = "+ user puts "user = " + user
puts "pass = "+ pass puts "pass = " + pass
puts "host = "+ host puts "host = " + host
puts "port = "+ port puts "port = " + port
puts "stat = "+ stat puts "stat = " + stat
end end
# Dump the graph configuration data # Dump the graph configuration data
if ARGV[0] == 'config' if ARGV[0] == 'config'
puts 'host_name ' + host puts 'host_name ' + host
puts 'graph_category network' puts 'graph_category network'
case stat case stat
when 'syncrate' when 'syncrate'
puts 'graph_info This graph shows the ADSL line sync rate.' puts 'graph_info This graph shows the ADSL line sync rate.'
puts 'graph_title ADSL line sync rate' puts 'graph_title ADSL line sync rate'
puts 'graph_vlabel connection rate bits / second' puts 'graph_vlabel connection rate bits / second'
puts 'graph_args --base 1000 -l 0 ' puts 'graph_args --base 1000 -l 0 '
when 'attenuation' when 'attenuation'
puts 'graph_info This graph shows the ADSL line attenuation.' puts 'graph_info This graph shows the ADSL line attenuation.'
puts 'graph_title ADSL line attenuation' puts 'graph_title ADSL line attenuation'
puts 'graph_vlabel attenuation dB' puts 'graph_vlabel attenuation dB'
when 'margin','noise' when 'margin', 'noise'
puts 'graph_info This graph shows the ADSL SNR margin.' puts 'graph_info This graph shows the ADSL SNR margin.'
puts 'graph_title ADSL line SNR margin' puts 'graph_title ADSL line SNR margin'
puts 'graph_vlabel noise margin dB' puts 'graph_vlabel noise margin dB'
end end
puts 'down.label downstream' puts 'down.label downstream'
puts 'up.label upstream' puts 'up.label upstream'
exit 0 exit 0
end end
# Connect to the webadmin # Connect to the webadmin
http = Net::HTTP.start(host,port) http = Net::HTTP.start(host, port)
req = Net::HTTP::Get.new('/ADSLCStatus.htm') req = Net::HTTP::Get.new('/ADSLCStatus.htm')
# send the login info # send the login info
req.basic_auth user, pass req.basic_auth user, pass
response = http.request(req) response = http.request(req)
s = response.body s = response.body
#Make sure we got the page successfully # Make sure we got the page successfully
if response.code != '200' if response.code != '200'
puts "Getting web page failed:" puts "Getting web page failed:"
case response.code case response.code
when '401' when '401'
puts 'Probably because the username and password are incorrect' puts 'Probably because the username and password are incorrect'
#Looks like the modem response with 200 when you try to access a page that does not exist >_> # Looks like the modem response with 200 when you try to access a page that does not exist >_>
#when '404' # when '404'
# puts 'Looks like the page this plugin needs isn\'t available...' # puts 'Looks like the page this plugin needs isn\'t available...'
# puts 'Check your modem make/model/version' # puts 'Check your modem make/model/version'
end end
puts s puts s
exit 1 exit 1
end end
# Apply voodoo regex to the result HTML to get the data we want. # Apply voodoo regex to the result HTML to get the data we want.
case stat case stat
when 'syncrate' when 'syncrate'
a = s.scan(/.*share\.curstate.*\n.*share\.downstr[^0-9]*([0-9]+).*share\.upstr[^0-9]*([0-9]+).*$/) a = s.scan(/.*share\.curstate.*\n.*share\.downstr[^0-9]*([0-9]+).*share\.upstr[^0-9]*([0-9]+).*$/)
b,c = a[0] b, c = a[0]
puts 'down.value '+ (b.to_i*1000).to_s + "\n" + 'up.value '+ (c.to_i*1000).to_s puts 'down.value ' + (b.to_i * 1000).to_s + "\n" + 'up.value ' + (c.to_i * 1000).to_s
exit 0 exit 0
when 'attenuation' when 'attenuation'
a = s.scan(/.*share\.lineatt.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/) a = s.scan(/.*share\.lineatt.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/)
b,c = a[0] b, c = a[0]
puts 'down.value '+ (b.to_i).to_s + "\n" + 'up.value '+ (c.to_i).to_s puts 'down.value ' + (b.to_i).to_s + "\n" + 'up.value ' + (c.to_i).to_s
exit 0 exit 0
when 'margin','noise' when 'margin', 'noise'
a = s.scan(/.*share\.noise.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/) a = s.scan(/.*share\.noise.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/)
b,c = a[0] b, c = a[0]
puts 'down.value '+ (b.to_i).to_s + "\n" + 'up.value '+ (c.to_i).to_s puts 'down.value ' + (b.to_i).to_s + "\n" + 'up.value ' + (c.to_i).to_s
exit 0 exit 0
else else
puts 'Statistic ' + stat.to_s + ' not known, would you like me to fabricate it for you?' puts 'Statistic ' + stat.to_s + ' not known, would you like me to fabricate it for you?'
exit 1 exit 1
end end

View File

@ -31,7 +31,6 @@ require 'mechanize'
require 'digest/md5' require 'digest/md5'
require 'nokogiri' require 'nokogiri'
def output def output
nics = Hash.new nics = Hash.new
nics["LAN"] = Hash.new nics["LAN"] = Hash.new
@ -80,7 +79,7 @@ def output
j = 0 j = 0
doc = Nokogiri::XML(clients_xml.to_s) doc = Nokogiri::XML(clients_xml.to_s)
doc.xpath('//assoc').each do |assoc| doc.xpath('//assoc').each do |assoc|
j+=1 j += 1
end end
puts "wifi_assoc.value " + j.to_s puts "wifi_assoc.value " + j.to_s
@ -89,7 +88,7 @@ def output
j = 0 j = 0
doc = Nokogiri::XML(clients_xml.to_s) doc = Nokogiri::XML(clients_xml.to_s)
doc.xpath('//client').each do |client| doc.xpath('//client').each do |client|
j+=1 j += 1
end end
puts "dhcp_clients.value " + j.to_s puts "dhcp_clients.value " + j.to_s
@ -98,31 +97,31 @@ def output
clients_xml = agent.get("#{router_path}/wan_connection_status.xml").body clients_xml = agent.get("#{router_path}/wan_connection_status.xml").body
doc = Nokogiri::XML(clients_xml.to_s) doc = Nokogiri::XML(clients_xml.to_s)
uptime = doc.children.search('wan_interface_up_time_0')[0].text uptime = doc.children.search('wan_interface_up_time_0')[0].text
puts "uptime.value " + sprintf( "%.2f", (Float(uptime)/86400) ) puts "uptime.value " + sprintf("%.2f", (Float(uptime) / 86400))
# graph overall interface packets transferred per interval # graph overall interface packets transferred per interval
puts "multigraph if_packets" puts "multigraph if_packets"
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_recv.value " + nics[i]["packets_received"] puts "#{i}_recv.value " + nics[i]["packets_received"]
puts "#{i}_send.value " + nics[i]["packets_sent"] puts "#{i}_send.value " + nics[i]["packets_sent"]
end end
# graph overall interface dropped packets per interval # graph overall interface dropped packets per interval
puts "multigraph if_drop" puts "multigraph if_drop"
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_recv.value " + nics[i]["rx_dropped"] puts "#{i}_recv.value " + nics[i]["rx_dropped"]
puts "#{i}_send.value " + nics[i]["tx_dropped"] puts "#{i}_send.value " + nics[i]["tx_dropped"]
end end
# graph overall interface collisions & errors per interval # graph overall interface collisions & errors per interval
puts "multigraph if_collerr" puts "multigraph if_collerr"
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_coll.value " + nics[i]["tx_collisions"] puts "#{i}_coll.value " + nics[i]["tx_collisions"]
puts "#{i}_err.value " + nics[i]["rx_errors"] puts "#{i}_err.value " + nics[i]["rx_errors"]
end end
# graph stats for each interface # graph stats for each interface
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "multigraph if_packets.#{i}" puts "multigraph if_packets.#{i}"
puts "send.value " + nics[i]["packets_sent"] puts "send.value " + nics[i]["packets_sent"]
puts "recv.value " + nics[i]["packets_received"] puts "recv.value " + nics[i]["packets_received"]
@ -135,7 +134,6 @@ def output
end end
end end
def config def config
# build the configuration for graphs # build the configuration for graphs
puts "multigraph if_packets" puts "multigraph if_packets"
@ -143,7 +141,7 @@ def config
puts 'graph_category network' puts 'graph_category network'
puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send' puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send'
puts 'graph_vlabel packets in (-) / out (+) per ${graph_period}' puts 'graph_vlabel packets in (-) / out (+) per ${graph_period}'
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_recv.type DERIVE" puts "#{i}_recv.type DERIVE"
puts "#{i}_recv.graph no" puts "#{i}_recv.graph no"
puts "#{i}_recv.min 0" puts "#{i}_recv.min 0"
@ -158,7 +156,7 @@ def config
puts 'graph_category network' puts 'graph_category network'
puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send' puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send'
puts 'graph_vlabel packets / ${graph_period}' puts 'graph_vlabel packets / ${graph_period}'
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_recv.type DERIVE" puts "#{i}_recv.type DERIVE"
puts "#{i}_recv.graph no" puts "#{i}_recv.graph no"
puts "#{i}_recv.min 0" puts "#{i}_recv.min 0"
@ -173,7 +171,7 @@ def config
puts 'graph_category network' puts 'graph_category network'
puts 'graph_order LAN_coll LAN_err WAN_coll WAN_err WLAN_coll WLAN_coll' puts 'graph_order LAN_coll LAN_err WAN_coll WAN_err WLAN_coll WLAN_coll'
puts 'graph_vlabel packets / ${graph_period}' puts 'graph_vlabel packets / ${graph_period}'
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "#{i}_coll.label #{i} collisions" puts "#{i}_coll.label #{i} collisions"
puts "#{i}_coll.type DERIVE" puts "#{i}_coll.type DERIVE"
puts "#{i}_coll.min 0" puts "#{i}_coll.min 0"
@ -201,7 +199,7 @@ def config
puts 'uptime.label uptime' puts 'uptime.label uptime'
puts 'uptime.draw AREA' puts 'uptime.draw AREA'
for i in [ "LAN", "WAN", "WLAN" ] do for i in ["LAN", "WAN", "WLAN"] do
puts "multigraph if_packets.#{i}" puts "multigraph if_packets.#{i}"
puts "graph_title D-Link DIR-655 #{i} traffic" puts "graph_title D-Link DIR-655 #{i} traffic"
puts 'graph_category network' puts 'graph_category network'
@ -244,7 +242,6 @@ def config
end end
end end
# main # main
if ARGV.length == 1 and ARGV[0] == 'config' if ARGV.length == 1 and ARGV[0] == 'config'
config() config()

View File

@ -89,6 +89,7 @@ when "config"
if not is_vb_valid(vb, subchannel) if not is_vb_valid(vb, subchannel)
next next
end end
puts "#{field_name(unit, vb, letter)}.label #{label(unit, vb)}" puts "#{field_name(unit, vb, letter)}.label #{label(unit, vb)}"
end end
end end
@ -96,7 +97,6 @@ when "config"
exit 0 exit 0
end end
units.each do |unit| units.each do |unit|
SNMP::Manager.open(:Host => unit, SNMP::Manager.open(:Host => unit,
:Community => community, :Community => community,
@ -105,6 +105,7 @@ units.each do |unit|
if not is_vb_valid(vb, subchannel) if not is_vb_valid(vb, subchannel)
next next
end end
puts "#{field_name(unit, vb, letter)}.value #{vb.value.to_f / 100}" puts "#{field_name(unit, vb, letter)}.value #{vb.value.to_f / 100}"
end end
end end

View File

@ -1,50 +1,56 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# Plugin to monitor the number of invalid access to sshd per country
# =begin
# Require read permissions for SYSLOG
# ref) ls -l /var/log/secure Plugin to monitor the number of invalid access to sshd per country
# Require geoip rubygem
# ref) http://geoip.rubyforge.org/ Require read permissions for SYSLOG
# Require GeoIP-database for searching ip or host for the country ref) ls -l /var/log/secure
# ref) http://www.maxmind.com/app/geoip_country Require geoip rubygem
# ref) http://geoip.rubyforge.org/
# Parameters: Require GeoIP-database for searching ip or host for the country
# config (required) ref) http://www.maxmind.com/app/geoip_country
# autoconf (optional - used by munin-config)
# Parameters:
# $Log$ config (required)
# Revision 1.0 2010/12/25 11:56:12 hirata yoshiyuki autoconf (optional - used by munin-config)
# released.
# $Log$
# Magick markers (optional): Revision 1.0 2010/12/25 11:56:12 hirata yoshiyuki
released.
Magick markers (optional):
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
#
# config example for /etc/munin/plugin-conf.d/munin-node config example for /etc/munin/plugin-conf.d/munin-node
#[sshd_invalid_countries_ruby] [sshd_invalid_countries_ruby]
#user root user root
#group root group root
#env.logfile /var/log/secure env.logfile /var/log/secure
#env.geoip /home/you/GeoIP.dat env.geoip /home/you/GeoIP.dat
#env.loadpath /usr/local/lib/ruby/gems/1.9.1/gems/geoip-0.8.8/lib/ env.loadpath /usr/local/lib/ruby/gems/1.9.1/gems/geoip-0.8.8/lib/
=end
require (ENV['loadpath'] || '') + 'geoip' require (ENV['loadpath'] || '') + 'geoip'
SYSLOG = ENV['syslog'] || '/var/log/secure' SYSLOG = ENV['syslog'] || '/var/log/secure'
GEOIP_DB = ENV['geoip'] || '/var/www/conf/bbs/GeoIP.dat' GEOIP_DB = ENV['geoip'] || '/var/www/conf/bbs/GeoIP.dat'
AWK_CMD = 'awk \'/sshd\[.*Did not receive identification string/{print $12} ' + AWK_CMD = 'awk \'/sshd\[.*Did not receive identification string/{print $12} ' +
'/sshd\[.*Failed password for (root|ROOT)/{print $11} ' + '/sshd\[.*Failed password for (root|ROOT)/{print $11} ' +
'/sshd\[.*Invalid user/{print $10}a\' < ' + SYSLOG '/sshd\[.*Invalid user/{print $10}a\' < ' + SYSLOG
def getInvalids def getInvalids
c={} c = {}
wholeips = `#{AWK_CMD}`.split("\n") wholeips = `#{AWK_CMD}`.split("\n")
uniqueips = wholeips.inject({}) do |hash, key| uniqueips = wholeips.inject({}) do |hash, key|
hash.include?(key) ? hash[key] += 1 : hash[key] = 1; hash.include?(key) ? hash[key] += 1 : hash[key] = 1;
hash hash
end end
geoip = GeoIP.new(GEOIP_DB) geoip = GeoIP.new(GEOIP_DB)
uniqueips.each do |ip,cnt| uniqueips.each do |ip, cnt|
begin begin
country = geoip.country(ip)[5] country = geoip.country(ip)[5]
c[country] = c[country] ? c[country] + cnt : cnt c[country] = c[country] ? c[country] + cnt : cnt
@ -52,7 +58,7 @@ def getInvalids
c['Unknown'] = c['Unknown'] ? c['Unknown'] + cnt : cnt c['Unknown'] = c['Unknown'] ? c['Unknown'] + cnt : cnt
end end
end end
c = c.to_a.sort {|a,b| a[0] <=> b[0]} c = c.to_a.sort { |a, b| a[0] <=> b[0] }
c c
end end
@ -73,8 +79,8 @@ when 'config'
puts 'graph_vlabel number of invalid access per country' puts 'graph_vlabel number of invalid access per country'
puts 'graph_category security' puts 'graph_category security'
puts 'graph_info This graph shows the countries of invalid access to sshd.' puts 'graph_info This graph shows the countries of invalid access to sshd.'
getInvalids.each {|k,v| puts k + '.label ' + k} getInvalids.each { |k, v| puts k + '.label ' + k }
exit 0 exit 0
else else
getInvalids.each {|k,v| puts k + '.value ' + v.to_s} getInvalids.each { |k, v| puts k + '.value ' + v.to_s }
end end

View File

@ -1,50 +1,55 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# thin_memory - A munin plugin for Linux to monitor memory size of each individual thin process
# =begin
# For Linux ONLY !
# DOES NOT WORK on OSX, Solaris or BSD. thin_memory - A munin plugin for Linux to monitor memory size of each individual thin process
# only linux, because this script relies on proc filesystem
# For Linux ONLY !
# Original author: DOES NOT WORK on OSX, Solaris or BSD.
# Frederico de Souza Araujo - fred.the.master@gmail.com only linux, because this script relies on proc filesystem
# http://www.frederico-araujo.com
# Original author:
# Usurper: Frederico de Souza Araujo - fred.the.master@gmail.com
# Adam Michel - elfurbe@furbism.com http://www.frederico-araujo.com
# http://www.furbism.com
# Usurper:
# Originally based on: Adam Michel - elfurbe@furbism.com
# thin_process_memory - http://www.furbism.com
# A munin plugin to monitor memory size of
# each individual thin process Originally based on:
# by Ben VandenBos and Avvo, Inc. thin_process_memory -
# A munin plugin to monitor memory size of
# This program is free software; you can redistribute it and/or modify each individual thin process
# it under the terms of the GNU General Public License version 2 by Ben VandenBos and Avvo, Inc.
# as published by the Free Software Foundation.
# This program is free software; you can redistribute it and/or modify
# This program is distributed in the hope that it will be useful, it under the terms of the GNU General Public License version 2
# but WITHOUT ANY WARRANTY; without even the implied warranty of as published by the Free Software Foundation.
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# You should have received a copy of the GNU General Public License along MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# with this program; if not, write to the Free Software Foundation, Inc., GNU General Public License for more details.
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
module Munin module Munin
class ThinProcessMemory class ThinProcessMemory
# run main method # run main method
def run def run
instances = get_pids() instances = get_pids()
instances.each do |instance| instances.each do |instance|
pid, port = instance.split("|") pid, port = instance.split("|")
rss = (pid_rss(pid).to_i)/1024 rss = (pid_rss(pid).to_i) / 1024
puts "thin_#{port}.value #{rss}" puts "thin_#{port}.value #{rss}"
end end
end end
@ -67,7 +72,6 @@ module Munin
def autoconf def autoconf
get_pids().length > 0 get_pids().length > 0
end end
end end
end end

View File

@ -1,45 +1,50 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# thin_threads -
# A munin plugin for Linux to monitor how many threads per thin process =begin
#
# For Linux ONLY ! thin_threads -
# DOES NOT WORK on OSX, Solaris or BSD. A munin plugin for Linux to monitor how many threads per thin process
# only linux, because this script relies on proc filesystem
# For Linux ONLY !
# Original author: DOES NOT WORK on OSX, Solaris or BSD.
# Frederico de Souza Araujo - fred.the.master@gmail.com only linux, because this script relies on proc filesystem
# http://www.frederico-araujo.com
# Original author:
# Usurper: Frederico de Souza Araujo - fred.the.master@gmail.com
# Adam Michel - elfurbe@furbism.com http://www.frederico-araujo.com
# http://www.furbism.com
# Usurper:
# Originally based on: Adam Michel - elfurbe@furbism.com
# thin_process_memory - http://www.furbism.com
# A munin plugin to monitor memory size of
# each individual thin process Originally based on:
# by Ben VandenBos and Avvo, Inc. thin_process_memory -
# A munin plugin to monitor memory size of
# This program is free software; you can redistribute it and/or modify each individual thin process
# it under the terms of the GNU General Public License version 2 by Ben VandenBos and Avvo, Inc.
# as published by the Free Software Foundation.
# This program is free software; you can redistribute it and/or modify
# This program is distributed in the hope that it will be useful, it under the terms of the GNU General Public License version 2
# but WITHOUT ANY WARRANTY; without even the implied warranty of as published by the Free Software Foundation.
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# You should have received a copy of the GNU General Public License along MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# with this program; if not, write to the Free Software Foundation, Inc., GNU General Public License for more details.
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
module Munin module Munin
class ThinThreads class ThinThreads
def run def run
instances = get_pids() instances = get_pids()
instances.each do |instance| instances.each do |instance|
@ -71,7 +76,6 @@ module Munin
def autoconf def autoconf
get_pids().length > 0 get_pids().length > 0
end end
end end
end end

View File

@ -1,47 +1,52 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# thin_peak_memory -
# A munin plugin for Linux to monitor the maximum memory size =begin
# that an each individual thin process has reached
# thin_peak_memory -
# For Linux ONLY ! A munin plugin for Linux to monitor the maximum memory size
# DOES NOT WORK on OSX, Solaris or BSD. that an each individual thin process has reached
# only linux, because this script relies on proc filesystem
# For Linux ONLY !
# Author: DOES NOT WORK on OSX, Solaris or BSD.
# Frederico de Souza Araujo - fred.the.master@gmail.com only linux, because this script relies on proc filesystem
# http://www.frederico-araujo.com
# Author:
# Based on: Frederico de Souza Araujo - fred.the.master@gmail.com
# thin_process_memory - http://www.frederico-araujo.com
# A munin plugin to monitor memory size of
# each individual thin process Based on:
# by Ben VandenBos and Avvo, Inc. thin_process_memory -
# A munin plugin to monitor memory size of
# This program is free software; you can redistribute it and/or modify each individual thin process
# it under the terms of the GNU General Public License version 2 by Ben VandenBos and Avvo, Inc.
# as published by the Free Software Foundation.
# This program is free software; you can redistribute it and/or modify
# This program is distributed in the hope that it will be useful, it under the terms of the GNU General Public License version 2
# but WITHOUT ANY WARRANTY; without even the implied warranty of as published by the Free Software Foundation.
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# You should have received a copy of the GNU General Public License along MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# with this program; if not, write to the Free Software Foundation, Inc., GNU General Public License for more details.
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#%# family=auto #%# family=auto
#%# capabilities=autoconf #%# capabilities=autoconf
=end
module Munin module Munin
class ThinPeakMemory class ThinPeakMemory
def run def run
instances = get_pids() instances = get_pids()
instances.each do |instance| instances.each do |instance|
pid, port = instance.split("|") pid, port = instance.split("|")
hwm = (pid_hwm(pid).to_i)/1024 hwm = (pid_hwm(pid).to_i) / 1024
puts "thin_#{port}.value #{hwm}" puts "thin_#{port}.value #{hwm}"
end end
end end
@ -69,7 +74,6 @@ module Munin
def autoconf def autoconf
get_pids().length > 0 get_pids().length > 0
end end
end end
end end

View File

@ -32,7 +32,8 @@ module Munin
chunks = line.strip.split(/\s+/, 5) chunks = line.strip.split(/\s+/, 5)
pid, pcmd = chunks[0], chunks[4] pid, pcmd = chunks[0], chunks[4]
next if pid !~ /\A\d+\z/ or pcmd !~ /worker/ next if pid !~ /\A\d+\z/ or pcmd !~ /worker/
result << pid.to_i
result << pid.to_i
end end
result result
end end
@ -48,7 +49,7 @@ module Munin
end end
def memory_usage def memory_usage
result = { :master => {master_pid => nil}, :worker => {} } result = { :master => { master_pid => nil }, :worker => {} }
ps_output = `ps auxw | grep unicorn` ps_output = `ps auxw | grep unicorn`
ps_output.split("\n").each do |line| ps_output.split("\n").each do |line|
chunks = line.strip.split(/\s+/, 11) chunks = line.strip.split(/\s+/, 11)

View File

@ -32,7 +32,8 @@ module Munin
chunks = line.strip.split(/\s+/, 5) chunks = line.strip.split(/\s+/, 5)
pid, pcmd = chunks[0], chunks[4] pid, pcmd = chunks[0], chunks[4]
next if pid !~ /\A\d+\z/ or pcmd !~ /worker/ next if pid !~ /\A\d+\z/ or pcmd !~ /worker/
result << pid.to_i
result << pid.to_i
end end
result result
end end