right_support 2.7.0 → 2.8.0

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.
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