munin_manager 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ module MuninManager
2
+ class Plugins::HaproxyAppResponseTime < LogReader
3
+ include ActsAsMuninPlugin
4
+
5
+ def data
6
+ @data ||= Hash.new {|h, k| h[k] = Hash.new{|d,v| d[v] = Array.new}}
7
+ end
8
+
9
+ def scan(log_file)
10
+ loop do
11
+ line = log_file.readline
12
+ chunks = line.split(/\s+/)
13
+ server, port = chunks[8].split(":") rescue []
14
+ server_name = server.split("/")[1] rescue nil
15
+ next if server_name.nil?
16
+ timers = chunks[9].split("/") rescue []
17
+ data[server_name][:client_connect] << timers[0].to_f
18
+ data[server_name][:waiting_in_queue] << timers[1].to_f
19
+ data[server_name][:server_connect] << timers[2].to_f
20
+ data[server_name][:server_response] << timers[3].to_f
21
+ data[server_name][:rails_action] << line.match(/\{([0-9.]+)\}/).captures[0].to_f rescue 0
22
+ data[server_name][:total] << timers[4].to_f
23
+ end
24
+ end
25
+
26
+ def process!
27
+ data.each do |server, values|
28
+ values.each do |k, v|
29
+ values[k] = values[k].inject(0) {|sum, i| sum + i} / values[k].length rescue 0
30
+ values[k] = formatted(values[k] / 1000)
31
+ end
32
+ end
33
+ end
34
+
35
+ def config
36
+ log_file = ENV['log_file'] || "/var/log/haproxy.log"
37
+ f = File.open(log_file)
38
+ count = 0
39
+ server_hash = {}
40
+ while(!f.eof? && count < 100)
41
+ count += 1
42
+ line = f.readline
43
+ chunks = line.split(/\s+/)
44
+ server, port = chunks[8].split(":") rescue []
45
+ server_name = server.split("/")[1] rescue nil
46
+ server_hash[server_name] = '' unless server_name.nil?
47
+ end
48
+ default = [:client_connect,:waiting_in_queue, :server_connect, :server_response, :rails_action, :total]
49
+
50
+ config_text = <<-LABEL
51
+ graph_title HAProxy Response Breakdown
52
+ graph_vlabel time (secs)
53
+ graph_category Haproxy
54
+ LABEL
55
+ server_hash.keys.sort.each do |server|
56
+ config_text << default.map{|k| "#{server}_#{k}.label #{server}_#{k}"}.join("\n")
57
+ config_text << "\n"
58
+ end
59
+ config_text
60
+ end
61
+
62
+ def values
63
+ data.inject([]){|datas, (server, values)| (datas + values.map{|k,v| "#{server}_#{k}.value #{v}"})}.join("\n")
64
+ end
65
+
66
+ def self.run
67
+ log_file = ENV['log_file'] || "/var/log/haproxy.log"
68
+ allowed_commands = ['config']
69
+
70
+ haproxy = new(log_file)
71
+
72
+ if cmd = ARGV[0] and allowed_commands.include? cmd then
73
+ puts haproxy.send(cmd.to_sym)
74
+ else
75
+ haproxy.collect!
76
+ puts haproxy.values
77
+ end
78
+ end
79
+
80
+ def self.help_text
81
+ %Q{
82
+ #{plugin_name.capitalize} Munin Plugin
83
+ ===========================
84
+
85
+ Please remember to add something like the lines below to /etc/munin/plugin-conf.d/munin-node
86
+ if the haproxy log file is not at /var/log/haproxy.log
87
+
88
+ [#{plugin_name}]
89
+ env.log_file /var/log/custom/haproxy.log
90
+
91
+ Also, make sure that the '/var/lib/munin/plugin-state' is writable by munin.
92
+
93
+ $ sudo chmod 777 /var/lib/munin/plugin-state
94
+
95
+ }
96
+ end
97
+
98
+ private
99
+
100
+ def formatted(num)
101
+ "%.10f" % num
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,87 @@
1
+ module MuninManager
2
+ class Plugins::HaproxyResponseTime < LogReader
3
+ include ActsAsMuninPlugin
4
+
5
+ def data
6
+ @data ||= Hash.new {|h, k| h[k] = Array.new}
7
+ end
8
+
9
+ def scan(log_file)
10
+ loop do
11
+ line = log_file.readline
12
+ chunks = line.split(/\s+/)
13
+
14
+ timers = chunks[9].split("/") rescue []
15
+ data[:client_connect] << timers[0].to_f
16
+ data[:waiting_in_queue] << timers[1].to_f
17
+ data[:server_connect] << timers[2].to_f
18
+ data[:server_response] << timers[3].to_f
19
+ data[:rails_action] << line.match(/\{([0-9.]+)\}/).captures[0].to_f * 1000 rescue 0
20
+ data[:total] << timers[4].to_f
21
+ end
22
+ end
23
+
24
+ def process!
25
+ data.each do |k, v|
26
+ data[k] = data[k].inject(0) {|sum, i| sum + i} / data[k].length rescue 0
27
+ data[k] = formatted(data[k] / 1000)
28
+ end
29
+ end
30
+
31
+ def config
32
+ <<-LABEL
33
+ graph_title HAProxy Response Breakdown
34
+ graph_vlabel time (secs)
35
+ graph_category Haproxy
36
+ client_connect.label Client Connect
37
+ waiting_in_queue.label Waiting In Queue
38
+ server_connect.label Server Connect
39
+ server_response.label Server Response
40
+ rails_action.label Rails Controller Action
41
+ total.label Total Response Time
42
+ LABEL
43
+ end
44
+
45
+ def values
46
+ data.map {|k, v| "#{k}.value #{v}"}.join("\n")
47
+ end
48
+
49
+ def self.run
50
+ log_file = ENV['log_file'] || "/var/log/haproxy.log"
51
+ allowed_commands = ['config']
52
+
53
+ haproxy = new(log_file)
54
+
55
+ if cmd = ARGV[0] and allowed_commands.include? cmd then
56
+ puts haproxy.send(cmd.to_sym)
57
+ else
58
+ haproxy.collect!
59
+ puts haproxy.values
60
+ end
61
+ end
62
+
63
+ def self.help_text
64
+ %Q{
65
+ #{plugin_name.capitalize} Munin Plugin
66
+ ===========================
67
+
68
+ Please remember to add something like the lines below to /etc/munin/plugin-conf.d/munin-node
69
+ if the haproxy log file is not at /var/log/haproxy.log
70
+
71
+ [#{plugin_name}]
72
+ env.log_file /var/log/custom/haproxy.log
73
+
74
+ Also, make sure that the '/var/lib/munin/plugin-state' is writable by munin.
75
+
76
+ $ sudo chmod 777 /var/lib/munin/plugin-state
77
+
78
+ }
79
+ end
80
+
81
+ private
82
+
83
+ def formatted(num)
84
+ "%.10f" % num
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,95 @@
1
+ #! /usr/bin/env ruby
2
+ # Munin plugin for starling.
3
+ require 'open-uri'
4
+ require 'base64'
5
+
6
+ module MuninManager
7
+ class Plugins::HaproxyRps
8
+ include ActsAsMuninPlugin
9
+
10
+ def initialize(url, user, pass)
11
+ @url = url
12
+ @user = user
13
+ @pass = pass
14
+ @data = Hash.new{|h,k|h[k] = 0}
15
+ @category = 'Haproxy'
16
+ parse_csv
17
+ end
18
+
19
+ def parse_csv
20
+ base64 = Base64.encode64("#{@user}:#{@pass}")
21
+ file = open(@url, {"Authorization" => "Basic #{base64}"})
22
+ file.readline #skip first line
23
+ file.each_line do |line|
24
+ data_ary = line.split(",")
25
+ host,port = data_ary[1].split(":")
26
+ @data[host] += data_ary[7].to_i
27
+ end
28
+ end
29
+
30
+ def ops_stats
31
+ defaults = {
32
+ 'min' => 0,
33
+ 'type' => 'DERIVE',
34
+ 'draw' => 'LINE2',
35
+ }
36
+
37
+ stats = {
38
+
39
+ }
40
+
41
+ @data.each_key do |k|
42
+ stats[k] = defaults.merge({:label => k})
43
+ end
44
+ return stats
45
+ end
46
+
47
+ def config
48
+ graph_config = <<-END.gsub(/ +/, '')
49
+ graph_title Haproxy RPS / App Server
50
+ graph_args --base 1000
51
+ graph_vlabel ops/${graph_period}
52
+ graph_category #{@category}
53
+ graph_order #{@data.keys.sort.join(" ")}
54
+ END
55
+
56
+ stat_config = []
57
+ ops_stats.each do |stat,config|
58
+ config.each do |var,value|
59
+ stat_config << "#{stat}.#{var} #{value}\n"
60
+ end
61
+ end
62
+ return graph_config + stat_config.sort.join
63
+ end
64
+
65
+ def values
66
+ ret = ''
67
+ @data.each do |key, stat|
68
+ ret << "#{key}.value #{stat}\n"
69
+ end
70
+ return ret
71
+ end
72
+
73
+ def self.run
74
+ url = ENV['URL'] || 'http://lb01.ffs.seriousops.com/haproxy?stats;csv'
75
+ user = ENV['USERNAME'] || 'admin'
76
+ pass = ENV['PASSWORD'] || 'pass'
77
+ haproxy = new(url, user, pass)
78
+
79
+ allowed_commands = ['config']
80
+
81
+ if cmd = ARGV[0] and allowed_commands.include? cmd then
82
+ puts haproxy.send(cmd.to_sym)
83
+ else
84
+ puts haproxy.values
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def format_for_munin(str)
91
+ str.to_s.gsub(/[^A-Za-z0-9_]/, "_")
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,53 @@
1
+ module MuninManager
2
+ class Plugins::NetworkLatency < LogReader
3
+ include ActsAsMuninPlugin
4
+
5
+ def self.run
6
+ hostnames = (ENV['hostnames'] || 'localhost').split(",")
7
+ count = (ENV["count"] || 1).to_i
8
+ if ARGV[0] == "config"
9
+ puts config(hostnames)
10
+ else
11
+ values = Hash.new {|h,k| h[k] = []}
12
+ threads = []
13
+ count.times do |i|
14
+ threads << Thread.new do
15
+ output = %x{/usr/sbin/fping -c 10 -p 100 -q #{hostnames.join(" ")} 2>&1}
16
+ Thread.current[:output] = output
17
+ end
18
+ end
19
+ threads.each do |t|
20
+ t.join
21
+ t[:output].to_s.split("\n").each do |line|
22
+ if line =~ /^([^\s]+)\s*:\s*xmt\/rcv\/%loss = [0-9]+\/[0-9]+\/[0-9]+%, min\/avg\/max = [0-9.]+\/([0-9.]+)\/[0-9.]+/
23
+ values[$1] << $2.to_f
24
+ end
25
+ end
26
+ end
27
+
28
+ values.each do |host, results|
29
+ avg = results.size > 0 ? results.inject(0){|a,b| a + b}.to_f / results.size : -1
30
+ puts "#{sanitize(host)}.value #{avg}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.sanitize(hostname)
36
+ hostname.to_s.gsub(/[^\w]/, '_')
37
+ end
38
+
39
+ def self.config(hostnames)
40
+ configs = {
41
+ "graph_title" => "Network Latency",
42
+ "graph_vlabel" => "time (ms)",
43
+ "graph_category" => "Network",
44
+ "graph_order" => ""
45
+ }
46
+ hostnames.each do |hostname|
47
+ configs["#{sanitize(hostname)}.label"] = hostname
48
+ configs["graph_order"] += "#{sanitize(hostname)} "
49
+ end
50
+ configs.map {|key_value_pair| key_value_pair.join(" ")}.join("\n")
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ module MuninManager
5
+ class Plugins::NotificationClassification
6
+ include ActsAsMuninPlugin
7
+
8
+ def config
9
+ "graph_title #{ENV['app']} Notification Classification Creation
10
+ graph_vlabel new classifications / hour
11
+ notification_rate.label new classifications / hour
12
+ notification_rate.type derive
13
+ notification_rate.warning 10
14
+ notification_rate.critical 100"
15
+ end
16
+
17
+ def self.run
18
+ allowed_commands = ['config']
19
+ if cmd = ARGV[0] and allowed_commands.include? cmd
20
+ puts new.config
21
+ else
22
+ cmd = "mysql -u #{ENV['mysql_user']} --password=#{ENV['mysql_password']} -h #{ENV['host']} -e 'use #{ENV['database']}; select count(*) from notification_classifications where created_at >= \"#{1.hour.ago.to_s(:db)}\";' --skip-column-names --silent"
23
+ puts "notification_rate.value %s" % `#{cmd}`
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ module MuninManager
2
+ class Plugins::PacketLoss < LogReader
3
+ include ActsAsMuninPlugin
4
+
5
+ def self.run
6
+ hostnames = (ENV['hostnames'] || 'localhost').split(",")
7
+ count = (ENV["count"] || 1).to_i
8
+ if ARGV[0] == "config"
9
+ puts config(hostnames)
10
+ else
11
+ values = Hash.new {|h,k| h[k] = []}
12
+ threads = []
13
+ count.times do |i|
14
+ threads << Thread.new do
15
+ output = %x{/usr/sbin/fping -c 10 -p 100 -q #{hostnames.join(" ")} 2>&1}
16
+ Thread.current[:output] = output
17
+ end
18
+ end
19
+ threads.each do |t|
20
+ t.join
21
+ t[:output].to_s.split("\n").each do |line|
22
+ if line =~ /^([^\s]+)\s*:\s*xmt\/rcv\/%loss = [0-9]+\/[0-9]+\/([0-9]+)%/
23
+ values[$1] << $2.to_f
24
+ end
25
+ end
26
+ end
27
+
28
+ values.each do |host, results|
29
+ avg = results.size > 0 ? results.inject(0){|a,b| a + b}.to_f / results.size : -1
30
+ puts "#{sanitize(host)}.value #{avg}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.sanitize(hostname)
36
+ hostname.to_s.gsub(/[^\w]/, '_')
37
+ end
38
+
39
+ def self.config(hostnames)
40
+ configs = {
41
+ "graph_title" => "Packet Loss",
42
+ "graph_vlabel" => "percentage",
43
+ "graph_category" => "Network",
44
+ "graph_order" => ""
45
+ }
46
+ hostnames.each do |hostname|
47
+ configs["#{sanitize(hostname)}.label"] = hostname
48
+ configs["graph_order"] += "#{sanitize(hostname)} "
49
+ end
50
+ configs.map {|key_value_pair| key_value_pair.join(" ")}.join("\n")
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,82 @@
1
+ module MuninManager
2
+ class Plugins::RailsRendering < LogReader
3
+ include ActsAsMuninPlugin
4
+
5
+ def data
6
+ @data ||= Hash.new {|h, k| h[k] = Array.new}
7
+ end
8
+
9
+ def scan(log_file)
10
+ loop do
11
+ line = log_file.readline
12
+ next unless line.match(/^Completed in/)
13
+
14
+ chunks = line.split(/\s/)
15
+ data[:total] << chunks[2].to_f
16
+ data[:rendering] << chunks[7].to_f
17
+ data[:memcache] << chunks[11].to_f
18
+ data[:db] << chunks[14].to_f
19
+ end
20
+ end
21
+
22
+ def process!
23
+ data.each_pair do |component, response_times|
24
+ data[component] = response_times.inject(0) {|sum, i| sum + i} / data[component].length rescue 0
25
+ end
26
+ end
27
+
28
+ def config
29
+ <<-LABEL
30
+ graph_title Rails Response Breakdown
31
+ graph_vlabel response time
32
+ graph_category Rails
33
+ total.label total
34
+ rendering.label rendering
35
+ db.label db
36
+ memcache.label memcache
37
+ LABEL
38
+ end
39
+
40
+ def values
41
+ data.map {|k, v| "#{format_for_munin(k)}.value #{"%.10f" % v}"}.join("\n")
42
+ end
43
+
44
+ def self.run
45
+ log_file = ENV['log_file'] || "/var/log/rails.log"
46
+ allowed_commands = ['config']
47
+
48
+ rails = new(log_file)
49
+
50
+ if cmd = ARGV[0] and allowed_commands.include? cmd then
51
+ puts rails.send(cmd.to_sym)
52
+ else
53
+ rails.collect!
54
+ puts rails.values
55
+ end
56
+ end
57
+
58
+ def self.help_text(options = {})
59
+ %Q{
60
+ #{plugin_name.capitalize} Munin Plugin
61
+ ===========================
62
+
63
+ Please remember to add something like the lines below to /etc/munin/plugin-conf.d/munin-node
64
+ if the rails log file is not at /var/log/rails.log
65
+
66
+ [#{options[:symlink] || plugin_name}]
67
+ env.log_file /var/log/custom/rails.log
68
+
69
+ Also, make sure that the '/var/lib/munin/plugin-state' is writable by munin.
70
+
71
+ $ sudo chmod 777 /var/lib/munin/plugin-state
72
+
73
+ }
74
+ end
75
+
76
+ private
77
+
78
+ def format_for_munin(str)
79
+ str.to_s.gsub(/[^A-Za-z0-9_]/, "_")
80
+ end
81
+ end
82
+ end