right_support 2.11.3 → 2.12.1
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.
- checksums.yaml +4 -4
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/lib/right_support/notifiers/airbrake.rb +194 -0
- data/lib/right_support/notifiers/base.rb +73 -0
- data/lib/right_support/notifiers/blacklisters/base.rb +48 -0
- data/lib/right_support/notifiers/blacklisters/canonical.rb +60 -0
- data/lib/right_support/notifiers/blacklisters/regular_expression.rb +86 -0
- data/{features/support/file_utils_bundler_mixin.rb → lib/right_support/notifiers/blacklisters/simple.rb} +21 -20
- data/lib/right_support/notifiers/blacklisters/snake_case.rb +60 -0
- data/lib/right_support/notifiers/blacklisters/wildcard.rb +65 -0
- data/lib/right_support/notifiers/blacklisters.rb +34 -0
- data/lib/right_support/notifiers/logger.rb +94 -0
- data/lib/right_support/notifiers/notification.rb +57 -0
- data/lib/right_support/notifiers/utilities/backtrace_decoder.rb +234 -0
- data/lib/right_support/notifiers/utilities.rb +29 -0
- data/lib/right_support/notifiers.rb +32 -0
- data/lib/right_support/rack/request_logger.rb +13 -9
- data/lib/right_support.rb +1 -0
- data/right_support.gemspec +19 -70
- metadata +17 -69
- data/.coveralls.yml +0 -2
- data/.rspec +0 -3
- data/.simplecov +0 -6
- data/.travis.yml +0 -13
- data/Gemfile +0 -51
- data/Gemfile.lock +0 -153
- data/features/balancer_error_handling.feature +0 -34
- data/features/balancer_health_check.feature +0 -33
- data/features/hash_tools.feature +0 -27
- data/features/http_client_timeout.feature +0 -19
- data/features/serialization.feature +0 -113
- data/features/step_definitions/hash_tools_steps.rb +0 -41
- data/features/step_definitions/http_client_steps.rb +0 -27
- data/features/step_definitions/request_balancer_steps.rb +0 -93
- data/features/step_definitions/ruby_steps.rb +0 -176
- data/features/step_definitions/serialization_steps.rb +0 -133
- data/features/step_definitions/server_steps.rb +0 -134
- data/features/support/env.rb +0 -148
- data/right_support.rconf +0 -9
- data/spec/config/feature_set_spec.rb +0 -83
- data/spec/crypto/signed_hash_spec.rb +0 -73
- data/spec/data/hash_tools_spec.rb +0 -602
- data/spec/data/mash_spec.rb +0 -313
- data/spec/data/token_spec.rb +0 -21
- data/spec/data/uuid_spec.rb +0 -45
- data/spec/db/cassandra_model_part1_spec.rb +0 -84
- data/spec/db/cassandra_model_part2_spec.rb +0 -73
- data/spec/db/cassandra_model_spec.rb +0 -375
- data/spec/fixtures/encrypted_priv_rsa.pem +0 -30
- data/spec/fixtures/good_priv_dsa.pem +0 -12
- data/spec/fixtures/good_priv_rsa.pem +0 -15
- data/spec/fixtures/good_pub_dsa.ssh +0 -1
- data/spec/fixtures/good_pub_rsa.pem +0 -5
- data/spec/fixtures/good_pub_rsa.ssh +0 -1
- data/spec/log/exception_logger_spec.rb +0 -76
- data/spec/log/filter_logger_spec.rb +0 -66
- data/spec/log/mixin_spec.rb +0 -141
- data/spec/log/multiplexer_spec.rb +0 -54
- data/spec/log/null_logger_spec.rb +0 -36
- data/spec/log/step_level_logger_spec.rb +0 -49
- data/spec/log/system_logger_spec.rb +0 -172
- data/spec/net/address_helper_spec.rb +0 -57
- data/spec/net/dns_spec.rb +0 -187
- data/spec/net/http_client_spec.rb +0 -181
- data/spec/net/lb/health_check_spec.rb +0 -417
- data/spec/net/lb/round_robin_spec.rb +0 -15
- data/spec/net/lb/sticky_spec.rb +0 -92
- data/spec/net/request_balancer_spec.rb +0 -690
- data/spec/net/s3_helper_spec.rb +0 -160
- data/spec/net/ssl_spec.rb +0 -42
- data/spec/net/string_encoder_spec.rb +0 -58
- data/spec/rack/log_setter_spec.rb +0 -5
- data/spec/rack/request_logger_spec.rb +0 -225
- data/spec/rack/request_tracker_spec.rb +0 -115
- data/spec/rack/runtime_spec.rb +0 -49
- data/spec/ruby/easy_singleton_spec.rb +0 -72
- data/spec/ruby/object_extensions_spec.rb +0 -27
- data/spec/ruby/string_extensions_spec.rb +0 -98
- data/spec/spec_helper.rb +0 -188
- data/spec/stats/activity_spec.rb +0 -425
- data/spec/stats/exceptions_spec.rb +0 -247
- data/spec/stats/helpers_spec.rb +0 -685
- data/spec/validation/openssl_spec.rb +0 -37
- data/spec/validation/ssh_spec.rb +0 -39
data/spec/stats/activity_spec.rb
DELETED
@@ -1,425 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2009-2012 RightScale Inc
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
|
23
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
24
|
-
|
25
|
-
describe RightSupport::Stats::Activity do
|
26
|
-
|
27
|
-
include FlexMock::ArgumentTypes
|
28
|
-
|
29
|
-
before(:all) do
|
30
|
-
@original_recent_size = RightSupport::Stats::Activity::RECENT_SIZE
|
31
|
-
RightSupport::Stats::Activity.instance_eval { remove_const(:RECENT_SIZE) }
|
32
|
-
RightSupport::Stats::Activity.const_set(:RECENT_SIZE, 10)
|
33
|
-
end
|
34
|
-
|
35
|
-
after(:all) do
|
36
|
-
RightSupport::Stats::Activity.instance_eval { remove_const(:RECENT_SIZE) }
|
37
|
-
RightSupport::Stats::Activity.const_set(:RECENT_SIZE, @original_recent_size)
|
38
|
-
end
|
39
|
-
|
40
|
-
before(:each) do
|
41
|
-
@now = 1000000
|
42
|
-
flexmock(Time).should_receive(:now).and_return(@now).by_default
|
43
|
-
@stats = RightSupport::Stats::Activity.new
|
44
|
-
end
|
45
|
-
|
46
|
-
context :initialize do
|
47
|
-
it "initializes stats data" do
|
48
|
-
@stats.instance_variable_get(:@interval).should == 0.0
|
49
|
-
@stats.instance_variable_get(:@last_start_time).should == @now
|
50
|
-
@stats.instance_variable_get(:@avg_latency).should be_nil
|
51
|
-
@stats.instance_variable_get(:@total).should == 0
|
52
|
-
@stats.instance_variable_get(:@count_per_type).should == {}
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context :update do
|
57
|
-
it "updates count and interval information" do
|
58
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
59
|
-
@stats.update
|
60
|
-
@stats.instance_variable_get(:@interval).should == 1.0
|
61
|
-
@stats.instance_variable_get(:@last_start_time).should == @now + 10
|
62
|
-
@stats.instance_variable_get(:@avg_latency).should be_nil
|
63
|
-
@stats.instance_variable_get(:@total).should == 1
|
64
|
-
@stats.instance_variable_get(:@count_per_type).should == {}
|
65
|
-
end
|
66
|
-
|
67
|
-
it "updates counts per type when type provided" do
|
68
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
69
|
-
@stats.update("test")
|
70
|
-
@stats.instance_variable_get(:@interval).should == 1.0
|
71
|
-
@stats.instance_variable_get(:@last_start_time).should == @now + 10
|
72
|
-
@stats.instance_variable_get(:@avg_latency).should be_nil
|
73
|
-
@stats.instance_variable_get(:@total).should == 1
|
74
|
-
@stats.instance_variable_get(:@count_per_type).should == {"test" => 1}
|
75
|
-
end
|
76
|
-
|
77
|
-
it "limits length of type string when submitting update" do
|
78
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
79
|
-
@stats.update("test 12345678901234567890123456789012345678901234567890123456789")
|
80
|
-
@stats.instance_variable_get(:@total).should == 1
|
81
|
-
@stats.instance_variable_get(:@count_per_type).should ==
|
82
|
-
{"test 1234567890123456789012345678901234567890123456789012..." => 1}
|
83
|
-
end
|
84
|
-
|
85
|
-
it "doesn't convert symbol or boolean to string when submitting update" do
|
86
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
87
|
-
@stats.update(:test)
|
88
|
-
@stats.update(true)
|
89
|
-
@stats.update(false)
|
90
|
-
@stats.instance_variable_get(:@total).should == 3
|
91
|
-
@stats.instance_variable_get(:@count_per_type).should == {:test => 1, true => 1, false => 1}
|
92
|
-
end
|
93
|
-
|
94
|
-
it "converts arbitrary type value to limited-length string when submitting update" do
|
95
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
96
|
-
@stats.update({1 => 11, 2 => 22})
|
97
|
-
@stats.update({1 => 11, 2 => 22, 3 => 12345678901234567890123456789012345678901234567890123456789})
|
98
|
-
@stats.instance_variable_get(:@total).should == 2
|
99
|
-
@stats.instance_variable_get(:@count_per_type).should == {"{1=>11, 2=>22}" => 1,
|
100
|
-
"{1=>11, 2=>22, 3=>123456789012345678901234567890123456789..." => 1}
|
101
|
-
end
|
102
|
-
|
103
|
-
it "doesn't measure rate if disabled" do
|
104
|
-
@stats = RightSupport::Stats::Activity.new(false)
|
105
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
106
|
-
@stats.update
|
107
|
-
@stats.instance_variable_get(:@interval).should == 0.0
|
108
|
-
@stats.instance_variable_get(:@last_start_time).should == @now + 10
|
109
|
-
@stats.instance_variable_get(:@avg_latency).should be_nil
|
110
|
-
@stats.instance_variable_get(:@total).should == 1
|
111
|
-
@stats.instance_variable_get(:@count_per_type).should == {}
|
112
|
-
end
|
113
|
-
|
114
|
-
it "tracks the id associated with the update" do
|
115
|
-
@stats.update("test", "id")
|
116
|
-
@stats.instance_variable_get(:@last_id).should == "id"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context :finish do
|
121
|
-
it "updates latency when finish using internal start time by default" do
|
122
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
123
|
-
@stats.avg_latency.should be_nil
|
124
|
-
@stats.finish
|
125
|
-
@stats.instance_variable_get(:@interval).should == 0.0
|
126
|
-
@stats.instance_variable_get(:@last_start_time).should == @now
|
127
|
-
@stats.instance_variable_get(:@avg_latency).should == 1.0
|
128
|
-
@stats.instance_variable_get(:@total).should == 0
|
129
|
-
@stats.instance_variable_get(:@count_per_type).should == {}
|
130
|
-
end
|
131
|
-
|
132
|
-
it "updates latency when finish using specified start time" do
|
133
|
-
flexmock(Time).should_receive(:now).and_return(1000030)
|
134
|
-
@stats.avg_latency.should be_nil
|
135
|
-
@stats.finish(1000010)
|
136
|
-
@stats.instance_variable_get(:@interval).should == 0.0
|
137
|
-
@stats.instance_variable_get(:@last_start_time).should == @now
|
138
|
-
@stats.instance_variable_get(:@avg_latency).should == 2.0
|
139
|
-
@stats.instance_variable_get(:@total).should == 0
|
140
|
-
@stats.instance_variable_get(:@count_per_type).should == {}
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
context :measure do
|
145
|
-
it "updates and finishes the activity" do
|
146
|
-
flexmock(Time).should_receive(:now).and_return(1000010, 1000020)
|
147
|
-
@stats.measure("test", "id") { }
|
148
|
-
@stats.instance_variable_get(:@interval).should == 1.0
|
149
|
-
@stats.instance_variable_get(:@last_start_time).should == @now + 10
|
150
|
-
@stats.instance_variable_get(:@total).should == 1
|
151
|
-
@stats.instance_variable_get(:@count_per_type).should == {"test" => 1}
|
152
|
-
@stats.instance_variable_get(:@last_id).should == 0
|
153
|
-
@stats.instance_variable_get(:@avg_latency).should == 1.0
|
154
|
-
end
|
155
|
-
|
156
|
-
it "yields to the block" do
|
157
|
-
called = 0
|
158
|
-
flexmock(Time).should_receive(:now).and_return(1000010, 1000030)
|
159
|
-
@stats.measure("test", "id") { called += 1}
|
160
|
-
called.should == 1
|
161
|
-
end
|
162
|
-
|
163
|
-
it "returns the result of the yield" do
|
164
|
-
@stats.measure("test", "id") { 99 }.should == 99
|
165
|
-
end
|
166
|
-
|
167
|
-
it "raises exception if block is missing" do
|
168
|
-
lambda { @stats.measure("test", "id") }.should raise_error(ArgumentError, "block missing")
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
context :avg_rate do
|
173
|
-
it "converts interval to rate" do
|
174
|
-
flexmock(Time).should_receive(:now).and_return(1000020, 1000042)
|
175
|
-
@stats.avg_rate.should be_nil
|
176
|
-
@stats.update
|
177
|
-
@stats.instance_variable_get(:@interval).should == 2.0
|
178
|
-
@stats.avg_rate.should == 0.25
|
179
|
-
end
|
180
|
-
|
181
|
-
it "adjusts rate based on interval since last event" do
|
182
|
-
flexmock(Time).should_receive(:now).and_return(1000020, 1000042, 1000086)
|
183
|
-
@stats.avg_rate.should be_nil
|
184
|
-
@stats.update
|
185
|
-
@stats.update
|
186
|
-
@stats.instance_variable_get(:@interval).should == 4.0
|
187
|
-
@stats.avg_rate.should == 0.125
|
188
|
-
end
|
189
|
-
|
190
|
-
it "sets rate to 0 if interval is 0" do
|
191
|
-
flexmock(Time).should_receive(:now).and_return(1000000, 1000000)
|
192
|
-
@stats.avg_rate.should be_nil
|
193
|
-
@stats.update
|
194
|
-
@stats.instance_variable_get(:@interval).should == 0.0
|
195
|
-
@stats.avg_rate.should == 0.0
|
196
|
-
end
|
197
|
-
|
198
|
-
it "does not compute average unless measuring rate is enabled" do
|
199
|
-
@stats = RightSupport::Stats::Activity.new(false)
|
200
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
201
|
-
@stats.update
|
202
|
-
@stats.avg_rate.should be_nil
|
203
|
-
end
|
204
|
-
|
205
|
-
it "does not compute average if there have been no events" do
|
206
|
-
@stats.avg_rate.should be_nil
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
context :last do
|
211
|
-
it "reports number of seconds since last update or nil if no updates" do
|
212
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
213
|
-
@stats.last.should be_nil
|
214
|
-
@stats.update
|
215
|
-
@stats.last.should == {"elapsed" => 0}
|
216
|
-
end
|
217
|
-
|
218
|
-
it "reports number of seconds since last update and last type" do
|
219
|
-
@stats.update("test")
|
220
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
221
|
-
@stats.last.should == {"elapsed" => 10, "type" => "test"}
|
222
|
-
end
|
223
|
-
|
224
|
-
it "reports whether last activity is still active" do
|
225
|
-
@stats.update("test", "token")
|
226
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
227
|
-
@stats.last.should == {"elapsed" => 10, "type" => "test", "active" => true}
|
228
|
-
@stats.finish(@now - 10, "token")
|
229
|
-
@stats.last.should == {"elapsed" => 10, "type" => "test", "active" => false}
|
230
|
-
@stats.instance_variable_get(:@avg_latency).should == 2.0
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
context :percentage do
|
235
|
-
it "converts count per type to percentages" do
|
236
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
237
|
-
@stats.update("foo")
|
238
|
-
@stats.instance_variable_get(:@total).should == 1
|
239
|
-
@stats.instance_variable_get(:@count_per_type).should == {"foo" => 1}
|
240
|
-
@stats.percentage.should == {"total" => 1, "percent" => {"foo" => 100.0}}
|
241
|
-
@stats.update("bar")
|
242
|
-
@stats.instance_variable_get(:@total).should == 2
|
243
|
-
@stats.instance_variable_get(:@count_per_type).should == {"foo" => 1, "bar" => 1}
|
244
|
-
@stats.percentage.should == {"total" => 2, "percent" => {"foo" => 50.0, "bar" => 50.0}}
|
245
|
-
@stats.update("foo")
|
246
|
-
@stats.update("foo")
|
247
|
-
@stats.instance_variable_get(:@total).should == 4
|
248
|
-
@stats.instance_variable_get(:@count_per_type).should == {"foo" => 3, "bar" => 1}
|
249
|
-
@stats.percentage.should == {"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
context :all do
|
254
|
-
it "returns all activity aspects that were measured" do
|
255
|
-
flexmock(Time).should_receive(:now).and_return(1000020, 1000042)
|
256
|
-
@stats.update
|
257
|
-
@stats.finish
|
258
|
-
@stats.all.should == {"last" => {"elapsed" => 22}, "total" => 1, "rate" => 0.25, "latency" => 2.2}
|
259
|
-
end
|
260
|
-
|
261
|
-
it "excludes rate if it is not being measured" do
|
262
|
-
@stats = RightSupport::Stats::Activity.new(false)
|
263
|
-
flexmock(Time).should_receive(:now).and_return(1000020, 1000042)
|
264
|
-
@stats.update
|
265
|
-
@stats.finish
|
266
|
-
@stats.all.should == {"last" => {"elapsed" => 22}, "total" => 1, "latency" => 2.2}
|
267
|
-
end
|
268
|
-
|
269
|
-
it "excludes latency if it is not being measured" do
|
270
|
-
flexmock(Time).should_receive(:now).and_return(1000020, 1000042)
|
271
|
-
@stats.update
|
272
|
-
@stats.all.should == {"last" => {"elapsed" => 22}, "total" => 1, "rate" => 0.25}
|
273
|
-
end
|
274
|
-
|
275
|
-
it "includes percentage breakdown when update recorded per type" do
|
276
|
-
@stats = RightSupport::Stats::Activity.new(false)
|
277
|
-
flexmock(Time).should_receive(:now).and_return(1000010, 1000010, 1000020, 1000020, 1000030, 1000030, 1000040)
|
278
|
-
@stats.update("foo")
|
279
|
-
@stats.all.should == {"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}}
|
280
|
-
@stats.update("bar")
|
281
|
-
@stats.all.should == {"last" => {"elapsed" => 0, "type" => "bar"}, "total" => 2, "percent" => {"foo" => 50.0, "bar" => 50.0}}
|
282
|
-
@stats.update("bar")
|
283
|
-
@stats.update("foo")
|
284
|
-
@stats.all.should == {"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 4, "percent" => {"foo" => 50.0, "bar" => 50.0}}
|
285
|
-
end
|
286
|
-
|
287
|
-
it "returns nil if there was no activity" do
|
288
|
-
@stats.all.should be_nil
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
context :average do
|
293
|
-
it "weights average toward past activity" do
|
294
|
-
@stats.send(:average, 0.0, 10.0).should == 1.0
|
295
|
-
@stats.send(:average, 1.0, 10.0).should == 1.9
|
296
|
-
@stats.send(:average, 1.9, 10.0).should == 2.71
|
297
|
-
@stats.send(:average, 2.71, 10.0).should == 3.439
|
298
|
-
@stats.send(:average, 3.439, 10.0).should == 4.0951
|
299
|
-
@stats.send(:average, 4.0951, 10.0).should == 4.68559
|
300
|
-
@stats.send(:average, 4.68559, 10.0).should == 5.217031
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
describe "class methods" do
|
305
|
-
|
306
|
-
context :all do
|
307
|
-
it "aggregates stats from multiple all calls" do
|
308
|
-
stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
|
309
|
-
{"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}}]
|
310
|
-
RightSupport::Stats::Activity.all(stats).should ==
|
311
|
-
{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}}
|
312
|
-
end
|
313
|
-
|
314
|
-
it "includes rate if provided" do
|
315
|
-
stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}, "rate" => 0.5},
|
316
|
-
{"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}, "rate" => 0.1}]
|
317
|
-
RightSupport::Stats::Activity.all(stats).should ==
|
318
|
-
{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}, "rate" => 0.18}
|
319
|
-
end
|
320
|
-
|
321
|
-
it "includes latency if provided" do
|
322
|
-
stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}, "rate" => 0.5, "latency" => 0.5},
|
323
|
-
{"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}, "rate" => 0.1, "latency" => 0.1}]
|
324
|
-
RightSupport::Stats::Activity.all(stats).should ==
|
325
|
-
{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}, "rate" => 0.18, "latency" => 0.18}
|
326
|
-
end
|
327
|
-
|
328
|
-
it "handles nil stat" do
|
329
|
-
stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
|
330
|
-
nil,
|
331
|
-
{"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}}]
|
332
|
-
RightSupport::Stats::Activity.all(stats).should ==
|
333
|
-
{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}}
|
334
|
-
end
|
335
|
-
|
336
|
-
it "returns nil if there are no stats" do
|
337
|
-
RightSupport::Stats::Activity.all([]).should be_nil
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
context :percentage do
|
342
|
-
it "aggregates multiple percentage stats" do
|
343
|
-
stats = [{"total" => 1, "percent" => {"foo" => 100.0}},
|
344
|
-
{"total" => 5, "percent" => {"bar" => 100.0}},
|
345
|
-
{"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}]
|
346
|
-
RightSupport::Stats::Activity.percentage(stats, 10).should == {"total" => 10, "percent" => {"foo" => 40.0, "bar" => 60.0}}
|
347
|
-
end
|
348
|
-
|
349
|
-
it "handles nil stat" do
|
350
|
-
stats = [{"total" => 1, "percent" => {"foo" => 100.0}},
|
351
|
-
nil,
|
352
|
-
{"total" => 5, "percent" => {"bar" => 100.0}},
|
353
|
-
nil,
|
354
|
-
{"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}]
|
355
|
-
RightSupport::Stats::Activity.percentage(stats, 10).should == {"total" => 10, "percent" => {"foo" => 40.0, "bar" => 60.0}}
|
356
|
-
end
|
357
|
-
|
358
|
-
it "returns only total if there is no data" do
|
359
|
-
RightSupport::Stats::Activity.percentage([], 0).should == {"total" => 0}
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
context :avg_rate do
|
364
|
-
it "computes average rate from multiple average rates" do
|
365
|
-
stats = [{"total" => 1, "rate" => 0.5},
|
366
|
-
{"total" => 5, "rate" => 0.1},
|
367
|
-
{"total" => 4, "rate" => 0.2}]
|
368
|
-
RightSupport::Stats::Activity.avg_rate(stats, 10).should == 0.18
|
369
|
-
end
|
370
|
-
|
371
|
-
it "handles nil stat" do
|
372
|
-
stats = [{"total" => 1, "rate" => 0.5},
|
373
|
-
nil,
|
374
|
-
{"total" => 5, "rate" => 0.1},
|
375
|
-
nil,
|
376
|
-
{"total" => 4, "rate" => 0.2}]
|
377
|
-
RightSupport::Stats::Activity.avg_rate(stats, 10).should == 0.18
|
378
|
-
end
|
379
|
-
|
380
|
-
it "returns nil if there is no data" do
|
381
|
-
RightSupport::Stats::Activity.avg_rate([], 0).should be_nil
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
|
-
context :avg_latency do
|
386
|
-
it "computes average latency from multiple average latencies" do
|
387
|
-
stats = [{"total" => 1, "latency" => 0.5},
|
388
|
-
{"total" => 5, "latency" => 0.1},
|
389
|
-
{"total" => 4, "latency" => 0.2}]
|
390
|
-
RightSupport::Stats::Activity.avg_latency(stats, 10).should == 0.18
|
391
|
-
end
|
392
|
-
|
393
|
-
it "handles nil stat" do
|
394
|
-
stats = [{"total" => 1, "latency" => 0.5},
|
395
|
-
nil,
|
396
|
-
{"total" => 5, "latency" => 0.1},
|
397
|
-
nil,
|
398
|
-
{"total" => 4, "latency" => 0.2}]
|
399
|
-
RightSupport::Stats::Activity.avg_latency(stats, 10).should == 0.18
|
400
|
-
end
|
401
|
-
|
402
|
-
it "returns nil if there is no data" do
|
403
|
-
RightSupport::Stats::Activity.avg_latency([], 0).should be_nil
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
context :last do
|
408
|
-
it "determines last activity from multiple last activity stats" do
|
409
|
-
stats = [{"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
|
410
|
-
{"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}}]
|
411
|
-
end
|
412
|
-
|
413
|
-
it "handles nil stat" do
|
414
|
-
stats = [{"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
|
415
|
-
nil,
|
416
|
-
{"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}}]
|
417
|
-
end
|
418
|
-
|
419
|
-
it "returns nil if there is no data" do
|
420
|
-
RightSupport::Stats::Activity.last([]).should be_nil
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
end # RightSupport::Stats::Activity
|
@@ -1,247 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2009-2012 RightScale Inc
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
|
23
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
24
|
-
|
25
|
-
describe RightSupport::Stats::Exceptions do
|
26
|
-
|
27
|
-
include FlexMock::ArgumentTypes
|
28
|
-
|
29
|
-
before(:each) do
|
30
|
-
@now = 1000000
|
31
|
-
flexmock(Time).should_receive(:now).and_return(@now).by_default
|
32
|
-
@stats = RightSupport::Stats::Exceptions.new
|
33
|
-
@exception = Exception.new("Test error")
|
34
|
-
end
|
35
|
-
|
36
|
-
context :initialize do
|
37
|
-
it "initializes stats data" do
|
38
|
-
@stats.stats.should be_nil
|
39
|
-
@stats.instance_variable_get(:@callback).should be_nil
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context :reset do
|
44
|
-
it "clears any currently stored exceptions" do
|
45
|
-
@stats.track("testing", @exception)
|
46
|
-
@stats.stats.should_not be_nil
|
47
|
-
@stats.reset
|
48
|
-
@stats.stats.should be_nil
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context :track do
|
53
|
-
it "tracks submitted exception information by category" do
|
54
|
-
@stats.track("testing", @exception)
|
55
|
-
@stats.stats.should == {"testing" => {"total" => 1,
|
56
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
57
|
-
"when" => @now, "where" => nil}]}}
|
58
|
-
end
|
59
|
-
|
60
|
-
it "tracks where exception occurred if it has a backtrace" do
|
61
|
-
begin
|
62
|
-
raise Exception.new("Test error")
|
63
|
-
rescue Exception => e
|
64
|
-
@exception = e
|
65
|
-
end
|
66
|
-
@stats.track("testing", @exception)
|
67
|
-
@stats.stats["testing"]["recent"][0]["where"].should =~ /spec\/stats\/exceptions_spec.rb/
|
68
|
-
end
|
69
|
-
|
70
|
-
it "recognizes and counts repeated exceptions" do
|
71
|
-
@stats.track("testing", @exception)
|
72
|
-
@stats.stats.should == {"testing" => {"total" => 1,
|
73
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
74
|
-
"when" => @now, "where" => nil}]}}
|
75
|
-
flexmock(Time).should_receive(:now).and_return(1000010)
|
76
|
-
category = "another"
|
77
|
-
backtrace = ["here", "and", "there"]
|
78
|
-
4.times do |i|
|
79
|
-
begin
|
80
|
-
raise ArgumentError, "badarg"
|
81
|
-
rescue Exception => e
|
82
|
-
flexmock(e).should_receive(:backtrace).and_return(backtrace)
|
83
|
-
@stats.track(category, e)
|
84
|
-
backtrace.shift(2) if i == 1
|
85
|
-
category = "testing" if i == 2
|
86
|
-
end
|
87
|
-
end
|
88
|
-
@stats.stats.should == {"testing" => {"total" => 2,
|
89
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
90
|
-
"when" => @now, "where" => nil},
|
91
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
92
|
-
"when" => @now + 10, "where" => "there"}]},
|
93
|
-
"another" => {"total" => 3,
|
94
|
-
"recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
95
|
-
"when" => @now + 10, "where" => "here"},
|
96
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
97
|
-
"when" => @now + 10, "where" => "there"}]}}
|
98
|
-
end
|
99
|
-
|
100
|
-
it "limits the number of exceptions stored by eliminating older exceptions" do
|
101
|
-
(RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1).times do |i|
|
102
|
-
begin
|
103
|
-
raise ArgumentError, "badarg"
|
104
|
-
rescue Exception => e
|
105
|
-
flexmock(e).should_receive(:backtrace).and_return([i.to_s])
|
106
|
-
@stats.track("testing", e)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
stats = @stats.stats
|
110
|
-
stats["testing"]["total"].should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1
|
111
|
-
stats["testing"]["recent"].size.should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS
|
112
|
-
stats["testing"]["recent"][0]["where"].should == "1"
|
113
|
-
end
|
114
|
-
|
115
|
-
it "makes callback if callback and message defined" do
|
116
|
-
called = 0
|
117
|
-
callback = lambda do |exception, message, server|
|
118
|
-
called += 1
|
119
|
-
exception.should == @exception
|
120
|
-
message.should == "message"
|
121
|
-
server.should == "server"
|
122
|
-
end
|
123
|
-
@stats = RightSupport::Stats::Exceptions.new("server", callback)
|
124
|
-
@stats.track("testing", @exception, "message")
|
125
|
-
@stats.stats.should == {"testing" => {"total" => 1,
|
126
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
127
|
-
"when" => @now, "where" => nil}]}}
|
128
|
-
called.should == 1
|
129
|
-
end
|
130
|
-
|
131
|
-
it "includes category parameter in callback if callback supports it" do
|
132
|
-
called = 0
|
133
|
-
callback = lambda do |exception, message, server, category|
|
134
|
-
called += 1
|
135
|
-
exception.should == @exception
|
136
|
-
message.should == "message"
|
137
|
-
server.should == "server"
|
138
|
-
category.should == "testing"
|
139
|
-
end
|
140
|
-
@stats = RightSupport::Stats::Exceptions.new("server", callback)
|
141
|
-
@stats.track("testing", @exception, "message")
|
142
|
-
@stats.stats.should == {"testing" => {"total" => 1,
|
143
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
144
|
-
"when" => @now, "where" => nil}]}}
|
145
|
-
called.should == 1
|
146
|
-
end
|
147
|
-
|
148
|
-
it "catches any exceptions raised internally and log them" do
|
149
|
-
begin
|
150
|
-
logger = flexmock("logger")
|
151
|
-
logger.should_receive(:error).with(/Failed to track exception 'Test error' \(Exception: bad IN/).once
|
152
|
-
RightSupport::Log::Mixin.default_logger = logger
|
153
|
-
flexmock(@exception).should_receive(:backtrace).and_raise(Exception.new("bad"))
|
154
|
-
@stats = RightSupport::Stats::Exceptions.new
|
155
|
-
@stats.track("testing", @exception, "message")
|
156
|
-
@stats.stats["testing"]["total"].should == 1
|
157
|
-
ensure
|
158
|
-
RightSupport::Log::Mixin.default_logger = nil
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
context :all do
|
164
|
-
it "returns current stats" do
|
165
|
-
@stats.track("testing", @exception)
|
166
|
-
@stats.all.should == {"testing" => {"total" => 1,
|
167
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
168
|
-
"when" => @now, "where" => nil}]}}
|
169
|
-
end
|
170
|
-
|
171
|
-
it "returns nil if there are no stats" do
|
172
|
-
@stats.all.should be_nil
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
describe "class methods" do
|
177
|
-
|
178
|
-
context :all do
|
179
|
-
before(:each) do
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
it "aggregates the stats from multiple all calls" do
|
184
|
-
stats = [{"testing" => {"total" => 3,
|
185
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
186
|
-
"when" => @now, "where" => nil},
|
187
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
188
|
-
"when" => @now + 20, "where" => "there"},
|
189
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
190
|
-
"when" => @now + 30, "where" => "everywhere"}]}},
|
191
|
-
{"testing" => {"total" => 5,
|
192
|
-
"recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
193
|
-
"when" => @now + 10, "where" => "here"},
|
194
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
195
|
-
"when" => @now + 15, "where" => "there"},
|
196
|
-
{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
197
|
-
"when" => @now + 30, "where" => "everywhere"}]}},
|
198
|
-
nil,
|
199
|
-
{"testing" => {"total" => 1,
|
200
|
-
"recent" => [{"count" => 1, "type" => "ArgumentError", "message" => "awfularg",
|
201
|
-
"when" => @now + 10, "where" => "here"}]}},
|
202
|
-
{"another" => {"total" => 3,
|
203
|
-
"recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
204
|
-
"when" => @now + 10, "where" => "here"},
|
205
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
206
|
-
"when" => @now + 10, "where" => "there"}]}}]
|
207
|
-
|
208
|
-
RightSupport::Stats::Exceptions.all(stats).should ==
|
209
|
-
{"testing" => {"total" => 9,
|
210
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
211
|
-
"when" => @now, "where" => nil},
|
212
|
-
{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
213
|
-
"when" => @now + 10, "where" => "here"},
|
214
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "awfularg",
|
215
|
-
"when" => @now + 10, "where" => "here"},
|
216
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
217
|
-
"when" => @now + 15, "where" => "there"},
|
218
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
219
|
-
"when" => @now + 20, "where" => "there"},
|
220
|
-
{"count" => 3, "type" => "ArgumentError", "message" => "badarg",
|
221
|
-
"when" => @now + 30, "where" => "everywhere"}]},
|
222
|
-
"another" => {"total" => 3,
|
223
|
-
"recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
224
|
-
"when" => @now + 10, "where" => "here"},
|
225
|
-
{"count" => 1, "type" => "ArgumentError", "message" => "badarg",
|
226
|
-
"when" => @now + 10, "where" => "there"}]}}
|
227
|
-
end
|
228
|
-
|
229
|
-
it "does not allow max exceptions to exceed set limit" do
|
230
|
-
max = RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS
|
231
|
-
stats = []
|
232
|
-
((max / 2) + 1).times do |i|
|
233
|
-
stats << {"testing" => {"total" => 1,
|
234
|
-
"recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
|
235
|
-
"when" => @now + i, "where" => nil},
|
236
|
-
{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
237
|
-
"when" => @now + i, "where" => "here"}]}}
|
238
|
-
end
|
239
|
-
all = RightSupport::Stats::Exceptions.all(stats)
|
240
|
-
all["testing"]["recent"].size.should == max
|
241
|
-
all["testing"]["recent"][max - 1].should == {"count" => 2, "type" => "ArgumentError", "message" => "badarg",
|
242
|
-
"when" => @now + (max / 2), "where" => "here"}
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
end # RightSupport::Stats::Exceptions
|