harness 0.1.2 → 0.2.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/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
|