city-watch 0.5.2 → 0.5.3

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.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- city-watch (0.4.0)
4
+ city-watch (0.5.2)
5
5
  rack
6
6
  rack-mount
7
7
  redis
@@ -1 +1,2 @@
1
- :collector: "localhost:62001"
1
+ :debug: true
2
+ :watch_collector: "localhost:62001"
@@ -6,4 +6,6 @@ end
6
6
 
7
7
  ::Routes = CityWatch::Routes
8
8
 
9
+ require 'city_watch/util/collector'
10
+ require 'city_watch/watchmen'
9
11
  require 'city_watch/collector/receive'
@@ -1,25 +1,11 @@
1
- class ResendRequest
1
+ class WatchCollector
2
2
 
3
3
  def call(env)
4
4
 
5
5
  post_data = begin Yajl::Parser.new(:symbolize_keys => true).parse(env["rack.input"].read) || {} rescue {} end
6
6
  post_data[:received_at] = Time.now.to_s
7
7
 
8
- CityWatch.redis.sadd "#{CityWatch.config[:prefix]}::known_hosts", post_data[:hostname]
9
- CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{post_data[:hostname]}::raw_stats", Time.now.to_i, Yajl::Encoder.encode(post_data)
10
-
11
- summary = {}
12
-
13
- post_data[:watchmen].each do |watchman,dat|
14
- CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{post_data[:hostname]}::#{watchman}", Time.now.to_i, Yajl::Encoder.encode(dat.merge({:received_at => post_data[:received_at]}))
15
- if dat[:summary]
16
- sum = dat[:summary].is_a?(Array) ? dat[:summary].inject({}) {|acc,k| acc[k.to_sym] = dat[k.to_sym]; acc} : dat[:summary]
17
- CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{post_data[:hostname]}::#{watchman}::summary", Time.now.to_i, Yajl::Encoder.encode(sum)
18
- summary[watchman] = sum
19
- end
20
- end
21
-
22
- CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{post_data[:hostname]}::summary", Time.now.to_i, Yajl::Encoder.encode(summary.merge({:received_at => post_data[:received_at]}))
8
+ Collector.process(post_data)
23
9
 
24
10
  [200,{"Content-Type" => "text/plain"},["Got it!"]]
25
11
  end
@@ -6,5 +6,6 @@ end
6
6
 
7
7
  ::Routes = CityWatch::Routes
8
8
 
9
+ require 'city_watch/watchmen'
9
10
  require 'city_watch/commander/server'
10
11
  require 'city_watch/commander/home'
@@ -5,7 +5,25 @@ class Server
5
5
  parms = Rack::Request.new(env).params.merge(env["rack.routing_args"]).inject({}){|acc,(k,v)| acc[k.to_sym] = v; acc}
6
6
  server = parms[:server]
7
7
 
8
- output = CityWatch.header << '<h1>' << server << "</h1><ul>"
8
+ output = CityWatch.header << '<h1>' << server << "</h1>"
9
+ Watchmen.each do |watchman|
10
+ flags = watchman.get_flags(server)
11
+ alerts = watchman.get_alerts(server,2)
12
+ if (flags && flags.keys.count > 0) || (alerts && alerts.count > 0)
13
+ output << "<h3>" << watchman.name.to_s << "</h3><ul>"
14
+ if flags && flags.keys.count > 0
15
+ output << "<li class=\"alert\"><strong>Flags:</strong> <pre><code>" << Yajl::Encoder.encode(flags,:pretty => true, :indent => " ") << "</code></pre></li>"
16
+ end
17
+ if alerts && alerts.count > 0
18
+ output << "<li class=\"alert\"><strong>Alerts:</strong></li>"
19
+ alerts.each do |alert|
20
+ output << "<li><pre><code>" << Yajl::Encoder.encode(Yajl::Parser.parse(alert),:pretty => true, :indent => " ") << "</code></pre></li>"
21
+ end
22
+ end
23
+ output << "</ul>"
24
+ end
25
+ end
26
+ output << "<ol>"
9
27
  CityWatch.redis.zrevrange("#{CityWatch.config[:prefix]}::#{server}::raw_stats",0,10).each do |update|
10
28
  dat = Yajl::Parser.new(:symbolize_keys => true).parse(update)
11
29
  output << "<li><h4>" << dat[:received_at] << "</h4><ul>"
@@ -14,7 +32,7 @@ class Server
14
32
  end
15
33
  output << "</ul></li>"
16
34
  end
17
- output << "</ul></body></html>"
35
+ output << "</ol></body></html>"
18
36
 
19
37
  [200,{"Content-Type" => "text/html"},[output]]
20
38
  end
@@ -26,4 +26,21 @@ module Collector
26
26
  end
27
27
  end
28
28
 
29
+ def self.process(data)
30
+ rcv_time = Time.now.to_i
31
+ host = data[:hostname]
32
+ CityWatch.redis.sadd "#{CityWatch.config[:prefix]}::known_hosts", host
33
+ CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{host}::raw_stats", rcv_time, Yajl::Encoder.encode(data)
34
+
35
+ summary = {}
36
+
37
+ data[:watchmen].each do |watchman,dat|
38
+ if watch_obj = Watchmen.get(watchman)
39
+ status, summary[watchman] = watch_obj.process(dat,rcv_time,host)
40
+ end
41
+ end
42
+
43
+ CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{host}::summary", rcv_time, Yajl::Encoder.encode(summary.merge({:received_at => data[:received_at]}))
44
+ end
45
+
29
46
  end
@@ -6,6 +6,135 @@ module Watchman
6
6
 
7
7
  module ClassMethods
8
8
 
9
+ def process(dat,rcv,host)
10
+ @host = host
11
+ @rcv_time = rcv
12
+ CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{host}::#{self.name}", rcv_time, Yajl::Encoder.encode(dat.merge({:received_at => dat[:received_at]}))
13
+ if dat[:summary]
14
+ sum = dat[:summary].is_a?(Array) ? dat[:summary].inject({}) {|acc,k| acc[k.to_sym] = dat[k.to_sym]; acc} : dat[:summary]
15
+ CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{host}::#{self.name}::summary", rcv_time, Yajl::Encoder.encode(sum)
16
+ end
17
+ run_rules(dat)
18
+ return 0, sum || nil
19
+ end
20
+
21
+ def host
22
+ @host || nil
23
+ end
24
+
25
+ def rcv_time
26
+ @rcv_time || Time.now.to_i
27
+ end
28
+
29
+ def add_rule(name,&block)
30
+ @rules ||= {}
31
+ @rules[name] = block
32
+ end
33
+
34
+ def run_rules(dat)
35
+ @rules.map do |(name,rule)|
36
+ rule.call(dat)
37
+ end if @rules
38
+ end
39
+
40
+ def send_alert(message,dat=nil)
41
+ CityWatch.redis.zadd "#{CityWatch.config[:prefix]}::#{host}::#{self.name}::alerts", rcv_time, Yajl::Encoder.encode({:message => message, :data => dat, :when => rcv_time})
42
+ end
43
+
44
+ def alerts
45
+ @alerts ||= []
46
+ if block_given?
47
+ @alerts.each do |a|
48
+ yield a
49
+ end
50
+ else
51
+ @alerts
52
+ end
53
+ nil
54
+ end
55
+
56
+ def get_alerts(host=host,num=5)
57
+ CityWatch.redis.zrevrange "#{CityWatch.config[:prefix]}::#{host}::#{self.name}::alerts", 0, num - 1
58
+ end
59
+
60
+ def send_alerts!
61
+ @alerts.map do |alert|
62
+ puts "Alert: #{alert.inspect}" #if CityWatch.debug?
63
+ end if @alerts
64
+ end
65
+
66
+ def set_flag(name)
67
+ unless get_flag(name)
68
+ flag_flapped name, :on
69
+ end
70
+ CityWatch.redis.setbit "#{CityWatch.config[:prefix]}::#{host}::#{self.name}::flags", flag_position(name), 1
71
+ end
72
+
73
+ def clear_flag(name)
74
+ if get_flag(name)
75
+ flag_flapped name, :off
76
+ end
77
+ CityWatch.redis.setbit "#{CityWatch.config[:prefix]}::#{host}::#{self.name}::flags", flag_position(name), 0
78
+ end
79
+
80
+ def flag_flapped(name,new_val)
81
+ # should have some event to watch for a flag switching position
82
+ puts "Flag flipped: #{name} -> #{new_val}" #if CityWatch.debug?
83
+ end
84
+
85
+ def get_flag(name,host=host)
86
+ @host = host
87
+ CityWatch.redis.getbit("#{CityWatch.config[:prefix]}::#{host}::#{self.name}::flags", flag_position(name)) ? true : false
88
+ end
89
+
90
+ def get_flags(host=host)
91
+ @host = host
92
+ out = {}
93
+ map = flag_map
94
+ map.each_index do |idx|
95
+ out[map[idx]] = get_flag(map[idx])
96
+ end
97
+ out
98
+ end
99
+
100
+ def flag_map_key
101
+ "#{CityWatch.config[:prefix]}::#{self.name}::flag_map"
102
+ end
103
+
104
+ def flag_map
105
+ CityWatch.redis.lrange flag_map_key, 0, -1
106
+ end
107
+
108
+ def flag_position(name)
109
+ if (map = flag_map) && map.include?(name.to_s)
110
+ map.index(name.to_s)
111
+ else
112
+ new_flag(name)
113
+ end
114
+ end
115
+
116
+ def new_flag(name)
117
+ CityWatch.redis.rpush(flag_map_key, name) - 1
118
+ end
119
+
120
+ def set_default(k,val)
121
+ opts[k] = val
122
+ end
123
+
124
+ def opts
125
+ @options ||= {}
126
+ end
127
+
128
+ def options(*args)
129
+ if args.count > 1
130
+ return args.map {|k| opts[k]}
131
+ else
132
+ return opts[args.first]
133
+ end
134
+ return nil
135
+ end
136
+ alias_method :option, :options
137
+
9
138
  end
10
139
 
11
140
  def self.included(base)
@@ -20,14 +20,13 @@ module Watchmen
20
20
  @watchmen << cls
21
21
  end
22
22
 
23
- def self.add_rule(&block)
24
- @rules ||= []
25
- @rules << block
23
+ def self.get(name)
24
+ @watchmen.select {|w| w.name.to_s == name.to_s }.first
26
25
  end
27
26
 
28
- def self.run_rules(data)
29
- @rules.map do |rule|
30
- rule.call(data)
27
+ def self.each
28
+ @watchmen.each do |w|
29
+ yield w
31
30
  end
32
31
  end
33
32
 
@@ -2,10 +2,23 @@ class DiskUsage
2
2
 
3
3
  include Watchman
4
4
 
5
+ set_default :usage_threshold, 60
6
+
5
7
  def self.data
6
8
  dat = DF.data
7
9
  sum = dat.select {|d| d[:mounted]=="/"}.first
8
10
  {:partitions => dat, :summary => sum[:capacity] || sum["use%".to_sym]}
9
11
  end
10
12
 
13
+ add_rule(:root_usage_high) do |data|
14
+
15
+ if (usage = data[:summary].to_i) && usage > option(:usage_threshold)
16
+ send_alert "Root disk usage is over #{option(:usage_threshold)}% (#{usage}%)", data[:partitions].select {|d| d[:mounted]=="/"}.first
17
+ set_flag :root_disk_over_quota
18
+ else
19
+ clear_flag :root_disk_over_quota
20
+ end
21
+
22
+ end
23
+
11
24
  end
@@ -19,7 +19,7 @@ class Unicorns
19
19
  out.merge({:num_masters => out[:masters].count, :num_workers => out[:workers].count, :summary => [:num_masters, :num_workers]})
20
20
  end
21
21
 
22
- add_rule do |dat|
22
+ add_rule(:high_memory_usage) do |dat|
23
23
 
24
24
  end
25
25
 
@@ -1,3 +1,3 @@
1
1
  module CityWatch
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.3"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: city-watch
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.2
5
+ version: 0.5.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - John Bragg
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2013-02-10 00:00:00 Z
13
+ date: 2013-02-11 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: redis