right_support 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -23,7 +23,7 @@ group :development do
23
23
  gem "ruby-debug", ">= 0.10", :platforms => :ruby_18
24
24
  gem "ruby-debug19", ">= 0.11.6", :platforms => :ruby_19
25
25
  gem "rdoc", ">= 2.4.2"
26
- gem "flexmock", "~> 0.8"
26
+ gem "flexmock", "~> 1.0"
27
27
  gem "syntax", "~> 1.0.0" #rspec will syntax-highlight code snippets if this gem is available
28
28
  gem "nokogiri", "~> 1.5"
29
29
  end
data/Gemfile.lock CHANGED
@@ -1,16 +1,16 @@
1
1
  GIT
2
2
  remote: git@github.com:rightscale/right_develop.git
3
- revision: baabb68c392e1afdbff7d6cc21d87f9b1cdb2db6
3
+ revision: dedba69a68e8b56cc88db7d6dc518d42747b0586
4
4
  branch: master
5
5
  specs:
6
- right_develop (1.1.0)
6
+ right_develop (1.2.2)
7
7
  actionpack (>= 2.3.0, < 4.0)
8
8
  builder (~> 3.0)
9
9
  cucumber (~> 1.0)
10
10
  rake (>= 0.8.7, < 0.10)
11
11
  right_support (~> 2.0)
12
12
  rspec (>= 1.3, < 3.0)
13
- trollop (~> 1.0)
13
+ trollop (>= 1.0, < 3.0)
14
14
 
15
15
  GEM
16
16
  remote: http://rubygems.org/
@@ -21,16 +21,17 @@ GEM
21
21
  activesupport (2.3.18)
22
22
  addressable (2.2.8)
23
23
  archive-tar-minitar (0.5.2)
24
- builder (3.2.0)
24
+ builder (3.2.2)
25
25
  columnize (0.3.6)
26
- cucumber (1.2.5)
26
+ cucumber (1.3.3)
27
27
  builder (>= 2.1.2)
28
28
  diff-lcs (>= 1.1.3)
29
- gherkin (~> 2.11.7)
30
- multi_json (~> 1.3)
31
- diff-lcs (1.2.2)
32
- flexmock (0.9.0)
33
- gherkin (2.11.8)
29
+ gherkin (~> 2.12.0)
30
+ multi_json (~> 1.7.5)
31
+ multi_test (~> 0.0.1)
32
+ diff-lcs (1.2.4)
33
+ flexmock (1.3.2)
34
+ gherkin (2.12.0)
34
35
  multi_json (~> 1.3)
35
36
  git (1.2.5)
36
37
  jeweler (1.8.4)
@@ -46,7 +47,8 @@ GEM
46
47
  macaddr (1.6.1)
47
48
  systemu (~> 2.5.0)
48
49
  mime-types (1.22)
49
- multi_json (1.7.2)
50
+ multi_json (1.7.7)
51
+ multi_test (0.0.1)
50
52
  net-ssh (2.6.6)
51
53
  nokogiri (1.5.9)
52
54
  rack (1.1.6)
@@ -56,15 +58,15 @@ GEM
56
58
  json (~> 1.4)
57
59
  rest-client (1.6.7)
58
60
  mime-types (>= 1.16)
59
- right_support (2.6.17)
60
- rspec (2.13.0)
61
- rspec-core (~> 2.13.0)
62
- rspec-expectations (~> 2.13.0)
63
- rspec-mocks (~> 2.13.0)
64
- rspec-core (2.13.1)
65
- rspec-expectations (2.13.0)
61
+ right_support (2.7.0)
62
+ rspec (2.14.0)
63
+ rspec-core (~> 2.14.0)
64
+ rspec-expectations (~> 2.14.0)
65
+ rspec-mocks (~> 2.14.0)
66
+ rspec-core (2.14.0)
67
+ rspec-expectations (2.14.0)
66
68
  diff-lcs (>= 1.1.3, < 2.0)
67
- rspec-mocks (2.13.1)
69
+ rspec-mocks (2.14.1)
68
70
  ruby-debug (0.10.4)
69
71
  columnize (>= 0.1)
70
72
  ruby-debug-base (~> 0.10.4.0)
@@ -83,7 +85,7 @@ GEM
83
85
  simple_uuid (0.3.0)
84
86
  syntax (1.0.0)
85
87
  systemu (2.5.2)
86
- trollop (1.16.2)
88
+ trollop (2.0)
87
89
  uuid (2.3.7)
88
90
  macaddr (~> 1.0)
89
91
  uuidtools (2.1.3)
@@ -94,7 +96,7 @@ PLATFORMS
94
96
 
95
97
  DEPENDENCIES
96
98
  addressable (~> 2.2.7)
97
- flexmock (~> 0.8)
99
+ flexmock (~> 1.0)
98
100
  jeweler (~> 1.8.3)
99
101
  net-ssh (~> 2.0)
100
102
  nokogiri (~> 1.5)
data/Rakefile CHANGED
@@ -45,7 +45,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
45
45
  end
46
46
 
47
47
  require 'jeweler'
48
- Jeweler::Tasks.new do |gem|
48
+ tasks = Jeweler::Tasks.new do |gem|
49
49
  # gem is a Gem::Specification; see http://docs.rubygems.org/read/chapter/20 for more options
50
50
  gem.name = "right_support"
51
51
  gem.homepage = "https://github.com/rightscale/right_support"
@@ -55,6 +55,11 @@ Jeweler::Tasks.new do |gem|
55
55
  gem.email = "support@rightscale.com"
56
56
  gem.authors = ['Tony Spataro', 'Sergey Sergyenko', 'Ryan Williamson', 'Lee Kirchhoff', 'Alexey Karpik', 'Scott Messier']
57
57
  end
58
+
59
+ # Never auto-commit during operations that change the repository. Allows developers to decide on their own commit comment
60
+ # and/or aggregate version bumps into other fixes.
61
+ tasks.jeweler.commit = false
62
+
58
63
  Jeweler::RubygemsDotOrgTasks.new
59
64
 
60
65
  CLEAN.include('pkg')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.0
1
+ 2.8.0
@@ -233,7 +233,7 @@ module RightSupport::Net
233
233
  loop do
234
234
  if n > 0
235
235
  do_retry = @options[:retry] || DEFAULT_RETRY_PROC
236
- do_retry = do_retry.call(@ips || @endpoints, n) if do_retry.respond_to?(:call)
236
+ do_retry = do_retry.call((@ips.nil? || @ips.empty?) ? @endpoints : @ips, n) if do_retry.respond_to?(:call)
237
237
  break if (do_retry.is_a?(Integer) && n >= do_retry) || [nil, false].include?(do_retry)
238
238
  end
239
239
 
@@ -370,7 +370,7 @@ module RightSupport::Net
370
370
  @resolved_hostnames = RightSupport::Net::DNS.resolve_with_hostnames(@endpoints)
371
371
  resolved_endpoints = []
372
372
  @resolved_hostnames.each_value{ |v| resolved_endpoints.concat(v) }
373
- logger.info("RequestBalancer: resolved #{@endpoints.inspect} to #{resolved_endpoints.inspect}")
373
+ logger.info("RequestBalancer: resolved #{@endpoints.inspect} to #{resolved_endpoints.inspect}") if resolved_endpoints != @ips
374
374
  @ips = resolved_endpoints
375
375
  @policy.set_endpoints(@ips)
376
376
  @resolved_at = Time.now.to_i
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2012 RightScale Inc
1
+ # Copyright (c) 2009-2013 RightScale Inc
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -44,8 +44,7 @@ module RightSupport::Stats
44
44
 
45
45
  # Initialize activity data
46
46
  #
47
- # === Parameters
48
- # measure_rate(Boolean):: Whether to measure activity rate
47
+ # @param measure_rate [Boolean] Whether to measure activity rate
49
48
  def initialize(measure_rate = true)
50
49
  @measure_rate = measure_rate
51
50
  reset
@@ -53,8 +52,7 @@ module RightSupport::Stats
53
52
 
54
53
  # Reset statistics
55
54
  #
56
- # === Return
57
- # true:: Always return true
55
+ # @return [TrueClass] Always return true
58
56
  def reset
59
57
  @interval = 0.0
60
58
  @last_start_time = Time.now
@@ -67,17 +65,15 @@ module RightSupport::Stats
67
65
  end
68
66
 
69
67
  # Mark the start of an activity and update counts and average rate
70
- # with weighting toward recent activity
68
+ # with weighting toward past activity
71
69
  # Ignore the update if its type contains "stats"
72
70
  #
73
- # === Parameters
74
- # type(String|Symbol):: Type of activity, with anything that is not a symbol, true, or false
71
+ # @param type [String, Symbol] Type of activity, with anything that is not a symbol, true, or false
75
72
  # automatically converted to a String and truncated to MAX_TYPE_SIZE characters,
76
73
  # defaults to nil
77
- # id(String):: Unique identifier associated with this activity
74
+ # @param id [String] Unique identifier associated with this activity
78
75
  #
79
- # === Return
80
- # now(Time):: Update time
76
+ # @return [Time] Update time
81
77
  def update(type = nil, id = nil)
82
78
  now = Time.now
83
79
  if type.nil? || !(type =~ /stats/)
@@ -99,12 +95,10 @@ module RightSupport::Stats
99
95
 
100
96
  # Mark the finish of an activity and update the average duration
101
97
  #
102
- # === Parameters
103
- # start_time(Time):: Time when activity started, defaults to last time update was called
104
- # id(String):: Unique identifier associated with this activity
98
+ # @param start_time [Time] Time when activity started, defaults to last time update was called
99
+ # @param id [String] Unique identifier associated with this activity
105
100
  #
106
- # === Return
107
- # duration(Float):: Activity duration in seconds
101
+ # @return [Float] Activity duration in seconds
108
102
  def finish(start_time = nil, id = nil)
109
103
  now = Time.now
110
104
  start_time ||= @last_start_time
@@ -116,8 +110,7 @@ module RightSupport::Stats
116
110
 
117
111
  # Convert average interval to average rate
118
112
  #
119
- # === Return
120
- # (Float|nil):: Recent average rate, or nil if total is 0
113
+ # @return [Float, NilClass] Recent average rate, or nil if total is 0
121
114
  def avg_rate
122
115
  if @total > 0
123
116
  if @interval == 0.0 then 0.0 else 1.0 / @interval end
@@ -127,19 +120,18 @@ module RightSupport::Stats
127
120
 
128
121
  # Get average duration of activity
129
122
  #
130
- # === Return
131
- # (Float|nil) Average duration in seconds of activity weighted toward recent activity, or nil if total is 0
123
+ # @return [Float, NilClass] Average duration in seconds of activity weighted
124
+ # toward past activity, or nil if total is 0
132
125
  def avg_duration
133
126
  @avg_duration if @total > 0
134
127
  end
135
128
 
136
129
  # Get stats about last activity
137
130
  #
138
- # === Return
139
- # (Hash|nil):: Information about last activity, or nil if the total is 0
140
- # "elapsed"(Integer):: Seconds since last activity started
141
- # "type"(String):: Type of activity if specified, otherwise omitted
142
- # "active"(Boolean):: Whether activity still active
131
+ # @return [Hash, NilClass] Information about last activity, or nil if the total is 0
132
+ # "elapsed" [Integer] Seconds since last activity started
133
+ # "type" [String] Type of activity if specified, otherwise omitted
134
+ # "active" [Boolean] Whether activity still active
143
135
  def last
144
136
  if @total > 0
145
137
  result = {"elapsed" => (Time.now - @last_start_time).to_i}
@@ -151,10 +143,9 @@ module RightSupport::Stats
151
143
 
152
144
  # Convert count per type into percentage by type
153
145
  #
154
- # === Return
155
- # (Hash|nil):: Converted counts, or nil if total is 0
156
- # "total"(Integer):: Total activity count
157
- # "percent"(Hash):: Percentage for each type of activity if tracking type, otherwise omitted
146
+ # @return [Hash, NilClass] Converted counts, or nil if total is 0
147
+ # "total" [Integer] Total activity count
148
+ # "percent" [Hash] Percentage for each type of activity if tracking type, otherwise omitted
158
149
  def percentage
159
150
  if @total > 0
160
151
  percent = {}
@@ -165,15 +156,14 @@ module RightSupport::Stats
165
156
 
166
157
  # Get stat summary including all aspects of activity that were measured except duration
167
158
  #
168
- # === Return
169
- # (Hash|nil):: Information about activity, or nil if the total is 0
170
- # "total"(Integer):: Total activity count
171
- # "percent"(Hash):: Percentage for each type of activity if tracking type, otherwise omitted
172
- # "last"(Hash):: Information about last activity
173
- # "elapsed"(Integer):: Seconds since last activity started
174
- # "type"(String):: Type of activity if tracking type, otherwise omitted
175
- # "active"(Boolean):: Whether activity still active if tracking whether active, otherwise omitted
176
- # "rate"(Float):: Recent average rate if measuring rate, otherwise omitted
159
+ # @return [Hash, NilClass] Information about activity, or nil if the total is 0
160
+ # "total" [Integer] Total activity count
161
+ # "percent" [Hash] Percentage for each type of activity if tracking type, otherwise omitted
162
+ # "last" [Hash] Information about last activity
163
+ # "elapsed" [Integer] Seconds since last activity started
164
+ # "type" [String] Type of activity if tracking type, otherwise omitted
165
+ # "active" [Boolean] Whether activity still active if tracking whether active, otherwise omitted
166
+ # "rate" [Float] Recent average rate if measuring rate, otherwise omitted
177
167
  def all
178
168
  if @total > 0
179
169
  result = if @count_per_type.empty?
@@ -189,18 +179,87 @@ module RightSupport::Stats
189
179
 
190
180
  protected
191
181
 
192
- # Calculate smoothed average with weighting toward recent activity
182
+ # Calculate smoothed average with weighting toward past activity
193
183
  #
194
- # === Parameters
195
- # current(Float|Integer):: Current average value
196
- # value(Float|Integer):: New value
184
+ # @param current [Float, Integer] Current average value
185
+ # @param value [Float, Integer] New value
197
186
  #
198
- # === Return
199
- # (Float):: New average
187
+ # @return [Float] New average
200
188
  def average(current, value)
201
189
  ((current * (RECENT_SIZE - 1)) + value) / RECENT_SIZE.to_f
202
190
  end
203
191
 
192
+ public
193
+
194
+ # Aggregate the stats from multiple 'all' calls
195
+ #
196
+ # @param stats [Array] Hashes that are to be aggregated
197
+ #
198
+ # @return [Hash, NilClass] Summed information about activity, or nil if the total is 0
199
+ # "total" [Integer] Total activity count
200
+ # "percent" [Hash] Percentage for each type of activity if tracking type, otherwise omitted
201
+ # "last" [Hash] Information about last activity
202
+ # "elapsed" [Integer] Seconds since last activity started
203
+ # "type" [String] Type of activity if tracking type, otherwise omitted
204
+ # "active" [Boolean] Whether activity still active if tracking whether active, otherwise omitted
205
+ # "rate" [Float] Recent average rate if measuring rate, otherwise omitted
206
+ def self.all(stats)
207
+ if (total = stats.inject(0) { |t, s| t += s["total"] if s && s["total"]; t }) > 0
208
+ all = percentage(stats, total)
209
+ all["last"] = last(stats.map { |s| s["last"] if s })
210
+ rate = avg_rate(stats.map { |s| {"rate" => s["rate"], "total" => s["total"]} if s }, total)
211
+ all["rate"] = rate if rate
212
+ all
213
+ end
214
+ end
215
+
216
+ # Aggregate multiple percentage stats
217
+ #
218
+ # @param stats [Array] List of stats containing "percent" hash and "total" value
219
+ # @param total [Integer] Overall total
220
+ #
221
+ # @return [Hash] Converted counts
222
+ # "total" [Integer] Total activity count
223
+ # "percent" [Hash] Percentage for each type of activity if tracking type, omitted if no data
224
+ def self.percentage(stats, total)
225
+ count_per_type = {}
226
+ stats.each do |s|
227
+ if s
228
+ t = s["total"]
229
+ s["percent"].each do |k, v|
230
+ count_per_type[k] = (count_per_type[k] || 0) + ((v / 100.0) * t).round
231
+ end if s["percent"]
232
+ end
233
+ end
234
+ if count_per_type.empty?
235
+ {"total" => total}
236
+ else
237
+ percent = {}
238
+ count_per_type.each { |k, v| percent[k] = (v / total.to_f) * 100.0 }
239
+ {"percent" => percent, "total" => total}
240
+ end
241
+ end
242
+
243
+ # Compute average rate from multiple average rates
244
+ #
245
+ # @param stats [Array] List of stats containing hash of "rate" and "total"
246
+ # @param total [Integer] Overall total
247
+ #
248
+ # @return [Fixnum, NilClass] Average rate or nil if no average rate data
249
+ def self.avg_rate(stats, total)
250
+ sum = stats.inject(nil) { |sum, stat| sum = (sum || 0.0) + (stat["rate"] * stat["total"]) if stat["rate"]; sum }
251
+ sum / total if sum
252
+ end
253
+
254
+ # Determine last activity from multiple last activity stats
255
+ #
256
+ # @param stats [Array] Multiple last activity stats
257
+ #
258
+ # @return [Hash, NilClass] Last activity, or nil if no last activity data
259
+ def self.last(stats)
260
+ stats.inject(nil) { |l, s| l = s if s && (l.nil? || (l["elapsed"] > s["elapsed"] && (s["type"] || s["active"]))); l }
261
+ end
262
+
204
263
  end # Activity
205
264
 
206
265
  end # RightScale::Stats
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2012 RightScale Inc
1
+ # Copyright (c) 2009-2013 RightScale Inc
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -29,20 +29,19 @@ module RightSupport::Stats
29
29
  # Maximum number of recent exceptions to track per category
30
30
  MAX_RECENT_EXCEPTIONS = 10
31
31
 
32
- # (Hash) Exceptions raised per category with keys
33
- # "total"(Integer):: Total exceptions for this category
34
- # "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
32
+ # [Hash] Exceptions raised per category with keys
33
+ # "total" [Integer] Total exceptions for this category
34
+ # "recent" [Array] Most recent as a hash of "count", "type", "message", "when", and "where"
35
35
  attr_reader :stats
36
36
  alias :all :stats
37
37
 
38
38
  # Initialize exception data
39
39
  #
40
- # === Parameters
41
- # server(Object):: Server where exceptions are originating, must be defined for callbacks
42
- # callback(Proc):: Block with following parameters to be activated when an exception occurs
43
- # exception(Exception):: Exception
44
- # message(Packet):: Message being processed
45
- # server(Server):: Server where exception occurred
40
+ # @param server [Object] Server where exceptions are originating, must be defined for callbacks
41
+ # @param callback [Proc] Block with following parameters to be activated when an exception occurs
42
+ # exception [Exception] Exception
43
+ # message [Packet] Message being processed
44
+ # server [Server] Server where exception occurred
46
45
  def initialize(server = nil, callback = nil)
47
46
  @server = server
48
47
  @callback = callback
@@ -51,8 +50,7 @@ module RightSupport::Stats
51
50
 
52
51
  # Reset statistics
53
52
  #
54
- # === Return
55
- # true:: Always return true
53
+ # @return [TrueClass] Always return true
56
54
  def reset
57
55
  @stats = nil
58
56
  true
@@ -62,12 +60,10 @@ module RightSupport::Stats
62
60
  # Catch any exceptions since this function may be called from within an EM block
63
61
  # and an exception here would then derail EM
64
62
  #
65
- # === Parameters
66
- # category(String):: Exception category
67
- # exception(Exception):: Exception
63
+ # @param category [String] Exception category
64
+ # @param exception [Exception] Exception
68
65
  #
69
- # === Return
70
- # true:: Always return true
66
+ # @return [TrueClass] Always return true
71
67
  def track(category, exception, message = nil)
72
68
  begin
73
69
  @callback.call(exception, message, @server) if @server && @callback && message
@@ -91,6 +87,47 @@ module RightSupport::Stats
91
87
  true
92
88
  end
93
89
 
90
+ # Aggregate the stats from multiple 'all' calls
91
+ #
92
+ # @param stats [Array] Hashes that are to be aggregated
93
+ #
94
+ # @return [Hash, NilClass] Exceptions raised per category with keys
95
+ # "total" [Integer] Total exceptions for this category
96
+ # "recent" [Array] Most recent as a hash of "count", "type", "message", "when", and "where"
97
+ def self.all(stats)
98
+ all = nil
99
+ stats.each do |s|
100
+ if s
101
+ all ||= {}
102
+ s.each do |category, exceptions|
103
+ if (all_exceptions = all[category])
104
+ all_exceptions["total"] += exceptions["total"]
105
+ all_recent = all_exceptions["recent"]
106
+ exceptions["recent"].each do |e|
107
+ i = 0
108
+ last = nil
109
+ all_recent.each do |all_e|
110
+ break if e["when"] < all_e["when"] && (last.nil? || e["when"] >= last["when"])
111
+ last = all_e
112
+ i += 1
113
+ end
114
+ if last && last["type"] == e["type"] && last["message"] == e["message"] && last["where"] == e["where"]
115
+ last["count"] += e["count"]
116
+ last["when"] = e["when"]
117
+ else
118
+ all_recent.insert(i, e)
119
+ all_recent.shift if all_recent.size > MAX_RECENT_EXCEPTIONS
120
+ end
121
+ end
122
+ else
123
+ all[category] = exceptions
124
+ end
125
+ end
126
+ end
127
+ end
128
+ all
129
+ end
130
+
94
131
  end # Exceptions
95
132
 
96
133
  end # RightSupport::Stats