librato-metrics 0.5.0.pre1 → 0.5.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/.travis.yml +0 -1
- data/CHANGELOG.md +1 -0
- data/README.md +9 -5
- data/lib/librato/metrics/connection.rb +2 -0
- data/lib/librato/metrics/errors.rb +10 -0
- data/lib/librato/metrics/middleware/count_requests.rb +29 -0
- data/lib/librato/metrics/middleware/expects_status.rb +11 -3
- data/lib/librato/metrics/middleware/retry.rb +7 -6
- data/lib/librato/metrics/persistence/direct.rb +36 -4
- data/lib/librato/metrics/persistence/test.rb +1 -1
- data/lib/librato/metrics/queue.rb +8 -4
- data/lib/librato/metrics/version.rb +1 -1
- data/librato-metrics.gemspec +2 -0
- data/spec/integration/metrics/middleware/count_requests_spec.rb +28 -0
- data/spec/integration/metrics/queue_spec.rb +43 -0
- data/spec/integration/metrics_spec.rb +5 -4
- data/spec/rackups/status.ru +21 -0
- data/spec/spec_helper.rb +48 -10
- data/spec/unit/metrics/client_spec.rb +2 -2
- data/spec/unit/metrics/connection_spec.rb +40 -8
- data/spec/unit/metrics/queue_spec.rb +17 -10
- data/spec/unit/metrics_spec.rb +2 -2
- metadata +48 -19
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
### Version 0.5.0
|
|
4
4
|
* Support using multiple accounts simultaneously via Client
|
|
5
5
|
* Switch network library to faraday for broader platform support and flexibility
|
|
6
|
+
* Automatically break large submissions into multiple requests for better performance
|
|
6
7
|
* Automatic retry support
|
|
7
8
|
* Consolidate connection functions in Connection
|
|
8
9
|
* Documentation improvements
|
data/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Librato Metrics
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
[](http://travis-ci.org/librato/librato-metrics)
|
|
5
|
+
|
|
4
6
|
A convenient Ruby wrapper for the Librato Metrics API.
|
|
5
7
|
|
|
6
8
|
## Installation
|
|
@@ -140,19 +142,21 @@ Once the queue is associated you can use it normally:
|
|
|
140
142
|
|
|
141
143
|
The `librato-metrics` gem currently does not do internal locking for thread safety. When used in multi-threaded applications, please add your own mutexes for sensitive operations.
|
|
142
144
|
|
|
143
|
-
##
|
|
145
|
+
## Feature Roadmap
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
These are features we expect to add in future versions, roughly in the order of current priority. If you feel strongly about a feature, feel free to [create an issue](https://github.com/librato/librato-metrics/issues) or [join us in live chat](https://librato.campfirenow.com/269d3) and talk to us about it.
|
|
146
148
|
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
149
|
+
* Queue objects support a single default measure_time to use for any measurements which don't have it set
|
|
150
|
+
* Queues auto-submit when they hit a set number of records
|
|
151
|
+
* Queues auto-submit when they hit a max time interval
|
|
152
|
+
* Query actions return a collection object which auto-paginates large result sets
|
|
150
153
|
|
|
151
154
|
## Contribution
|
|
152
155
|
|
|
153
156
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
|
154
157
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
|
155
158
|
* Fork the project and submit a pull request from a feature or bugfix branch.
|
|
159
|
+
* Please review our [code conventions](https://github.com/librato/librato-metrics/wiki/Code-Conventions).
|
|
156
160
|
* Please include specs. This is important so we don't break your changes unintentionally in a future version.
|
|
157
161
|
* Please don't modify the gemspec, Rakefile, version, or changelog. If you do change these files, please isolate a separate commit so we can cherry-pick around it.
|
|
158
162
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'faraday'
|
|
2
|
+
require 'metrics/middleware/count_requests'
|
|
2
3
|
require 'metrics/middleware/expects_status'
|
|
3
4
|
require 'metrics/middleware/retry'
|
|
4
5
|
|
|
@@ -29,6 +30,7 @@ module Librato
|
|
|
29
30
|
@transport ||= Faraday::Connection.new(:url => api_endpoint + "/v1/") do |f|
|
|
30
31
|
#f.use FaradayMiddleware::EncodeJson
|
|
31
32
|
f.use Librato::Metrics::Middleware::Retry
|
|
33
|
+
f.use Librato::Metrics::Middleware::CountRequests
|
|
32
34
|
f.use Librato::Metrics::Middleware::ExpectsStatus
|
|
33
35
|
#f.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
|
|
34
36
|
f.adapter Faraday.default_adapter
|
|
@@ -8,6 +8,16 @@ module Librato
|
|
|
8
8
|
class AgentInfoMissing < MetricsError; end
|
|
9
9
|
class NoMetricsQueued < MetricsError; end
|
|
10
10
|
class NoClientProvided < MetricsError; end
|
|
11
|
+
|
|
12
|
+
class NetworkError < StandardError; end
|
|
13
|
+
|
|
14
|
+
class ClientError < NetworkError; end
|
|
15
|
+
class Unauthorized < ClientError; end
|
|
16
|
+
class Forbidden < ClientError; end
|
|
17
|
+
class NotFound < ClientError; end
|
|
18
|
+
class EntityAlreadyExists < ClientError; end
|
|
19
|
+
|
|
20
|
+
class ServerError < NetworkError; end
|
|
11
21
|
|
|
12
22
|
end
|
|
13
23
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Librato
|
|
2
|
+
module Metrics
|
|
3
|
+
module Middleware
|
|
4
|
+
|
|
5
|
+
class CountRequests < Faraday::Response::Middleware
|
|
6
|
+
@total_requests = 0
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
attr_reader :total_requests
|
|
10
|
+
|
|
11
|
+
def increment
|
|
12
|
+
@total_requests += 1
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def reset
|
|
16
|
+
@total_requests = 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(env)
|
|
21
|
+
self.class.increment
|
|
22
|
+
@app.call(env)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -8,10 +8,18 @@ module Librato
|
|
|
8
8
|
# TODO: clean up exception output
|
|
9
9
|
# TODO: catch specific status codes by request
|
|
10
10
|
case env[:status]
|
|
11
|
+
when 401
|
|
12
|
+
raise Unauthorized, env.to_s
|
|
13
|
+
when 403
|
|
14
|
+
raise Forbidden, env.to_s
|
|
11
15
|
when 404
|
|
12
|
-
raise
|
|
13
|
-
when
|
|
14
|
-
raise
|
|
16
|
+
raise NotFound, env.to_s
|
|
17
|
+
when 422
|
|
18
|
+
raise EntityAlreadyExists, env.to_s
|
|
19
|
+
when 400..499
|
|
20
|
+
raise ClientError, env.to_s
|
|
21
|
+
when 500..599
|
|
22
|
+
raise ServerError, env.to_s
|
|
15
23
|
end
|
|
16
24
|
end
|
|
17
25
|
|
|
@@ -12,13 +12,14 @@ module Librato
|
|
|
12
12
|
|
|
13
13
|
def call(env)
|
|
14
14
|
retries = @retries
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
retries
|
|
19
|
-
|
|
15
|
+
begin
|
|
16
|
+
@app.call(env)
|
|
17
|
+
rescue Librato::Metrics::ServerError, Timeout::Error
|
|
18
|
+
if retries > 0
|
|
19
|
+
retries -= 1 and retry
|
|
20
|
+
end
|
|
21
|
+
raise
|
|
20
22
|
end
|
|
21
|
-
raise
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
end
|
|
@@ -9,10 +9,42 @@ module Librato
|
|
|
9
9
|
# Persist the queued metrics directly to the
|
|
10
10
|
# Metrics web API.
|
|
11
11
|
#
|
|
12
|
-
def persist(client, queued)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
def persist(client, queued, options={})
|
|
13
|
+
per_request = options[:per_request]
|
|
14
|
+
if per_request
|
|
15
|
+
requests = chunk_queued(queued, per_request)
|
|
16
|
+
else
|
|
17
|
+
requests = [queued]
|
|
18
|
+
end
|
|
19
|
+
requests.each do |request|
|
|
20
|
+
payload = MultiJson.encode(request)
|
|
21
|
+
# expects 200
|
|
22
|
+
client.connection.post('metrics', payload)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def chunk_queued(queued, per_request)
|
|
29
|
+
return [queued] if queue_count(queued) <= per_request
|
|
30
|
+
reqs = []
|
|
31
|
+
queued.each do |metric_type, measurements|
|
|
32
|
+
if measurements.size <= per_request
|
|
33
|
+
# we can fit all of this metric type in a single
|
|
34
|
+
# request, so do so
|
|
35
|
+
reqs << {metric_type => measurements}
|
|
36
|
+
else
|
|
37
|
+
# going to have to split things up
|
|
38
|
+
measurements.each_slice(per_request) do |elements|
|
|
39
|
+
reqs << {metric_type => elements}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
reqs
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def queue_count(queued)
|
|
47
|
+
queued.inject(0) { |result, data| result + data.last.size }
|
|
16
48
|
end
|
|
17
49
|
|
|
18
50
|
end
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
module Librato
|
|
2
2
|
module Metrics
|
|
3
3
|
class Queue
|
|
4
|
+
MEASUREMENTS_PER_REQUEST = 500
|
|
4
5
|
|
|
6
|
+
attr_reader :per_request
|
|
5
7
|
attr_accessor :skip_measurement_times
|
|
6
8
|
|
|
7
9
|
def initialize(options={})
|
|
8
|
-
@queued
|
|
9
|
-
@
|
|
10
|
-
@
|
|
10
|
+
@queued = {}
|
|
11
|
+
@per_request = options[:per_request] || MEASUREMENTS_PER_REQUEST
|
|
12
|
+
@skip_measurement_times = options[:skip_measurement_times]
|
|
13
|
+
@client = options[:client] || Librato::Metrics.client
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
# Add a metric entry to the metric set:
|
|
@@ -99,7 +102,8 @@ module Librato
|
|
|
99
102
|
# @return Boolean
|
|
100
103
|
def submit
|
|
101
104
|
raise NoMetricsQueued if self.queued.empty?
|
|
102
|
-
|
|
105
|
+
options = {:per_request => @per_request}
|
|
106
|
+
if persister.persist(self.client, self.queued, options)
|
|
103
107
|
flush and return true
|
|
104
108
|
end
|
|
105
109
|
false
|
data/librato-metrics.gemspec
CHANGED
|
@@ -33,6 +33,8 @@ Gem::Specification.new do |s|
|
|
|
33
33
|
s.add_development_dependency 'pry'
|
|
34
34
|
s.add_development_dependency 'yard'
|
|
35
35
|
s.add_development_dependency 'rdiscount' # for yard
|
|
36
|
+
s.add_development_dependency 'sinatra'
|
|
37
|
+
s.add_development_dependency 'popen4'
|
|
36
38
|
|
|
37
39
|
s.files = `git ls-files`.split("\n")
|
|
38
40
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Librato
|
|
4
|
+
module Metrics
|
|
5
|
+
module Middleware
|
|
6
|
+
|
|
7
|
+
describe CountRequests do
|
|
8
|
+
before(:all) { prep_integration_tests }
|
|
9
|
+
|
|
10
|
+
it "should count requests" do
|
|
11
|
+
CountRequests.reset
|
|
12
|
+
Metrics.submit :foo => 123
|
|
13
|
+
Metrics.submit :foo => 135
|
|
14
|
+
CountRequests.total_requests.should == 2
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should be resettable" do
|
|
18
|
+
Metrics.submit :foo => 123
|
|
19
|
+
CountRequests.total_requests.should > 0
|
|
20
|
+
CountRequests.reset
|
|
21
|
+
CountRequests.total_requests.should == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Librato
|
|
4
|
+
module Metrics
|
|
5
|
+
|
|
6
|
+
describe Queue do
|
|
7
|
+
before(:all) { prep_integration_tests }
|
|
8
|
+
|
|
9
|
+
context "with a large number of metrics" do
|
|
10
|
+
it "should submit them in multiple requests" do
|
|
11
|
+
Middleware::CountRequests.reset
|
|
12
|
+
queue = Queue.new(:per_request => 3)
|
|
13
|
+
(1..10).each do |i|
|
|
14
|
+
queue.add "gauge_#{i}" => 1
|
|
15
|
+
end
|
|
16
|
+
queue.submit
|
|
17
|
+
Middleware::CountRequests.total_requests.should == 4
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should persist all metrics" do
|
|
21
|
+
queue = Queue.new(:per_request => 2)
|
|
22
|
+
(1..5).each do |i|
|
|
23
|
+
queue.add "gauge_#{i}" => i
|
|
24
|
+
end
|
|
25
|
+
(1..3).each do |i|
|
|
26
|
+
queue.add "counter_#{i}" => {:type => :counter, :value => i}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
delete_all_metrics
|
|
30
|
+
queue.submit
|
|
31
|
+
|
|
32
|
+
metrics = Metrics.list
|
|
33
|
+
metrics.length.should == 8
|
|
34
|
+
counter = Metrics.fetch :counter_3, :count => 1
|
|
35
|
+
counter['unassigned'][0]['value'].should == 3
|
|
36
|
+
gauge = Metrics.fetch :gauge_5, :count => 1
|
|
37
|
+
gauge['unassigned'][0]['value'].should == 5
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -7,11 +7,12 @@ module Librato
|
|
|
7
7
|
describe "#fetch" do
|
|
8
8
|
before(:all) do
|
|
9
9
|
delete_all_metrics
|
|
10
|
-
Metrics.submit :my_counter => {:type => :counter, :value => 0}
|
|
10
|
+
Metrics.submit :my_counter => {:type => :counter, :value => 0, :measure_time => Time.now.to_i-60}
|
|
11
11
|
1.upto(2).each do |i|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Metrics.submit :my_counter =>
|
|
12
|
+
measure_time = Time.now.to_i - (5+i)
|
|
13
|
+
opts = {:measure_time => measure_time, :type => :counter}
|
|
14
|
+
Metrics.submit :my_counter => opts.merge(:value => i)
|
|
15
|
+
Metrics.submit :my_counter => opts.merge(:source => 'baz', :value => i+1)
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'sinatra'
|
|
2
|
+
|
|
3
|
+
class App < Sinatra::Base
|
|
4
|
+
get('/v1/success') do
|
|
5
|
+
status 200
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
post('/v1/forbidden') do
|
|
9
|
+
status 403
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
get('/v1/not_found') do
|
|
13
|
+
status 404
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
post('/v1/service_unavailable') do
|
|
17
|
+
status 503
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
run App
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# only load pry for MRI > 1.8
|
|
4
|
+
require 'pry' if RUBY_ENGINE == 'ruby' rescue nil
|
|
5
|
+
require 'popen4'
|
|
4
6
|
require 'rspec'
|
|
5
7
|
require 'rspec/mocks/standalone'
|
|
8
|
+
require 'set'
|
|
6
9
|
|
|
7
10
|
require 'librato/metrics'
|
|
8
11
|
|
|
9
12
|
RSpec.configure do |config|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
# purge all metrics from test account
|
|
15
|
+
def delete_all_metrics
|
|
16
|
+
connection = Librato::Metrics.client.connection
|
|
17
|
+
Librato::Metrics.list.each do |metric|
|
|
18
|
+
#puts "deleting #{metric['name']}..."
|
|
19
|
+
# expects 204
|
|
20
|
+
connection.delete("metrics/#{metric['name']}")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
11
24
|
# set up test account credentials for integration tests
|
|
12
25
|
def prep_integration_tests
|
|
13
26
|
raise 'no TEST_API_USER specified in environment' unless ENV['TEST_API_USER']
|
|
@@ -17,14 +30,26 @@ RSpec.configure do |config|
|
|
|
17
30
|
end
|
|
18
31
|
Librato::Metrics.authenticate ENV['TEST_API_USER'], ENV['TEST_API_KEY']
|
|
19
32
|
end
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
|
|
34
|
+
def rackup_path(*parts)
|
|
35
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'rackups', *parts))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# fire up a given rackup file for the enclosed tests
|
|
39
|
+
def with_rackup(name)
|
|
40
|
+
if RUBY_PLATFORM == 'java'
|
|
41
|
+
pid, w, r, e = IO.popen4("rackup", rackup_path(name), '-p 9296')
|
|
42
|
+
else
|
|
43
|
+
GC.disable
|
|
44
|
+
pid, w, r, e = Open4.popen4("rackup", rackup_path(name), '-p 9296')
|
|
45
|
+
end
|
|
46
|
+
until e.gets =~ /HTTPServer#start:/; end
|
|
47
|
+
yield
|
|
48
|
+
ensure
|
|
49
|
+
Process.kill(9, pid)
|
|
50
|
+
if RUBY_PLATFORM != 'java'
|
|
51
|
+
GC.enable
|
|
52
|
+
Process.wait(pid)
|
|
28
53
|
end
|
|
29
54
|
end
|
|
30
55
|
|
|
@@ -37,4 +62,17 @@ RSpec::Matchers.define :start_with do |start_string|
|
|
|
37
62
|
start_length = start_string.length
|
|
38
63
|
string[0..start_length-1] == start_string
|
|
39
64
|
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Compares hashes of arrays by converting the arrays to
|
|
68
|
+
# sets before comparision
|
|
69
|
+
#
|
|
70
|
+
# @example
|
|
71
|
+
# {:foo => [1,3,2]}.should equal_unordered({:foo => [1,2,3]})
|
|
72
|
+
RSpec::Matchers.define :equal_unordered do |result|
|
|
73
|
+
result.each { |key, value| result[key] = value.to_set }
|
|
74
|
+
match do |target|
|
|
75
|
+
target.each { |key, value| target[key] = value.to_set }
|
|
76
|
+
target == result
|
|
77
|
+
end
|
|
40
78
|
end
|
|
@@ -92,7 +92,7 @@ module Librato
|
|
|
92
92
|
subject.authenticate 'me@librato.com', 'foo'
|
|
93
93
|
subject.persistence = :test
|
|
94
94
|
subject.submit(:foo => 123).should eql true
|
|
95
|
-
subject.persister.persisted.should
|
|
95
|
+
subject.persister.persisted.should == {:gauges => [{:name => 'foo', :value => 123}]}
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
it "should tolerate muliple metrics" do
|
|
@@ -100,7 +100,7 @@ module Librato
|
|
|
100
100
|
subject.persistence = :test
|
|
101
101
|
lambda{ subject.submit :foo => 123, :bar => 456 }.should_not raise_error
|
|
102
102
|
expected = {:gauges => [{:name => 'foo', :value => 123}, {:name => 'bar', :value => 456}]}
|
|
103
|
-
subject.persister.persisted.should
|
|
103
|
+
subject.persister.persisted.should equal_unordered(expected)
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
|
|
@@ -5,14 +5,6 @@ module Librato
|
|
|
5
5
|
|
|
6
6
|
describe Connection do
|
|
7
7
|
|
|
8
|
-
describe "network operations" do
|
|
9
|
-
context "when missing client" do
|
|
10
|
-
it "should raise exception" do
|
|
11
|
-
lambda { subject.get 'metrics' }#.should raise(NoClientProvided)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
8
|
describe "#api_endpoint" do
|
|
17
9
|
context "when not provided" do
|
|
18
10
|
it "should be default" do
|
|
@@ -48,6 +40,46 @@ module Librato
|
|
|
48
40
|
# TODO: verify user agent is being sent with rackup test
|
|
49
41
|
end
|
|
50
42
|
|
|
43
|
+
describe "network operations" do
|
|
44
|
+
context "when missing client" do
|
|
45
|
+
it "should raise exception" do
|
|
46
|
+
lambda { subject.get 'metrics' }.should raise_error(NoClientProvided)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "with 400 class errors" do
|
|
51
|
+
it "should not retry" do
|
|
52
|
+
Middleware::CountRequests.reset
|
|
53
|
+
client = Client.new
|
|
54
|
+
client.api_endpoint = 'http://127.0.0.1:9296'
|
|
55
|
+
client.authenticate 'foo', 'bar'
|
|
56
|
+
with_rackup('status.ru') do
|
|
57
|
+
lambda {
|
|
58
|
+
client.connection.transport.post 'not_found'
|
|
59
|
+
}.should raise_error(NotFound)
|
|
60
|
+
lambda {
|
|
61
|
+
client.connection.transport.post 'forbidden'
|
|
62
|
+
}.should raise_error(ClientError)
|
|
63
|
+
end
|
|
64
|
+
Middleware::CountRequests.total_requests.should == 2
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context "with 500 class errors" do
|
|
69
|
+
it "should retry" do
|
|
70
|
+
Middleware::CountRequests.reset
|
|
71
|
+
client = Client.new
|
|
72
|
+
client.api_endpoint = 'http://127.0.0.1:9296'
|
|
73
|
+
client.authenticate 'foo', 'bar'
|
|
74
|
+
with_rackup('status.ru') do
|
|
75
|
+
lambda {
|
|
76
|
+
client.connection.transport.post 'service_unavailable'
|
|
77
|
+
}.should raise_error(ServerError)
|
|
78
|
+
end
|
|
79
|
+
Middleware::CountRequests.total_requests.should == 4
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
51
83
|
|
|
52
84
|
end
|
|
53
85
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
require "spec_helper
|
|
1
|
+
require "spec_helper"
|
|
2
2
|
|
|
3
3
|
module Librato
|
|
4
4
|
module Metrics
|
|
5
5
|
|
|
6
6
|
describe Queue do
|
|
7
7
|
|
|
8
|
-
before(:
|
|
8
|
+
before(:each) do
|
|
9
9
|
@time = Time.now.to_i
|
|
10
10
|
Queue.stub(:epoch_time).and_return(@time)
|
|
11
11
|
end
|
|
@@ -30,8 +30,9 @@ module Librato
|
|
|
30
30
|
describe "#add" do
|
|
31
31
|
context "with single hash argument" do
|
|
32
32
|
it "should record a key-value gauge" do
|
|
33
|
+
expected = {:gauges => [{:name => 'foo', :value => 3000, :measure_time => @time}]}
|
|
33
34
|
subject.add :foo => 3000
|
|
34
|
-
subject.queued.should
|
|
35
|
+
subject.queued.should equal_unordered(expected)
|
|
35
36
|
end
|
|
36
37
|
end
|
|
37
38
|
|
|
@@ -39,19 +40,19 @@ module Librato
|
|
|
39
40
|
it "should record counters" do
|
|
40
41
|
subject.add :total_visits => {:type => :counter, :value => 4000}
|
|
41
42
|
expected = {:counters => [{:name => 'total_visits', :value => 4000, :measure_time => @time}]}
|
|
42
|
-
subject.queued.should
|
|
43
|
+
subject.queued.should equal_unordered(expected)
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
it "should record gauges" do
|
|
46
47
|
subject.add :temperature => {:type => :gauge, :value => 34}
|
|
47
48
|
expected = {:gauges => [{:name => 'temperature', :value => 34, :measure_time => @time}]}
|
|
48
|
-
subject.queued.should
|
|
49
|
+
subject.queued.should equal_unordered(expected)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
it "should accept type key as string or a symbol" do
|
|
52
53
|
subject.add :total_visits => {"type" => "counter", :value => 4000}
|
|
53
54
|
expected = {:counters => [{:name => 'total_visits', :value => 4000, :measure_time => @time}]}
|
|
54
|
-
subject.queued.should
|
|
55
|
+
subject.queued.should equal_unordered(expected)
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
@@ -64,7 +65,7 @@ module Librato
|
|
|
64
65
|
expected = {:gauges => [{:value => 35.4, :name => 'disk_use', :period => 2,
|
|
65
66
|
:description => 'current disk utilization', :measure_time => measure_time,
|
|
66
67
|
:source => 'db2'}]}
|
|
67
|
-
subject.queued.should
|
|
68
|
+
subject.queued.should equal_unordered(expected)
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
|
|
@@ -74,7 +75,7 @@ module Librato
|
|
|
74
75
|
expected = {:gauges=>[{:name=>"foo", :value=>123, :measure_time => @time},
|
|
75
76
|
{:name=>"bar", :value=>345, :measure_time => @time},
|
|
76
77
|
{:name=>"baz", :value=>567, :measure_time => @time}]}
|
|
77
|
-
subject.queued.should
|
|
78
|
+
subject.queued.should equal_unordered(expected)
|
|
78
79
|
end
|
|
79
80
|
end
|
|
80
81
|
end
|
|
@@ -113,6 +114,12 @@ module Librato
|
|
|
113
114
|
subject.gauges.should eql []
|
|
114
115
|
end
|
|
115
116
|
end
|
|
117
|
+
|
|
118
|
+
describe "#per_request" do
|
|
119
|
+
it "should default to 500" do
|
|
120
|
+
subject.per_request.should == 500
|
|
121
|
+
end
|
|
122
|
+
end
|
|
116
123
|
|
|
117
124
|
describe "#size" do
|
|
118
125
|
it "should return empty if gauges and counters are emtpy" do
|
|
@@ -159,7 +166,7 @@ module Librato
|
|
|
159
166
|
end
|
|
160
167
|
queued = subject.queued[:gauges][0]
|
|
161
168
|
queued[:name].should == 'sleeping'
|
|
162
|
-
queued[:value].should be
|
|
169
|
+
queued[:value].should be >= 100
|
|
163
170
|
queued[:value].should be_within(30).of(100)
|
|
164
171
|
end
|
|
165
172
|
end
|
|
@@ -173,7 +180,7 @@ module Librato
|
|
|
173
180
|
queued[:name].should == 'sleep_two'
|
|
174
181
|
queued[:period].should == 2
|
|
175
182
|
queued[:source].should == 'app1'
|
|
176
|
-
queued[:value].should be
|
|
183
|
+
queued[:value].should be >= 50
|
|
177
184
|
queued[:value].should be_within(30).of(50)
|
|
178
185
|
end
|
|
179
186
|
end
|
data/spec/unit/metrics_spec.rb
CHANGED
|
@@ -35,13 +35,13 @@ module Librato
|
|
|
35
35
|
it "should persist metrics immediately" do
|
|
36
36
|
Metrics.persistence = :test
|
|
37
37
|
Metrics.submit(:foo => 123).should eql true
|
|
38
|
-
Metrics.persister.persisted.should
|
|
38
|
+
Metrics.persister.persisted.should == {:gauges => [{:name => 'foo', :value => 123}]}
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
it "should tolerate multiple metrics" do
|
|
42
42
|
lambda{ Librato::Metrics.submit :foo => 123, :bar => 456 }.should_not raise_error
|
|
43
43
|
expected = {:gauges => [{:name => 'foo', :value => 123}, {:name => 'bar', :value => 456}]}
|
|
44
|
-
Librato::Metrics.persister.persisted.should
|
|
44
|
+
Librato::Metrics.persister.persisted.should equal_unordered(expected)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
end
|
metadata
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: librato-metrics
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.0
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 0.5.0
|
|
5
|
+
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Matt Sanders
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-
|
|
12
|
+
date: 2012-04-02 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: faraday
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &70301317338000 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ~>
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: 0.7.6
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *70301317338000
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: multi_json
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &70301317369580 !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: *70301317369580
|
|
36
36
|
- !ruby/object:Gem::Dependency
|
|
37
37
|
name: rake
|
|
38
|
-
requirement: &
|
|
38
|
+
requirement: &70301317369120 !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: :development
|
|
45
45
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *70301317369120
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: rspec
|
|
49
|
-
requirement: &
|
|
49
|
+
requirement: &70301317368620 !ruby/object:Gem::Requirement
|
|
50
50
|
none: false
|
|
51
51
|
requirements:
|
|
52
52
|
- - ~>
|
|
@@ -54,10 +54,10 @@ dependencies:
|
|
|
54
54
|
version: 2.6.0
|
|
55
55
|
type: :development
|
|
56
56
|
prerelease: false
|
|
57
|
-
version_requirements: *
|
|
57
|
+
version_requirements: *70301317368620
|
|
58
58
|
- !ruby/object:Gem::Dependency
|
|
59
59
|
name: pry
|
|
60
|
-
requirement: &
|
|
60
|
+
requirement: &70301317368200 !ruby/object:Gem::Requirement
|
|
61
61
|
none: false
|
|
62
62
|
requirements:
|
|
63
63
|
- - ! '>='
|
|
@@ -65,10 +65,10 @@ dependencies:
|
|
|
65
65
|
version: '0'
|
|
66
66
|
type: :development
|
|
67
67
|
prerelease: false
|
|
68
|
-
version_requirements: *
|
|
68
|
+
version_requirements: *70301317368200
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: yard
|
|
71
|
-
requirement: &
|
|
71
|
+
requirement: &70301317367740 !ruby/object:Gem::Requirement
|
|
72
72
|
none: false
|
|
73
73
|
requirements:
|
|
74
74
|
- - ! '>='
|
|
@@ -76,10 +76,10 @@ dependencies:
|
|
|
76
76
|
version: '0'
|
|
77
77
|
type: :development
|
|
78
78
|
prerelease: false
|
|
79
|
-
version_requirements: *
|
|
79
|
+
version_requirements: *70301317367740
|
|
80
80
|
- !ruby/object:Gem::Dependency
|
|
81
81
|
name: rdiscount
|
|
82
|
-
requirement: &
|
|
82
|
+
requirement: &70301317367320 !ruby/object:Gem::Requirement
|
|
83
83
|
none: false
|
|
84
84
|
requirements:
|
|
85
85
|
- - ! '>='
|
|
@@ -87,7 +87,29 @@ dependencies:
|
|
|
87
87
|
version: '0'
|
|
88
88
|
type: :development
|
|
89
89
|
prerelease: false
|
|
90
|
-
version_requirements: *
|
|
90
|
+
version_requirements: *70301317367320
|
|
91
|
+
- !ruby/object:Gem::Dependency
|
|
92
|
+
name: sinatra
|
|
93
|
+
requirement: &70301317366900 !ruby/object:Gem::Requirement
|
|
94
|
+
none: false
|
|
95
|
+
requirements:
|
|
96
|
+
- - ! '>='
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
type: :development
|
|
100
|
+
prerelease: false
|
|
101
|
+
version_requirements: *70301317366900
|
|
102
|
+
- !ruby/object:Gem::Dependency
|
|
103
|
+
name: popen4
|
|
104
|
+
requirement: &70301317366480 !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ! '>='
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: *70301317366480
|
|
91
113
|
description: An easy to use ruby wrapper for Librato's Metrics API
|
|
92
114
|
email: matt@librato.com
|
|
93
115
|
executables: []
|
|
@@ -107,6 +129,7 @@ files:
|
|
|
107
129
|
- lib/librato/metrics/collection.rb
|
|
108
130
|
- lib/librato/metrics/connection.rb
|
|
109
131
|
- lib/librato/metrics/errors.rb
|
|
132
|
+
- lib/librato/metrics/middleware/count_requests.rb
|
|
110
133
|
- lib/librato/metrics/middleware/expects_status.rb
|
|
111
134
|
- lib/librato/metrics/middleware/retry.rb
|
|
112
135
|
- lib/librato/metrics/persistence.rb
|
|
@@ -116,7 +139,10 @@ files:
|
|
|
116
139
|
- lib/librato/metrics/version.rb
|
|
117
140
|
- librato-metrics.gemspec
|
|
118
141
|
- spec/integration/metrics/connection_spec.rb
|
|
142
|
+
- spec/integration/metrics/middleware/count_requests_spec.rb
|
|
143
|
+
- spec/integration/metrics/queue_spec.rb
|
|
119
144
|
- spec/integration/metrics_spec.rb
|
|
145
|
+
- spec/rackups/status.ru
|
|
120
146
|
- spec/spec_helper.rb
|
|
121
147
|
- spec/unit/metrics/client_spec.rb
|
|
122
148
|
- spec/unit/metrics/connection_spec.rb
|
|
@@ -138,9 +164,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
138
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
165
|
none: false
|
|
140
166
|
requirements:
|
|
141
|
-
- - ! '
|
|
167
|
+
- - ! '>='
|
|
142
168
|
- !ruby/object:Gem::Version
|
|
143
|
-
version:
|
|
169
|
+
version: '0'
|
|
144
170
|
requirements: []
|
|
145
171
|
rubyforge_project:
|
|
146
172
|
rubygems_version: 1.8.16
|
|
@@ -149,7 +175,10 @@ specification_version: 2
|
|
|
149
175
|
summary: Ruby wrapper for Librato's Metrics API
|
|
150
176
|
test_files:
|
|
151
177
|
- spec/integration/metrics/connection_spec.rb
|
|
178
|
+
- spec/integration/metrics/middleware/count_requests_spec.rb
|
|
179
|
+
- spec/integration/metrics/queue_spec.rb
|
|
152
180
|
- spec/integration/metrics_spec.rb
|
|
181
|
+
- spec/rackups/status.ru
|
|
153
182
|
- spec/spec_helper.rb
|
|
154
183
|
- spec/unit/metrics/client_spec.rb
|
|
155
184
|
- spec/unit/metrics/connection_spec.rb
|