munin_manager 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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