droid 1.0.2pre → 1.0.2

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,55 +1,55 @@
1
1
  class Droid
2
- module EMTimerUtils
3
- def self.included(base)
4
- base.extend(ClassMethods)
5
- end
6
-
7
- module ClassMethods
8
- # Trap exceptions leaving the block and log them. Do not re-raise
9
- def trap_exceptions
10
- yield
11
- rescue => e
12
- em_exception(e)
13
- end
14
-
15
- def em_exception(e)
16
- msg = format_em_exception(e)
17
- log.error "[EM.timer] #{msg}", :exception => e
18
- end
19
-
20
- def format_em_exception(e)
21
- # avoid backtrace in /usr or vendor if possible
22
- system, app = e.backtrace.partition { |b| b =~ /(^\/usr\/|vendor)/ }
23
- reordered_backtrace = app + system
24
-
25
- # avoid "/" as the method name (we want the controller action)
26
- row = 0
27
- row = 1 if reordered_backtrace[row].match(/in `\/'$/)
28
-
29
- # get file and method name
30
- begin
31
- file, method = reordered_backtrace[row].match(/(.*):in `(.*)'$/)[1..2]
32
- file.gsub!(/.*\//, '')
33
- "#{e.class} in #{file} #{method}: #{e.message}"
34
- rescue
35
- "#{e.class} in #{e.backtrace.first}: #{e.message}"
36
- end
37
- end
38
-
39
- # One-shot timer
40
- def timer(duration, &blk)
41
- EM.add_timer(duration) { trap_exceptions(&blk) }
42
- end
43
-
44
- # Add a periodic timer. If the now argument is true, run the block
45
- # immediately in addition to scheduling the periodic timer.
46
- def periodic_timer(duration, now=false, &blk)
47
- timer(1, &blk) if now
48
- EM.add_periodic_timer(duration) { trap_exceptions(&blk) }
49
- end
50
- end
51
-
52
- def timer(*args, &blk); self.class.timer(*args, &blk); end
53
- def periodic_timer(*args, &blk); self.class.periodic_timer(*args, &blk); end
54
- end
2
+ module EMTimerUtils
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ # Trap exceptions leaving the block and log them. Do not re-raise
9
+ def trap_exceptions
10
+ yield
11
+ rescue => e
12
+ em_exception(e)
13
+ end
14
+
15
+ def em_exception(e)
16
+ msg = format_em_exception(e)
17
+ log.error "[EM.timer] #{msg}", :exception => e
18
+ end
19
+
20
+ def format_em_exception(e)
21
+ # avoid backtrace in /usr or vendor if possible
22
+ system, app = e.backtrace.partition { |b| b =~ /(^\/usr\/|vendor)/ }
23
+ reordered_backtrace = app + system
24
+
25
+ # avoid "/" as the method name (we want the controller action)
26
+ row = 0
27
+ row = 1 if reordered_backtrace[row].match(/in `\/'$/)
28
+
29
+ # get file and method name
30
+ begin
31
+ file, method = reordered_backtrace[row].match(/(.*):in `(.*)'$/)[1..2]
32
+ file.gsub!(/.*\//, '')
33
+ "#{e.class} in #{file} #{method}: #{e.message}"
34
+ rescue
35
+ "#{e.class} in #{e.backtrace.first}: #{e.message}"
36
+ end
37
+ end
38
+
39
+ # One-shot timer
40
+ def timer(duration, &blk)
41
+ EM.add_timer(duration) { trap_exceptions(&blk) }
42
+ end
43
+
44
+ # Add a periodic timer. If the now argument is true, run the block
45
+ # immediately in addition to scheduling the periodic timer.
46
+ def periodic_timer(duration, now=false, &blk)
47
+ timer(1, &blk) if now
48
+ EM.add_periodic_timer(duration) { trap_exceptions(&blk) }
49
+ end
50
+ end
51
+
52
+ def timer(*args, &blk); self.class.timer(*args, &blk); end
53
+ def periodic_timer(*args, &blk); self.class.periodic_timer(*args, &blk); end
54
+ end
55
55
  end
@@ -3,100 +3,100 @@ require 'droid/heroku/local_stats'
3
3
  require 'droid/heroku/logger_client'
4
4
 
5
5
  Log.configure do |c|
6
- c.component = LocalStats.slot
7
- c.instance_name = LocalStats.instance_name
6
+ c.component = LocalStats.slot
7
+ c.instance_name = LocalStats.instance_name
8
8
  end
9
9
 
10
10
  Droid.log = Log
11
11
 
12
12
  class Droid
13
- module Utils
14
- def self.generate_name_for_instance(name)
15
- "#{name}.#{LocalStats.slot}.#{LocalStats.ion_instance_id}"
16
- end
17
- end
13
+ module Utils
14
+ def self.generate_name_for_instance(name)
15
+ "#{name}.#{LocalStats.slot}.#{LocalStats.ion_instance_id}"
16
+ end
17
+ end
18
18
  end
19
19
 
20
20
  begin
21
- require 'droid/json_server'
21
+ require 'droid/json_server'
22
22
  rescue LoadError => e
23
- Droid.log.error "Could not load JSONServer", :exception => e
23
+ Droid.log.error "Could not load JSONServer", :exception => e
24
24
  end
25
25
 
26
26
  class HerokuDroid < Droid
27
- attr_reader :extended_stats
28
-
29
- def initialize(name, opts={}, &blk)
30
- @extended_stats = !(opts[:extended_stats] == false)
31
-
32
- super(name, opts) do |droid|
33
- setup_standard_topics(self) unless opts[:standard_topics] == false
34
- LocalStats.attach
35
- blk.call(self)
36
- end
37
- end
38
-
39
- def stats(&blk)
40
- @stats = blk
41
- out = call_stats
42
- out = out.inspect unless out.kind_of?(String)
43
- Log.notice out
44
- end
45
-
46
- def call_stats
47
- @stats ? @stats.call : nil
48
- end
49
-
50
- def name
51
- Droid.name
52
- end
53
-
54
- def ruby_path
55
- if File.exists?("/usr/ruby1.8.6/bin/ruby")
56
- "/usr/ruby1.8.6/bin"
57
- else
58
- "/usr/local/bin"
59
- end
60
- end
61
-
62
- def setup_standard_topics(droid)
63
- setup_ping_topic(droid)
64
- end
65
-
66
- def setup_ping_topic(droid)
67
- require 'time'
68
-
69
- droid.listener('ping').subscribe do |req|
70
- Droid::Utilization.latency = (Time.now.to_f - req['departed_at']).abs
71
- end
72
-
73
- blk = Proc.new do |d|
74
- begin
75
- t1 = Time.now
76
- response = {}.merge(LocalStats.stats)
77
-
78
- estats = nil
79
- if self.extended_stats
80
- estats = droid.call_stats
81
- estats = { :notes => estats } unless estats.kind_of?(Hash)
82
- estats[:notes] ||= estats.map { |k, v| "#{v} #{k}" }.join(", ")
83
- estats.merge!(LocalStats.extended_stats)
84
- end
85
-
86
- response.merge!({
87
- :extended_stats => estats,
88
- :droid_name => Droid.name,
89
- :latency => Droid::Utilization.latency,
90
- })
91
-
92
- d.publish('pong', response.merge(:stat_collection => (Time.now - t1)))
93
- rescue Object => e
94
- log.error "Ping Block Error: #{e.class} -> #{e.message}", :exception => e
95
- end
96
- end
97
-
98
- EM.add_timer(2) { blk.call(droid) }
99
- EM.add_periodic_timer(50 + (rand*15).to_i) { blk.call(droid) }
100
- end
27
+ attr_reader :extended_stats
28
+
29
+ def initialize(name, opts={}, &blk)
30
+ @extended_stats = !(opts[:extended_stats] == false)
31
+
32
+ super(name, opts) do |droid|
33
+ setup_standard_topics(self) unless opts[:standard_topics] == false
34
+ LocalStats.attach
35
+ blk.call(self)
36
+ end
37
+ end
38
+
39
+ def stats(&blk)
40
+ @stats = blk
41
+ out = call_stats
42
+ out = out.inspect unless out.kind_of?(String)
43
+ Log.notice out
44
+ end
45
+
46
+ def call_stats
47
+ @stats ? @stats.call : nil
48
+ end
49
+
50
+ def name
51
+ Droid.name
52
+ end
53
+
54
+ def ruby_path
55
+ if File.exists?("/usr/ruby1.8.6/bin/ruby")
56
+ "/usr/ruby1.8.6/bin"
57
+ else
58
+ "/usr/local/bin"
59
+ end
60
+ end
61
+
62
+ def setup_standard_topics(droid)
63
+ setup_ping_topic(droid)
64
+ end
65
+
66
+ def setup_ping_topic(droid)
67
+ require 'time'
68
+
69
+ droid.listener('ping').subscribe do |req|
70
+ Droid::Utilization.latency = (Time.now.to_f - req['departed_at']).abs
71
+ end
72
+
73
+ blk = Proc.new do |d|
74
+ begin
75
+ t1 = Time.now
76
+ response = {}.merge(LocalStats.stats)
77
+
78
+ estats = nil
79
+ if self.extended_stats
80
+ estats = droid.call_stats
81
+ estats = { :notes => estats } unless estats.kind_of?(Hash)
82
+ estats[:notes] ||= estats.map { |k, v| "#{v} #{k}" }.join(", ")
83
+ estats.merge!(LocalStats.extended_stats)
84
+ end
85
+
86
+ response.merge!({
87
+ :extended_stats => estats,
88
+ :droid_name => Droid.name,
89
+ :latency => Droid::Utilization.latency,
90
+ })
91
+
92
+ d.publish('pong', response.merge(:stat_collection => (Time.now - t1)))
93
+ rescue Object => e
94
+ log.error "Ping Block Error: #{e.class} -> #{e.message}", :exception => e
95
+ end
96
+ end
97
+
98
+ EM.add_timer(2) { blk.call(droid) }
99
+ EM.add_periodic_timer(50 + (rand*15).to_i) { blk.call(droid) }
100
+ end
101
101
  end
102
102
 
@@ -2,108 +2,108 @@ require 'eventmachine'
2
2
  require 'evma_httpserver'
3
3
 
4
4
  class Droid
5
- class JSONServer < ::EM::Connection
6
- include ::EM::HttpServer
7
-
8
- def post_init
9
- super
10
- no_environment_strings
11
- end
12
-
13
- def process_http_request
14
- return not_found_response if @http_request_method != "GET"
15
-
16
- if @http_request_uri == "/"
17
- default_response
18
- else
19
- method_name = "get_#{@http_request_uri.split("/")[1]}".gsub(/[^\d\w_]/,'').downcase
20
- if public_methods.include?(method_name)
21
- generate_response(method_name)
22
- else
23
- not_found_response
24
- end
25
- end
26
- end
27
-
28
- def generate_response(method_name)
29
- status, data, content_type = self.send(method_name)
30
-
31
- response = ::EM::DelegatedHttpResponse.new(self)
32
- response.status = status
33
- response.content_type content_type
34
- response.content = data
35
- response.send_response
36
- end
37
-
38
- def default_response
39
- response = ::EM::DelegatedHttpResponse.new(self)
40
- response.status = 200
41
- response.content_type 'application/json'
42
- response.content = {"status" => "OK"}.to_json
43
- response.send_response
44
- end
45
-
46
- def not_found_response
47
- response = ::EM::DelegatedHttpResponse.new(self)
48
- response.status = 404
49
- response.content_type 'text/plain'
50
- response.content = "Not Found"
51
- response.send_response
52
- end
53
-
54
- def get_droid
55
- report_data = Droid::Utilization.report_data
56
-
57
- metrics = {}
58
- report_data.each do |topic, data|
59
- metrics[topic] = data['msgs']
60
- end
61
- metrics['latency'] = Droid::Utilization.latency
62
-
63
- summary = Droid::Utilization.report_summary(report_data)
64
-
65
- metrics['total_msgs'] = summary['msgs']
66
-
67
- status = "AMQP: #{summary['msgs']} msgs processed since #{Droid::Utilization.start.utc}"
68
-
69
- # reset metrics data
70
- Droid::Utilization.reinit
71
-
72
- data = {
73
- 'status' => status,
74
- 'state' => 'ok',
75
- 'metrics' => hash_to_metrics(metrics)
76
- }
77
- [200, data.to_json, "application/json"]
78
- end
79
-
80
- def hash_to_metrics(hash); self.class.hash_to_metrics(hash); end
81
-
82
- # utility method to convert a ruby hash to a metrics format
83
- # that can be consumed by cloudkick
84
- def self.hash_to_metrics(hash)
85
- hash.collect do |k,v|
86
- name = k.to_s
87
- value = v
88
- type = if v.kind_of?(Integer)
89
- 'int'
90
- elsif v.kind_of?(Float)
91
- 'float'
92
- else
93
- 'string'
94
- end
95
-
96
- # bool -> int conversion
97
- if [TrueClass, FalseClass].include?(v.class)
98
- value = v ? 1 : 0
99
- type = 'int'
100
- end
101
-
102
- # if type is really string then it should respond to .to_s
103
- value = value.to_s if type == 'string'
104
-
105
- { 'name' => name, 'type' => type, 'value' => value }
106
- end
107
- end
108
- end
5
+ class JSONServer < ::EM::Connection
6
+ include ::EM::HttpServer
7
+
8
+ def post_init
9
+ super
10
+ no_environment_strings
11
+ end
12
+
13
+ def process_http_request
14
+ return not_found_response if @http_request_method != "GET"
15
+
16
+ if @http_request_uri == "/"
17
+ default_response
18
+ else
19
+ method_name = "get_#{@http_request_uri.split("/")[1]}".gsub(/[^\d\w_]/,'').downcase
20
+ if public_methods.include?(method_name)
21
+ generate_response(method_name)
22
+ else
23
+ not_found_response
24
+ end
25
+ end
26
+ end
27
+
28
+ def generate_response(method_name)
29
+ status, data, content_type = self.send(method_name)
30
+
31
+ response = ::EM::DelegatedHttpResponse.new(self)
32
+ response.status = status
33
+ response.content_type content_type
34
+ response.content = data
35
+ response.send_response
36
+ end
37
+
38
+ def default_response
39
+ response = ::EM::DelegatedHttpResponse.new(self)
40
+ response.status = 200
41
+ response.content_type 'application/json'
42
+ response.content = {"status" => "OK"}.to_json
43
+ response.send_response
44
+ end
45
+
46
+ def not_found_response
47
+ response = ::EM::DelegatedHttpResponse.new(self)
48
+ response.status = 404
49
+ response.content_type 'text/plain'
50
+ response.content = "Not Found"
51
+ response.send_response
52
+ end
53
+
54
+ def get_droid
55
+ report_data = Droid::Utilization.report_data
56
+
57
+ metrics = {}
58
+ report_data.each do |topic, data|
59
+ metrics[topic] = data['msgs']
60
+ end
61
+ metrics['latency'] = Droid::Utilization.latency
62
+
63
+ summary = Droid::Utilization.report_summary(report_data)
64
+
65
+ metrics['total_msgs'] = summary['msgs']
66
+
67
+ status = "AMQP: #{summary['msgs']} msgs processed since #{Droid::Utilization.start.utc}"
68
+
69
+ # reset metrics data
70
+ Droid::Utilization.reinit
71
+
72
+ data = {
73
+ 'status' => status,
74
+ 'state' => 'ok',
75
+ 'metrics' => hash_to_metrics(metrics)
76
+ }
77
+ [200, data.to_json, "application/json"]
78
+ end
79
+
80
+ def hash_to_metrics(hash); self.class.hash_to_metrics(hash); end
81
+
82
+ # utility method to convert a ruby hash to a metrics format
83
+ # that can be consumed by cloudkick
84
+ def self.hash_to_metrics(hash)
85
+ hash.collect do |k,v|
86
+ name = k.to_s
87
+ value = v
88
+ type = if v.kind_of?(Integer)
89
+ 'int'
90
+ elsif v.kind_of?(Float)
91
+ 'float'
92
+ else
93
+ 'string'
94
+ end
95
+
96
+ # bool -> int conversion
97
+ if [TrueClass, FalseClass].include?(v.class)
98
+ value = v ? 1 : 0
99
+ type = 'int'
100
+ end
101
+
102
+ # if type is really string then it should respond to .to_s
103
+ value = value.to_s if type == 'string'
104
+
105
+ { 'name' => name, 'type' => type, 'value' => value }
106
+ end
107
+ end
108
+ end
109
109
  end