harness 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +72 -3
- data/harness.gemspec +2 -0
- data/lib/harness.rb +22 -28
- data/lib/harness/consumer.rb +0 -12
- data/lib/harness/counter.rb +5 -1
- data/lib/harness/gauge.rb +1 -1
- data/lib/harness/job.rb +23 -0
- data/lib/harness/measurement.rb +21 -0
- data/lib/harness/meter.rb +55 -0
- data/lib/harness/queues/resque_queue.rb +29 -0
- data/lib/harness/queues/sidekiq_queue.rb +29 -0
- data/lib/harness/queues/syncronous_queue.rb +13 -0
- data/lib/harness/railtie.rb +12 -4
- data/lib/harness/version.rb +1 -1
- data/test/integration/counters_with_redis_test.rb +22 -3
- data/test/integration/meter_test.rb +32 -0
- data/test/integration/queues/resque_test.rb +24 -0
- data/test/integration/queues/sidekiq_test.rb +34 -0
- data/test/test_helper.rb +5 -4
- data/test/unit/counter_test.rb +10 -0
- data/test/unit/gauge_test.rb +10 -0
- data/test/unit/harness_test.rb +12 -0
- data/test/unit/measurement_test.rb +33 -0
- data/test/unit/meter_test.rb +0 -0
- metadata +53 -12
data/README.md
CHANGED
@@ -8,6 +8,39 @@ Currently Supported Services:
|
|
8
8
|
|
9
9
|
* Librato
|
10
10
|
|
11
|
+
Current Features:
|
12
|
+
|
13
|
+
* Track counters over time (# of registered users)
|
14
|
+
* Read time specific values (# time to cache something)
|
15
|
+
* Build meters on top of counters (# requests per second)
|
16
|
+
* Sidekiq integration
|
17
|
+
* Resque integration
|
18
|
+
* Rails integration
|
19
|
+
* Capture and log all measurements coming out of Rails
|
20
|
+
|
21
|
+
**Crash Course**
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class ComplicatedClass
|
25
|
+
def hard_work
|
26
|
+
# Automatically track how long each of these calls takes so they can
|
27
|
+
# tracked and compared over time.
|
28
|
+
ActiveSupport::Notifications.instrument "hard_work", :gauge => true do
|
29
|
+
# do hard_work
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def register_user
|
34
|
+
# Automatically track the total # of registered users you have.
|
35
|
+
# As well, as be able to take measurements of users created in a
|
36
|
+
# specific interval
|
37
|
+
ActiveSupport::Notifications.instrument "register_user", :counter => true do
|
38
|
+
# register_user
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
11
44
|
## Installation
|
12
45
|
|
13
46
|
Add this line to your application's Gemfile:
|
@@ -28,7 +61,8 @@ In the metrics world there are two types of things: Gauges and Counters.
|
|
28
61
|
Gauges are time senstive and represent something at a specific point in
|
29
62
|
time. Counters keep track of things and should be increasing. Counters
|
30
63
|
can be reset back to zero. You can combine counters and/or gauges to
|
31
|
-
correlate data about your application.
|
64
|
+
correlate data about your application. Meters monitor counters. They
|
65
|
+
allow you look at rates of counters (read: counters per second).
|
32
66
|
|
33
67
|
Harness makes this process easily. Harness' primary goal it make it dead
|
34
68
|
simple to start measuring different parts of your application.
|
@@ -78,7 +112,30 @@ for that gauge or counter.
|
|
78
112
|
Harness will do all the extra work in sending these metrics to whatever
|
79
113
|
service you're using.
|
80
114
|
|
81
|
-
|
115
|
+
Once you the counters are you are instrumented, then you can meter them.
|
116
|
+
Meters allow you take arbitary readings of counter rates. The results
|
117
|
+
return a gauge so they can be logged as well.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
# Define a counter
|
121
|
+
class MyClass
|
122
|
+
def important_method(stuff)
|
123
|
+
ActiveSupport::Notifications.instrument "important_method.my_class", :counter => true do
|
124
|
+
do_important_stuff
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Now you can meter it
|
130
|
+
meter = Harnes::Meter.new('important_method.my_class')
|
131
|
+
meter.per_second # returns a gauge
|
132
|
+
meter.per_second.value # if you just want the number
|
133
|
+
meter.per(1.hour).value # You can use your own interval
|
134
|
+
meter.per_minute
|
135
|
+
meter.per_hour
|
136
|
+
```
|
137
|
+
|
138
|
+
## Customizing
|
82
139
|
|
83
140
|
You can pash a hash to `:counter` or `:gauge` to initialize the
|
84
141
|
measurement your own way.
|
@@ -157,7 +214,7 @@ default values are used. You can customize this in an initializer:
|
|
157
214
|
require 'erb'
|
158
215
|
|
159
216
|
file = Rails.root.join 'config', 'resque.yml'
|
160
|
-
config = YAML.load(ERB.new(File.read(Rails.root.join('config', '
|
217
|
+
config = YAML.load(ERB.new(File.read(Rails.root.join('config', 'redis.yml'))).result)
|
161
218
|
|
162
219
|
Harness.redis = Redis.new(:url => config[Rails.env])
|
163
220
|
```
|
@@ -170,6 +227,18 @@ Measurements are completely ignored in the test env. They are processed
|
|
170
227
|
in development mode, but not sent to the external service. Everything is
|
171
228
|
logged in production.
|
172
229
|
|
230
|
+
### Background Processing
|
231
|
+
|
232
|
+
Harness integrates automatically with Resque or Sidekiq. This is because
|
233
|
+
reporting measurements can take time and add unncessary overhead to the
|
234
|
+
response time. If neither of these libraries are present, measurements
|
235
|
+
**will be posted in realtime.** You can set your own queue by
|
236
|
+
specifiying a class like so:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
Harness.config.queue = MyCustomQueue
|
240
|
+
```
|
241
|
+
|
173
242
|
## Contributing
|
174
243
|
|
175
244
|
1. Fork it
|
data/harness.gemspec
CHANGED
data/lib/harness.rb
CHANGED
@@ -2,32 +2,41 @@ require "harness/version"
|
|
2
2
|
|
3
3
|
require 'thread'
|
4
4
|
|
5
|
-
require 'securerandom'
|
6
|
-
|
7
5
|
require 'redis'
|
8
6
|
require 'redis/namespace'
|
9
7
|
|
10
8
|
require 'active_support/notifications'
|
11
9
|
require 'active_support/core_ext/string'
|
10
|
+
require 'active_support/core_ext/hash/keys'
|
11
|
+
require 'active_support/core_ext/numeric'
|
12
|
+
require 'active_support/core_ext/integer'
|
12
13
|
|
13
14
|
module Harness
|
14
15
|
class LoggingError < RuntimeError ; end
|
16
|
+
class NoCounter < RuntimeError ; end
|
15
17
|
|
16
18
|
class Config
|
17
|
-
attr_reader :adapter
|
18
|
-
attr_accessor :syncronous
|
19
|
+
attr_reader :adapter, :queue
|
19
20
|
|
20
21
|
def adapter=(val)
|
21
22
|
if val.is_a? Symbol
|
22
|
-
@adapter = "Harness::#{val.to_s.
|
23
|
+
@adapter = "Harness::#{val.to_s.camelize}Adapter".constantize
|
23
24
|
else
|
24
25
|
@adapter = val
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
def queue=(val)
|
30
|
+
if val.is_a? Symbol
|
31
|
+
@queue= "Harness::#{val.to_s.camelize}Queue".constantize
|
32
|
+
else
|
33
|
+
@queue= val
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
28
37
|
def method_missing(name, *args, &block)
|
29
38
|
begin
|
30
|
-
"Harness::#{name.to_s.
|
39
|
+
"Harness::#{name.to_s.camelize}Adapter".constantize.config
|
31
40
|
rescue NameError
|
32
41
|
super
|
33
42
|
end
|
@@ -38,25 +47,8 @@ module Harness
|
|
38
47
|
@config ||= Config.new
|
39
48
|
end
|
40
49
|
|
41
|
-
def self.queue
|
42
|
-
@queue ||= Queue.new
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.consumer
|
46
|
-
Thread.current["#{object_id}_harness_consumer_"] ||= Consumer.new
|
47
|
-
end
|
48
|
-
|
49
50
|
def self.log(measurement)
|
50
|
-
queue
|
51
|
-
wait if config.syncronous
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.mutex
|
55
|
-
@mutex ||= Mutex.new
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.wait
|
59
|
-
sleep 0.01 until consumer.finished? && queue.empty?
|
51
|
+
config.queue.push measurement
|
60
52
|
end
|
61
53
|
|
62
54
|
def self.logger
|
@@ -77,7 +69,8 @@ module Harness
|
|
77
69
|
|
78
70
|
def self.reset_counters!
|
79
71
|
redis.smembers('counters').each do |counter|
|
80
|
-
redis.set counter,
|
72
|
+
redis.set counter, 0
|
73
|
+
redis.del "meters/#{counter}"
|
81
74
|
end
|
82
75
|
end
|
83
76
|
end
|
@@ -85,10 +78,13 @@ end
|
|
85
78
|
require 'harness/measurement'
|
86
79
|
require 'harness/counter'
|
87
80
|
require 'harness/gauge'
|
81
|
+
require 'harness/meter'
|
88
82
|
|
89
83
|
require 'harness/instrumentation'
|
90
84
|
|
91
|
-
require 'harness/
|
85
|
+
require 'harness/job'
|
86
|
+
|
87
|
+
require 'harness/queues/syncronous_queue'
|
92
88
|
|
93
89
|
require 'harness/adapters/librato_adapter'
|
94
90
|
require 'harness/adapters/memory_adapter'
|
@@ -101,8 +97,6 @@ require 'harness/integration/active_support'
|
|
101
97
|
|
102
98
|
require 'harness/railtie' if defined?(Rails)
|
103
99
|
|
104
|
-
Harness.consumer.consume
|
105
|
-
|
106
100
|
require 'logger'
|
107
101
|
|
108
102
|
Harness.logger = Logger.new $stdout
|
data/lib/harness/consumer.rb
CHANGED
@@ -4,18 +4,6 @@ module Harness
|
|
4
4
|
Thread.new do
|
5
5
|
while measurement = queue.pop
|
6
6
|
begin
|
7
|
-
logger.debug "[Harness] Processing Measurement: #{measurement.inspect}"
|
8
|
-
|
9
|
-
case measurement.class.to_s.demodulize.underscore.to_sym
|
10
|
-
when :gauge
|
11
|
-
adapter.log_gauge measurement
|
12
|
-
when :counter
|
13
|
-
adapter.log_counter measurement
|
14
|
-
end
|
15
|
-
rescue LoggingError => ex
|
16
|
-
logger.debug "[Harness] Logging measurement failed! Server Said: #{ex}"
|
17
|
-
logger.debug ex.backtrace.join("\n")
|
18
|
-
logger.warn "[Harness] Could not post measurement! Enable debug logging to see full errors"
|
19
7
|
ensure
|
20
8
|
mutex.synchronize { @finished = queue.empty? }
|
21
9
|
end
|
data/lib/harness/counter.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module Harness
|
2
4
|
class Counter < Measurement
|
3
5
|
def self.from_event(event)
|
4
6
|
if event.payload[:counter].is_a? Hash
|
5
7
|
counter = new event.payload[:counter]
|
6
|
-
elsif event.payload[:counter].is_a?
|
8
|
+
elsif event.payload[:counter].is_a?(Symbol) || event.payload[:counter].is_a?(String)
|
7
9
|
counter = new :id => event.payload[:counter].to_s
|
8
10
|
else
|
9
11
|
counter = new
|
@@ -23,6 +25,8 @@ module Harness
|
|
23
25
|
counter.value = Harness.redis.incr(counter.id).to_i
|
24
26
|
end
|
25
27
|
|
28
|
+
Harness.redis.zadd "meters/#{counter.id}", counter.time.to_f, counter.value
|
29
|
+
|
26
30
|
counter
|
27
31
|
end
|
28
32
|
end
|
data/lib/harness/gauge.rb
CHANGED
@@ -8,7 +8,7 @@ module Harness
|
|
8
8
|
def self.from_event(event)
|
9
9
|
if event.payload[:gauge].is_a? Hash
|
10
10
|
gauge = new event.payload[:gauge]
|
11
|
-
elsif event.payload[:gauge].is_a?
|
11
|
+
elsif event.payload[:gauge].is_a?(Symbol) || event.payload[:gauge].is_a?(String)
|
12
12
|
gauge = new :id => event.payload[:gauge].to_s
|
13
13
|
else
|
14
14
|
gauge = new
|
data/lib/harness/job.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Harness
|
2
|
+
class Job
|
3
|
+
def log(measurement)
|
4
|
+
logger.debug "[Harness] Processing Measurement: #{measurement.inspect}"
|
5
|
+
|
6
|
+
case measurement.class.to_s.demodulize.underscore.to_sym
|
7
|
+
when :gauge
|
8
|
+
adapter.log_gauge measurement
|
9
|
+
when :counter
|
10
|
+
adapter.log_counter measurement
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def logger
|
16
|
+
Harness.logger
|
17
|
+
end
|
18
|
+
|
19
|
+
def adapter
|
20
|
+
Harness.config.adapter
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/harness/measurement.rb
CHANGED
@@ -10,8 +10,29 @@ module Harness
|
|
10
10
|
self.time ||= Time.now
|
11
11
|
end
|
12
12
|
|
13
|
+
def time=(value)
|
14
|
+
if value.is_a? String
|
15
|
+
@time = DateTime.parse value
|
16
|
+
elsif value.is_a? Fixnum
|
17
|
+
@time = Time.at value
|
18
|
+
else
|
19
|
+
@time = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
13
23
|
def log
|
14
24
|
Harness.log self
|
15
25
|
end
|
26
|
+
|
27
|
+
def attributes
|
28
|
+
{
|
29
|
+
:id => id,
|
30
|
+
:name => name,
|
31
|
+
:source => source,
|
32
|
+
:time => time,
|
33
|
+
:units => units,
|
34
|
+
:value => value
|
35
|
+
}
|
36
|
+
end
|
16
37
|
end
|
17
38
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Harness
|
2
|
+
class Meter
|
3
|
+
def initialize(name)
|
4
|
+
@name = name
|
5
|
+
|
6
|
+
raise Harness::NoCounter, "#{@name} is not being metered" unless redis.exists key
|
7
|
+
end
|
8
|
+
|
9
|
+
def per_second
|
10
|
+
per 1.second
|
11
|
+
end
|
12
|
+
|
13
|
+
def per_minute
|
14
|
+
per 1.minute
|
15
|
+
end
|
16
|
+
|
17
|
+
def per_hour
|
18
|
+
per 1.hour
|
19
|
+
end
|
20
|
+
|
21
|
+
def per(rate, base = Time.now)
|
22
|
+
gauge = Gauge.new :value => redis.zcount(key, base.to_f - rate, base.to_f)
|
23
|
+
|
24
|
+
if words = rate_in_words(rate)
|
25
|
+
gauge.name = "#{@name} per #{words}"
|
26
|
+
gauge.id = "#{@name}-per-#{words}"
|
27
|
+
else
|
28
|
+
gauge.id = "#{@name} gauge"
|
29
|
+
end
|
30
|
+
|
31
|
+
gauge.time = Time.now
|
32
|
+
|
33
|
+
gauge
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def key
|
38
|
+
"meters/#{@name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def redis
|
42
|
+
Harness.redis
|
43
|
+
end
|
44
|
+
|
45
|
+
def rate_in_words(rate)
|
46
|
+
if rate < 1.minute
|
47
|
+
"second"
|
48
|
+
elsif rate >= 1.minute && rate < 1.hour
|
49
|
+
"minute"
|
50
|
+
elsif rate >= 1.hour && rate < 1.day
|
51
|
+
"hour"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Harness
|
2
|
+
class ResqueQueue
|
3
|
+
class SendGauge < Job
|
4
|
+
@queue = :high
|
5
|
+
|
6
|
+
def self.perform(attributes)
|
7
|
+
gauge = Gauge.new attributes
|
8
|
+
new.log gauge
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SendCounter < Job
|
13
|
+
@queue = :high
|
14
|
+
|
15
|
+
def self.perform(attributes)
|
16
|
+
counter = Counter.new attributes
|
17
|
+
new.log counter
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.push(measurement)
|
22
|
+
if measurement.is_a? Gauge
|
23
|
+
Resque.enqueue SendGauge, measurement.attributes
|
24
|
+
elsif measurement.is_a? Counter
|
25
|
+
Resque.enqueue SendCounter, measurement.attributes
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Harness
|
2
|
+
class SidekiqQueue
|
3
|
+
class SendGauge < Job
|
4
|
+
include Sidekiq::Worker
|
5
|
+
|
6
|
+
def perform(attributes)
|
7
|
+
gauge = Gauge.new attributes
|
8
|
+
log gauge
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SendCounter < Job
|
13
|
+
include Sidekiq::Worker
|
14
|
+
|
15
|
+
def perform(attributes)
|
16
|
+
counter = Counter.new attributes
|
17
|
+
log counter
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.push(measurement)
|
22
|
+
if measurement.is_a? Gauge
|
23
|
+
SendGauge.perform_async measurement.attributes
|
24
|
+
elsif measurement.is_a? Counter
|
25
|
+
SendCounter.perform_async measurement.attributes
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Harness
|
2
|
+
class SyncronousQueue
|
3
|
+
def self.push(measurement)
|
4
|
+
begin
|
5
|
+
Harness::Job.new.log(measurement)
|
6
|
+
rescue LoggingError => ex
|
7
|
+
logger.debug "[Harness] Logging measurement failed! Server Said: #{ex}"
|
8
|
+
logger.debug ex.backtrace.join("\n")
|
9
|
+
logger.warn "[Harness] Could not post measurement! Enable debug logging to see full errors"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/harness/railtie.rb
CHANGED
@@ -6,10 +6,6 @@ module Harness
|
|
6
6
|
load "harness/tasks.rake"
|
7
7
|
end
|
8
8
|
|
9
|
-
initializer "harness.thread" do
|
10
|
-
Thread.abort_on_exception = Rails.env.development? || Rails.env.test?
|
11
|
-
end
|
12
|
-
|
13
9
|
initializer "harness.adapter" do |app|
|
14
10
|
case Rails.env
|
15
11
|
when 'development'
|
@@ -32,5 +28,17 @@ module Harness
|
|
32
28
|
Harness.redis ||= Redis::Namespace.new('harness', :redis => Redis.connect(:host => 'localhost', :port => '6379'))
|
33
29
|
end
|
34
30
|
end
|
31
|
+
|
32
|
+
initializer "harness.queue" do
|
33
|
+
if defined? Resque
|
34
|
+
require 'harness/queues/resque_queue'
|
35
|
+
Harness.config.queue = :resque
|
36
|
+
elsif defined? Sidekiq
|
37
|
+
require 'harness/queues/sidekiq_queue'
|
38
|
+
Harness.config.queue = :sidekiq
|
39
|
+
else
|
40
|
+
Harness.config.queue = Harness::SyncronousQueue
|
41
|
+
end
|
42
|
+
end
|
35
43
|
end
|
36
44
|
end
|
data/lib/harness/version.rb
CHANGED
@@ -57,13 +57,32 @@ class CountersWithRedis < IntegrationTest
|
|
57
57
|
|
58
58
|
Harness.reset_counters!
|
59
59
|
|
60
|
-
assert_equal
|
61
|
-
assert_equal
|
60
|
+
assert_equal 0, redis.get("event-counter").to_i
|
61
|
+
assert_equal 0, redis.get("event-counter2").to_i
|
62
62
|
|
63
63
|
counters.clear
|
64
64
|
instrument "event-counter", :counter => true
|
65
65
|
assert_counter_logged 'event-counter'
|
66
66
|
|
67
|
-
assert_equal
|
67
|
+
assert_equal 1, counters.first.value
|
68
|
+
assert_equal 1, redis.get("event-counter").to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_resets_counters_resets_meters
|
72
|
+
instrument "event-counter", :counter => true
|
73
|
+
|
74
|
+
assert_equal 1, redis.get("event-counter").to_i
|
75
|
+
assert_equal 1, redis.zcard("meters/event-counter").to_i
|
76
|
+
|
77
|
+
Harness.reset_counters!
|
78
|
+
|
79
|
+
assert_equal 0, redis.get("event-counter").to_i
|
80
|
+
assert_equal 0, redis.zcard("meters/event-counter").to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_counting_updates_sorted_set_in_redis
|
84
|
+
instrument "event-counter", :counter => true
|
85
|
+
|
86
|
+
assert_equal 1, redis.zcard("meters/event-counter")
|
68
87
|
end
|
69
88
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CountersWithRedis < IntegrationTest
|
4
|
+
def test_counters_can_act_like_gauges
|
5
|
+
50.times { instrument "event-counter", :counter => true }
|
6
|
+
|
7
|
+
meter = Harness::Meter.new 'event-counter'
|
8
|
+
assert_equal 50, meter.per_second.value
|
9
|
+
assert_equal 50, meter.per_minute.value
|
10
|
+
assert_equal 50, meter.per_hour.value
|
11
|
+
end
|
12
|
+
|
13
|
+
def tests_raises_an_error_when_no_such_counter
|
14
|
+
assert_raises Harness::NoCounter do
|
15
|
+
Harness::Meter.new 'unknown-counter'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_rates_return_gauges
|
20
|
+
50.times { instrument "event-counter", :counter => true }
|
21
|
+
|
22
|
+
meter = Harness::Meter.new 'event-counter'
|
23
|
+
|
24
|
+
gauge = meter.per_second
|
25
|
+
|
26
|
+
assert_kind_of Harness::Gauge, gauge
|
27
|
+
|
28
|
+
assert_equal "event-counter-per-second", gauge.id
|
29
|
+
assert_equal "event-counter per second", gauge.name
|
30
|
+
assert_kind_of Time, gauge.time
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'harness/queues/resque_queue'
|
3
|
+
|
4
|
+
class ResqueTest < IntegrationTest
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
Resque.inline = true
|
8
|
+
Harness.config.queue = :resque
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_a_gauge_is_logged
|
12
|
+
instrument "test-gauge", :gauge => true
|
13
|
+
|
14
|
+
assert_gauge_logged "test-gauge"
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_a_counter_is_logged
|
18
|
+
instrument "test-counter", :counter => true
|
19
|
+
|
20
|
+
assert_counter_logged "test-counter"
|
21
|
+
|
22
|
+
assert_equal 1, counters.first.value
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'harness/queues/sidekiq_queue'
|
3
|
+
require 'sidekiq/testing'
|
4
|
+
|
5
|
+
class SidekiqTest < IntegrationTest
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
Harness.config.queue = :sidekiq
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_a_gauge_is_logged
|
12
|
+
instrument "test-gauge", :gauge => true
|
13
|
+
|
14
|
+
refute_empty Harness::SidekiqQueue::SendGauge.jobs
|
15
|
+
|
16
|
+
args = Harness::SidekiqQueue::SendGauge.jobs.first['args'].first
|
17
|
+
Harness::SidekiqQueue::SendGauge.new.perform args
|
18
|
+
|
19
|
+
assert_gauge_logged "test-gauge"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_a_counter_is_logged
|
23
|
+
instrument "test-counter", :counter => true
|
24
|
+
|
25
|
+
refute_empty Harness::SidekiqQueue::SendCounter.jobs
|
26
|
+
|
27
|
+
args = Harness::SidekiqQueue::SendCounter.jobs.first['args'].first
|
28
|
+
Harness::SidekiqQueue::SendCounter.new.perform args
|
29
|
+
|
30
|
+
assert_counter_logged "test-counter"
|
31
|
+
|
32
|
+
assert_equal 1, counters.first.value
|
33
|
+
end
|
34
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'simplecov'
|
2
2
|
SimpleCov.start
|
3
3
|
|
4
|
+
require 'resque'
|
5
|
+
require 'sidekiq'
|
6
|
+
|
4
7
|
require 'harness'
|
5
8
|
|
6
9
|
require 'minitest/unit'
|
@@ -11,10 +14,6 @@ require 'webmock/minitest'
|
|
11
14
|
|
12
15
|
WebMock.disable_net_connect!
|
13
16
|
|
14
|
-
Thread.abort_on_exception = true
|
15
|
-
|
16
|
-
Harness.config.syncronous = true
|
17
|
-
|
18
17
|
Harness.logger = Logger.new '/dev/null'
|
19
18
|
|
20
19
|
Harness.redis = Redis::Namespace.new 'harness-test', :redis => Redis.connect(:host => 'localhost', :port => '6379')
|
@@ -22,6 +21,8 @@ Harness.redis = Redis::Namespace.new 'harness-test', :redis => Redis.connect(:ho
|
|
22
21
|
class IntegrationTest < MiniTest::Unit::TestCase
|
23
22
|
def setup
|
24
23
|
Harness.config.adapter = :memory
|
24
|
+
Harness.config.queue = :syncronous
|
25
|
+
|
25
26
|
gauges.clear ; counters.clear
|
26
27
|
redis.flushall
|
27
28
|
end
|
data/test/unit/counter_test.rb
CHANGED
@@ -59,6 +59,16 @@ class CounterTest < MiniTest::Unit::TestCase
|
|
59
59
|
|
60
60
|
counter = Harness::Counter.from_event event
|
61
61
|
|
62
|
+
assert_equal 'foo', counter.id
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_sets_id_from_payload_if_string
|
66
|
+
base = Time.now
|
67
|
+
|
68
|
+
event = ActiveSupport::Notifications::Event.new "name", base - 1, Time.now, nil, :counter => 'foo'
|
69
|
+
|
70
|
+
counter = Harness::Counter.from_event event
|
71
|
+
|
62
72
|
assert_equal 'foo', counter.id
|
63
73
|
end
|
64
74
|
end
|
data/test/unit/gauge_test.rb
CHANGED
@@ -55,6 +55,16 @@ class GaugeTest < MiniTest::Unit::TestCase
|
|
55
55
|
assert_equal 'foo', gauge.id
|
56
56
|
end
|
57
57
|
|
58
|
+
def test_sets_id_from_payload_if_string
|
59
|
+
base = Time.now
|
60
|
+
|
61
|
+
event = ActiveSupport::Notifications::Event.new "name", base - 1, Time.now, nil, :gauge => 'foo'
|
62
|
+
|
63
|
+
gauge = Harness::Gauge.from_event event
|
64
|
+
|
65
|
+
assert_equal 'foo', gauge.id
|
66
|
+
end
|
67
|
+
|
58
68
|
def test_initializes_time_if_not_set
|
59
69
|
gauge = Harness::Gauge.new
|
60
70
|
|
data/test/unit/harness_test.rb
CHANGED
@@ -13,6 +13,18 @@ class HarnessModuleTest < MiniTest::Unit::TestCase
|
|
13
13
|
assert_equal Harness::MemoryAdapter, Harness.config.adapter
|
14
14
|
end
|
15
15
|
|
16
|
+
def test_can_set_the_queue_with_a_symbol
|
17
|
+
Harness.config.queue = :syncronous
|
18
|
+
|
19
|
+
assert_equal Harness::SyncronousQueue, Harness.config.queue
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_can_set_the_queue_with_a_class
|
23
|
+
Harness.config.adapter = Harness::SyncronousQueue
|
24
|
+
|
25
|
+
assert_equal Harness::SyncronousQueue, Harness.config.queue
|
26
|
+
end
|
27
|
+
|
16
28
|
def test_uses_method_missing_to_configure_adapters
|
17
29
|
Harness.config.librato.email = 'foo'
|
18
30
|
|
@@ -33,4 +33,37 @@ class MeasurementTest < MiniTest::Unit::TestCase
|
|
33
33
|
def test_initializes_time
|
34
34
|
assert @measurement.time
|
35
35
|
end
|
36
|
+
|
37
|
+
def test_can_take_a_string_time
|
38
|
+
@measurement.time = "2010-10-1T15:15:15Z"
|
39
|
+
|
40
|
+
assert_equal DateTime.parse("2010-10-1T15:15:15Z"), @measurement.time
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_can_take_an_integer_time
|
44
|
+
time = Time.now
|
45
|
+
|
46
|
+
@measurement.time = time.to_i
|
47
|
+
|
48
|
+
assert_equal time.to_i, @measurement.time.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_can_take_a_time
|
52
|
+
time = Time.now
|
53
|
+
|
54
|
+
@measurement.time = time
|
55
|
+
|
56
|
+
assert_equal time, @measurement.time
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_attributes
|
60
|
+
hash = @measurement.attributes
|
61
|
+
|
62
|
+
assert hash.has_key?(:id)
|
63
|
+
assert hash.has_key?(:name)
|
64
|
+
assert hash.has_key?(:source)
|
65
|
+
assert hash.has_key?(:time)
|
66
|
+
assert hash.has_key?(:units)
|
67
|
+
assert hash.has_key?(:value)
|
68
|
+
end
|
36
69
|
end
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: harness
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70140998559480 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70140998559480
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redis
|
27
|
-
requirement: &
|
27
|
+
requirement: &70140998559060 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70140998559060
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: redis-namespace
|
38
|
-
requirement: &
|
38
|
+
requirement: &70140998558600 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70140998558600
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: simplecov
|
49
|
-
requirement: &
|
49
|
+
requirement: &70140998558180 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70140998558180
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: webmock
|
60
|
-
requirement: &
|
60
|
+
requirement: &70140998557760 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,29 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70140998557760
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: resque
|
71
|
+
requirement: &70140998557340 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70140998557340
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: sidekiq
|
82
|
+
requirement: &70140998556920 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70140998556920
|
69
91
|
description: ''
|
70
92
|
email:
|
71
93
|
- me@broadcastingadam.com
|
@@ -91,7 +113,12 @@ files:
|
|
91
113
|
- lib/harness/integration/action_mailer.rb
|
92
114
|
- lib/harness/integration/action_view.rb
|
93
115
|
- lib/harness/integration/active_support.rb
|
116
|
+
- lib/harness/job.rb
|
94
117
|
- lib/harness/measurement.rb
|
118
|
+
- lib/harness/meter.rb
|
119
|
+
- lib/harness/queues/resque_queue.rb
|
120
|
+
- lib/harness/queues/sidekiq_queue.rb
|
121
|
+
- lib/harness/queues/syncronous_queue.rb
|
95
122
|
- lib/harness/railtie.rb
|
96
123
|
- lib/harness/tasks.rake
|
97
124
|
- lib/harness/version.rb
|
@@ -102,6 +129,9 @@ files:
|
|
102
129
|
- test/integration/integrations/action_view_test.rb
|
103
130
|
- test/integration/integrations/active_support_test.rb
|
104
131
|
- test/integration/logging_test.rb
|
132
|
+
- test/integration/meter_test.rb
|
133
|
+
- test/integration/queues/resque_test.rb
|
134
|
+
- test/integration/queues/sidekiq_test.rb
|
105
135
|
- test/test_helper.rb
|
106
136
|
- test/unit/adapters/librato_adapter_test.rb
|
107
137
|
- test/unit/adapters/memory_adapter_test.rb
|
@@ -109,6 +139,7 @@ files:
|
|
109
139
|
- test/unit/gauge_test.rb
|
110
140
|
- test/unit/harness_test.rb
|
111
141
|
- test/unit/measurement_test.rb
|
142
|
+
- test/unit/meter_test.rb
|
112
143
|
homepage: ''
|
113
144
|
licenses: []
|
114
145
|
post_install_message:
|
@@ -121,12 +152,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
152
|
- - ! '>='
|
122
153
|
- !ruby/object:Gem::Version
|
123
154
|
version: '0'
|
155
|
+
segments:
|
156
|
+
- 0
|
157
|
+
hash: 3488499753103101951
|
124
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
159
|
none: false
|
126
160
|
requirements:
|
127
161
|
- - ! '>='
|
128
162
|
- !ruby/object:Gem::Version
|
129
163
|
version: '0'
|
164
|
+
segments:
|
165
|
+
- 0
|
166
|
+
hash: 3488499753103101951
|
130
167
|
requirements: []
|
131
168
|
rubyforge_project:
|
132
169
|
rubygems_version: 1.8.11
|
@@ -141,6 +178,9 @@ test_files:
|
|
141
178
|
- test/integration/integrations/action_view_test.rb
|
142
179
|
- test/integration/integrations/active_support_test.rb
|
143
180
|
- test/integration/logging_test.rb
|
181
|
+
- test/integration/meter_test.rb
|
182
|
+
- test/integration/queues/resque_test.rb
|
183
|
+
- test/integration/queues/sidekiq_test.rb
|
144
184
|
- test/test_helper.rb
|
145
185
|
- test/unit/adapters/librato_adapter_test.rb
|
146
186
|
- test/unit/adapters/memory_adapter_test.rb
|
@@ -148,3 +188,4 @@ test_files:
|
|
148
188
|
- test/unit/gauge_test.rb
|
149
189
|
- test/unit/harness_test.rb
|
150
190
|
- test/unit/measurement_test.rb
|
191
|
+
- test/unit/meter_test.rb
|