librato-metrics 0.7.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -1
- data/README.md +44 -15
- data/lib/librato/metrics.rb +7 -4
- data/lib/librato/metrics/annotator.rb +106 -0
- data/lib/librato/metrics/client.rb +12 -4
- data/lib/librato/metrics/errors.rb +0 -1
- data/lib/librato/metrics/processor.rb +2 -2
- data/lib/librato/metrics/queue.rb +2 -1
- data/lib/librato/metrics/version.rb +1 -1
- data/spec/integration/metrics/annotator_spec.rb +139 -0
- data/spec/integration/metrics_spec.rb +39 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/unit/metrics/queue_spec.rb +3 -3
- metadata +6 -3
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
## Changelog
|
2
2
|
|
3
|
+
### Version 1.0.0
|
4
|
+
* Add support for annotation submission, listing, management
|
5
|
+
* Auto-convert Time objects anywhere a time is accepted
|
6
|
+
* Don't raise exception anymore for empty queue submission
|
7
|
+
|
3
8
|
### Version 0.7.5
|
4
9
|
* Catch a broader range of connection failures for retrying
|
5
|
-
* Add Metrics.faraday_adapter config option (Mathieu Ravaux)
|
10
|
+
* Add Metrics.faraday_adapter config option (Mathieu Ravaux)
|
6
11
|
|
7
12
|
### Version 0.7.4
|
8
13
|
* Support global measure_time option for Queues/Aggregators
|
data/README.md
CHANGED
@@ -14,13 +14,13 @@ In your shell:
|
|
14
14
|
Then, in your application or script:
|
15
15
|
|
16
16
|
require 'librato/metrics'
|
17
|
-
|
17
|
+
|
18
18
|
### Optional steps
|
19
19
|
|
20
20
|
For best performance we recommend installing [yajl-ruby](https://github.com/brianmario/yajl-ruby):
|
21
21
|
|
22
22
|
gem install yajl-ruby
|
23
|
-
|
23
|
+
|
24
24
|
If you are using jruby, you need to ensure [jruby-openssl](https://github.com/jruby/jruby-ossl) is available:
|
25
25
|
|
26
26
|
gem install jruby-openssl
|
@@ -52,18 +52,18 @@ Queue up a simple gauge metric named `temperature`:
|
|
52
52
|
|
53
53
|
queue = Librato::Metrics::Queue.new
|
54
54
|
queue.add :temperature => 32.2
|
55
|
-
|
55
|
+
|
56
56
|
While symbols are used by convention for metric names, strings will work just as well:
|
57
57
|
|
58
58
|
queue.add 'myapp.request_time' => 86.7
|
59
59
|
|
60
|
-
If you are tracking measurements over several seconds/minutes, the queue will handle storing measurement time for you (otherwise all metrics will be recorded as measured when they are submitted).
|
60
|
+
If you are tracking measurements over several seconds/minutes, the queue will handle storing measurement time for you (otherwise all metrics will be recorded as measured when they are submitted).
|
61
61
|
|
62
62
|
If you want to specify a time other than queuing time for the measurement:
|
63
63
|
|
64
64
|
# use a epoch integer
|
65
65
|
queue.add :humidity => {:measure_time => 1336508422, :value => 48.2}
|
66
|
-
|
66
|
+
|
67
67
|
# use a Time object to correct for a 5 second delay
|
68
68
|
queue.add :humidity => {:measure_time => Time.now-5, :value => 37.6}
|
69
69
|
|
@@ -125,23 +125,52 @@ If you need extra attributes for a `Queue` timing measurement, simply add them o
|
|
125
125
|
queue.time :my_measurement, :source => 'app1' do
|
126
126
|
# do work...
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
|
+
## Annotations
|
130
|
+
|
131
|
+
Annotation streams are a great way to track events like deploys, backups or anything else that might affect your system. They can be overlaid on any other metric stream so you can easily see the impact of changes.
|
132
|
+
|
133
|
+
At a minimum each annotation needs to be assigned to a stream and to have a title. Let's add an annotation for deploying v45 of our app to the `deployments` stream:
|
134
|
+
|
135
|
+
Librato::Metrics.annotate :deployments, 'deployed v45'
|
136
|
+
|
137
|
+
There are a number of optional fields which can make annotations even more powerful:
|
138
|
+
|
139
|
+
Librato::Metrics.annotate :deployments, 'deployed v46', :source => 'frontend',
|
140
|
+
:start_time => 1354662596, :end_time => 1354662608,
|
141
|
+
:description => 'Deployed 6f3bc6e67682: fix lotsa bugs…'
|
142
|
+
|
143
|
+
More fine-grained control of annotations is available via the `Annotator` object:
|
144
|
+
|
145
|
+
annotator = Librato::Metrics::Annotator.new
|
146
|
+
|
147
|
+
# list annotation streams
|
148
|
+
streams = annotator.list
|
149
|
+
|
150
|
+
# fetch a list of events in the last hour from a stream
|
151
|
+
annotator.fetch :deployments, :start_time => (Time.now.to_i-3600)
|
152
|
+
|
153
|
+
# delete an event
|
154
|
+
annotator.delete_event 'deployments', 23
|
155
|
+
|
156
|
+
See the documentation of `Annotator` for more details and examples of use.
|
157
|
+
|
129
158
|
## Auto-Submitting Metrics
|
130
159
|
|
131
160
|
Both `Queue` and `Aggregator` support automatically submitting measurements on a given time interval:
|
132
161
|
|
133
162
|
# submit once per minute
|
134
163
|
timed_queue = Librato::Metrics::Queue.new(:autosubmit_interval => 60)
|
135
|
-
|
164
|
+
|
136
165
|
# submit every 5 minutes
|
137
166
|
timed_aggregator = Librato::Metrics::Aggregator.new(:autosubmit_interval => 300)
|
138
|
-
|
167
|
+
|
139
168
|
`Queue` also supports auto-submission based on measurement volume:
|
140
169
|
|
141
170
|
# submit when the 400th measurement is queued
|
142
171
|
volume_queue = Librato::Metrics::Queue.new(:autosubmit_count => 400)
|
143
172
|
|
144
|
-
These options can also be combined for more flexible behavior.
|
173
|
+
These options can also be combined for more flexible behavior.
|
145
174
|
|
146
175
|
Both options are driven by the addition of measurements. Specifically for time-based autosubmission if you are adding measurements irregularly (less than once per second), submission may lag past your specified interval until the next measurement is added.
|
147
176
|
|
@@ -181,7 +210,7 @@ If you ever need to remove a metric and all of its measurements, doing so is eas
|
|
181
210
|
|
182
211
|
# Delete the metrics 'temperature' and 'humidity'
|
183
212
|
Librato::Metrics.delete :temperature, :humidity
|
184
|
-
|
213
|
+
|
185
214
|
Note that deleted metrics and their measurements are unrecoverable, so use with care.
|
186
215
|
|
187
216
|
## Using Multiple Accounts Simultaneously
|
@@ -190,7 +219,7 @@ If you need to use metrics with multiple sets of authentication credentials simu
|
|
190
219
|
|
191
220
|
joe = Librato::Metrics::Client.new
|
192
221
|
joe.authenticate 'email1', 'api_key1'
|
193
|
-
|
222
|
+
|
194
223
|
mike = Librato::Metrics::Client.new
|
195
224
|
mike.authenticate 'email2', 'api_key2'
|
196
225
|
|
@@ -198,16 +227,16 @@ All of the same operations you can call directly from `Librato::Metrics` are ava
|
|
198
227
|
|
199
228
|
# list Joe's metrics
|
200
229
|
joe.list
|
201
|
-
|
202
|
-
# fetch the last 20 data points for Mike's metric, humidity
|
230
|
+
|
231
|
+
# fetch the last 20 data points for Mike's metric, humidity
|
203
232
|
mike.fetch :humidity, :count => 20
|
204
|
-
|
233
|
+
|
205
234
|
There are two ways to associate a new queue with a client:
|
206
235
|
|
207
236
|
# these are functionally equivalent
|
208
237
|
joe_queue = Librato::Metrics::Queue.new(:client => joe)
|
209
238
|
joe_queue = joe.new_queue
|
210
|
-
|
239
|
+
|
211
240
|
Once the queue is associated you can use it normally:
|
212
241
|
|
213
242
|
joe_queue.add :temperature => {:source => 'sf', :value => 65.2}
|
data/lib/librato/metrics.rb
CHANGED
@@ -5,6 +5,7 @@ require 'base64'
|
|
5
5
|
require 'multi_json'
|
6
6
|
|
7
7
|
require 'metrics/aggregator'
|
8
|
+
require 'metrics/annotator'
|
8
9
|
require 'metrics/client'
|
9
10
|
require 'metrics/collection'
|
10
11
|
require 'metrics/connection'
|
@@ -67,12 +68,14 @@ module Librato
|
|
67
68
|
PLURAL_TYPES = [:counters, :gauges]
|
68
69
|
MIN_MEASURE_TIME = (Time.now-(3600*24*365)).to_i
|
69
70
|
|
70
|
-
#
|
71
|
+
# Most of the singleton methods of Librato::Metrics are actually
|
72
|
+
# being called on a global Client instance. See further docs on
|
73
|
+
# Client.
|
71
74
|
#
|
72
|
-
def_delegators :client, :agent_identifier, :api_endpoint,
|
75
|
+
def_delegators :client, :agent_identifier, :annotate, :api_endpoint,
|
73
76
|
:api_endpoint=, :authenticate, :connection, :delete,
|
74
|
-
:faraday_adapter, :faraday_adapter=, :fetch, :list,
|
75
|
-
:persistence, :persistence=, :persister, :submit,
|
77
|
+
:faraday_adapter, :faraday_adapter=, :fetch, :list,
|
78
|
+
:persistence, :persistence=, :persister, :submit,
|
76
79
|
:update
|
77
80
|
|
78
81
|
# The Librato::Metrics::Client being used by module-level
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Librato::Metrics
|
2
|
+
|
3
|
+
# manages writing and reading annotation streams for a
|
4
|
+
# given client connection
|
5
|
+
class Annotator
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@client = options[:client] || Librato::Metrics.client
|
9
|
+
end
|
10
|
+
|
11
|
+
# Creates a new annotation on the annotation stream
|
12
|
+
#
|
13
|
+
# @example Simple annotation
|
14
|
+
# annotator.add :deployments, 'deployed v45'
|
15
|
+
#
|
16
|
+
# @example Annotation with start and end times
|
17
|
+
# annotator.add :deployments, 'deployed v56', :start_time => start,
|
18
|
+
# :end_time => end
|
19
|
+
#
|
20
|
+
# @example Annotation with a specific source
|
21
|
+
# annotator.add :deployments, 'deployed v60', :source => 'app12'
|
22
|
+
#
|
23
|
+
# @example Annotation with a description
|
24
|
+
# annotator.add :deployments, 'deployed v61',
|
25
|
+
# :description => '9b562b2: shipped new feature foo!'
|
26
|
+
#
|
27
|
+
def add(stream, title, options={})
|
28
|
+
options[:title] = title
|
29
|
+
if options[:start_time]
|
30
|
+
options[:start_time] = options[:start_time].to_i
|
31
|
+
end
|
32
|
+
if options[:end_time]
|
33
|
+
options[:end_time] = options[:end_time].to_i
|
34
|
+
end
|
35
|
+
payload = SmartJSON.write(options)
|
36
|
+
# expects 200
|
37
|
+
connection.post("annotations/#{stream}", payload)
|
38
|
+
end
|
39
|
+
|
40
|
+
def client
|
41
|
+
@client
|
42
|
+
end
|
43
|
+
|
44
|
+
def connection
|
45
|
+
client.connection
|
46
|
+
end
|
47
|
+
|
48
|
+
# Delete an annotation streams
|
49
|
+
#
|
50
|
+
# @example Delete 'deployment' annotation stream
|
51
|
+
# annotator.delete :deployment
|
52
|
+
#
|
53
|
+
def delete(stream)
|
54
|
+
connection.delete do |request|
|
55
|
+
request.url connection.build_url("annotations/#{stream}")
|
56
|
+
end
|
57
|
+
# expects 204, middleware will raise exception otherwise
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
# Delete an event from a given annotation stream
|
62
|
+
#
|
63
|
+
# @example Delete event with id 42 from 'deployment'
|
64
|
+
# annotator.delete_event :deployment, 42
|
65
|
+
#
|
66
|
+
def delete_event(stream, id)
|
67
|
+
connection.delete do |request|
|
68
|
+
request.url connection.build_url("annotations/#{stream}/#{id}")
|
69
|
+
end
|
70
|
+
# expects 204, middleware will raise exception otherwise
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get a list of annotation events on a given annotation stream
|
75
|
+
#
|
76
|
+
# @example See properties of the 'deployments' annotation stream
|
77
|
+
# annotator.fetch :deployments
|
78
|
+
#
|
79
|
+
# @example Get events on 'deployments' between start and end times
|
80
|
+
# annotator.fetch :deployments, :start_time => start, :end_time => end
|
81
|
+
#
|
82
|
+
# @example Source-limited listing
|
83
|
+
# annotator.fetch :deployments, :sources => ['foo','bar','baz'],
|
84
|
+
# :start_time => start, :end_time => end
|
85
|
+
#
|
86
|
+
def fetch(stream, options={})
|
87
|
+
response = connection.get("annotations/#{stream}", options)
|
88
|
+
SmartJSON.read(response.body)
|
89
|
+
end
|
90
|
+
|
91
|
+
# List currently existing annotation streams
|
92
|
+
#
|
93
|
+
# @example List all annotation streams
|
94
|
+
# streams = annotator.list
|
95
|
+
#
|
96
|
+
# @example List annotator streams with 'deploy' in the name
|
97
|
+
# deploy_streams = annotator.list :name => 'deploy'
|
98
|
+
#
|
99
|
+
def list(options={})
|
100
|
+
response = connection.get("annotations", options)
|
101
|
+
SmartJSON.read(response.body)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -2,6 +2,10 @@ module Librato
|
|
2
2
|
module Metrics
|
3
3
|
|
4
4
|
class Client
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegator :annotator, :add, :annotate
|
8
|
+
|
5
9
|
attr_accessor :email, :api_key
|
6
10
|
|
7
11
|
# Provide agent identifier for the developer program. See:
|
@@ -26,6 +30,10 @@ module Librato
|
|
26
30
|
@agent_identifier ||= ''
|
27
31
|
end
|
28
32
|
|
33
|
+
def annotator
|
34
|
+
@annotator ||= Annotator.new(:client => self)
|
35
|
+
end
|
36
|
+
|
29
37
|
# API endpoint to use for queries and direct
|
30
38
|
# persistence.
|
31
39
|
#
|
@@ -57,7 +65,7 @@ module Librato
|
|
57
65
|
def connection
|
58
66
|
# prevent successful creation if no credentials set
|
59
67
|
raise CredentialsMissing unless (self.email and self.api_key)
|
60
|
-
@connection ||= Connection.new(:client => self, :api_endpoint => api_endpoint,
|
68
|
+
@connection ||= Connection.new(:client => self, :api_endpoint => api_endpoint,
|
61
69
|
:adapter => faraday_adapter)
|
62
70
|
end
|
63
71
|
|
@@ -94,14 +102,14 @@ module Librato
|
|
94
102
|
# otherwise.
|
95
103
|
true
|
96
104
|
end
|
97
|
-
|
105
|
+
|
98
106
|
# Return current adapter this client will use.
|
99
107
|
# Defaults to Metrics.faraday_adapter if set, otherwise
|
100
108
|
# Faraday.default_adapter
|
101
109
|
def faraday_adapter
|
102
110
|
@faraday_adapter ||= default_faraday_adapter
|
103
111
|
end
|
104
|
-
|
112
|
+
|
105
113
|
# Set faraday adapter this client will use
|
106
114
|
def faraday_adapter=(adapter)
|
107
115
|
@faraday_adapter = adapter
|
@@ -234,7 +242,7 @@ module Librato
|
|
234
242
|
end
|
235
243
|
|
236
244
|
private
|
237
|
-
|
245
|
+
|
238
246
|
def default_faraday_adapter
|
239
247
|
if Metrics.client == self
|
240
248
|
Faraday.default_adapter
|
@@ -5,7 +5,6 @@ module Librato
|
|
5
5
|
class MetricsError < StandardError; end
|
6
6
|
|
7
7
|
class CredentialsMissing < MetricsError; end
|
8
|
-
class NoMetricsQueued < MetricsError; end
|
9
8
|
class NoMetricsProvided < MetricsError; end
|
10
9
|
class NoClientProvided < MetricsError; end
|
11
10
|
class InvalidMeasureTime < MetricsError; end
|
@@ -27,7 +27,7 @@ module Librato
|
|
27
27
|
#
|
28
28
|
# @return Boolean
|
29
29
|
def submit
|
30
|
-
|
30
|
+
return true if self.queued.empty?
|
31
31
|
options = {:per_request => @per_request}
|
32
32
|
if persister.persist(self.client, self.queued, options)
|
33
33
|
@last_submit_time = Time.now
|
@@ -84,7 +84,7 @@ module Librato
|
|
84
84
|
@client = options[:client] || Librato::Metrics.client
|
85
85
|
@per_request = options[:per_request] || MEASUREMENTS_PER_REQUEST
|
86
86
|
@source = options[:source]
|
87
|
-
@measure_time = options[:measure_time]
|
87
|
+
@measure_time = options[:measure_time] && options[:measure_time].to_i
|
88
88
|
@create_time = Time.now
|
89
89
|
@clear_on_failure = options[:clear_failures] || false
|
90
90
|
@prefix = options[:prefix]
|
@@ -33,6 +33,7 @@ module Librato
|
|
33
33
|
end
|
34
34
|
type = ("#{type}s").to_sym
|
35
35
|
if metric[:measure_time]
|
36
|
+
metric[:measure_time] = metric[:measure_time].to_i
|
36
37
|
check_measure_time(metric)
|
37
38
|
elsif !skip_measurement_times
|
38
39
|
metric[:measure_time] = epoch_time
|
@@ -123,7 +124,7 @@ module Librato
|
|
123
124
|
private
|
124
125
|
|
125
126
|
def check_measure_time(data)
|
126
|
-
if data[:measure_time]
|
127
|
+
if data[:measure_time] < Metrics::MIN_MEASURE_TIME
|
127
128
|
raise InvalidMeasureTime, "Measure time for submitted metric (#{data}) is invalid."
|
128
129
|
end
|
129
130
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Librato
|
4
|
+
module Metrics
|
5
|
+
|
6
|
+
describe Annotator do
|
7
|
+
before(:all) { prep_integration_tests }
|
8
|
+
before(:each) { delete_all_annotations }
|
9
|
+
|
10
|
+
describe "#add" do
|
11
|
+
it "should create new annotation" do
|
12
|
+
subject.add :deployment, "deployed v68"
|
13
|
+
annos = subject.fetch(:deployment, :start_time => Time.now.to_i-60)
|
14
|
+
annos["events"]["unassigned"].length.should == 1
|
15
|
+
annos["events"]["unassigned"][0]["title"].should == 'deployed v68'
|
16
|
+
end
|
17
|
+
it "should support sources" do
|
18
|
+
subject.add :deployment, 'deployed v69', :source => 'box1'
|
19
|
+
annos = subject.fetch(:deployment, :start_time => Time.now.to_i-60)
|
20
|
+
annos["events"]["box1"].length.should == 1
|
21
|
+
first = annos["events"]["box1"][0]
|
22
|
+
first['title'].should == 'deployed v69'
|
23
|
+
end
|
24
|
+
it "should support start and end times" do
|
25
|
+
start_time = Time.now.to_i-120
|
26
|
+
end_time = Time.now.to_i-30
|
27
|
+
subject.add :deployment, 'deployed v70', :start_time => start_time,
|
28
|
+
:end_time => end_time
|
29
|
+
annos = subject.fetch(:deployment, :start_time => Time.now.to_i-180)
|
30
|
+
annos["events"]["unassigned"].length.should == 1
|
31
|
+
first = annos["events"]["unassigned"][0]
|
32
|
+
first['title'].should == 'deployed v70'
|
33
|
+
first['start_time'].should == start_time
|
34
|
+
first['end_time'].should == end_time
|
35
|
+
end
|
36
|
+
it "should support description" do
|
37
|
+
subject.add :deployment, 'deployed v71', :description => 'deployed foobar!'
|
38
|
+
annos = subject.fetch(:deployment, :start_time => Time.now.to_i-180)
|
39
|
+
annos["events"]["unassigned"].length.should == 1
|
40
|
+
first = annos["events"]["unassigned"][0]
|
41
|
+
first['title'].should == 'deployed v71'
|
42
|
+
first['description'].should == 'deployed foobar!'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#delete" do
|
47
|
+
it "should remove annotation streams" do
|
48
|
+
subject.add :deployment, "deployed v45"
|
49
|
+
subject.fetch :deployment # should exist
|
50
|
+
subject.delete :deployment
|
51
|
+
lambda {
|
52
|
+
subject.fetch(:deployment)
|
53
|
+
}.should raise_error(Metrics::NotFound)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#delete_event" do
|
58
|
+
it "should remove an annotation event" do
|
59
|
+
subject.add :deployment, 'deployed v46'
|
60
|
+
subject.add :deployment, 'deployed v47'
|
61
|
+
events = subject.fetch(:deployment, :start_time => Time.now.to_i-60)
|
62
|
+
events = events['events']['unassigned']
|
63
|
+
ids = events.each_with_object({}) do |event, hash|
|
64
|
+
hash[event['title']] = event['id']
|
65
|
+
end
|
66
|
+
subject.delete_event :deployment, ids['deployed v47']
|
67
|
+
events = subject.fetch(:deployment, :start_time => Time.now.to_i-60)
|
68
|
+
events = events['events']['unassigned']
|
69
|
+
events.length.should == 1
|
70
|
+
events[0]['title'].should == 'deployed v46'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#fetch" do
|
75
|
+
context "without a time frame" do
|
76
|
+
it "should return stream properties" do
|
77
|
+
subject.add :backups, "backup 21"
|
78
|
+
properties = subject.fetch :backups
|
79
|
+
properties['name'].should == 'backups'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with a time frame" do
|
84
|
+
it "should return set of annotations" do
|
85
|
+
subject.add :backups, "backup 22"
|
86
|
+
subject.add :backups, "backup 23"
|
87
|
+
annos = subject.fetch :backups, :start_time => Time.now.to_i-60
|
88
|
+
events = annos['events']['unassigned']
|
89
|
+
events[0]['title'].should == 'backup 22'
|
90
|
+
events[1]['title'].should == 'backup 23'
|
91
|
+
end
|
92
|
+
it "should respect source limits" do
|
93
|
+
subject.add :backups, "backup 24", :source => 'server_1'
|
94
|
+
subject.add :backups, "backup 25", :source => 'server_2'
|
95
|
+
subject.add :backups, "backup 26", :source => 'server_3'
|
96
|
+
annos = subject.fetch :backups, :start_time => Time.now.to_i-60,
|
97
|
+
:sources => %w{server_1 server_3}
|
98
|
+
annos['events']['server_1'].should_not be_nil
|
99
|
+
annos['events']['server_2'].should be_nil
|
100
|
+
annos['events']['server_3'].should_not be_nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return exception if annotation is missing" do
|
105
|
+
lambda {
|
106
|
+
subject.fetch :backups
|
107
|
+
}.should raise_error(Metrics::NotFound)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#list" do
|
112
|
+
before(:each) do
|
113
|
+
subject.add :backups, 'backup 1'
|
114
|
+
subject.add :deployment, 'deployed v74'
|
115
|
+
end
|
116
|
+
|
117
|
+
context "without arguments" do
|
118
|
+
it "should list annotation streams" do
|
119
|
+
streams = subject.list
|
120
|
+
streams['annotations'].length.should == 2
|
121
|
+
streams = streams['annotations'].map{|i| i['name']}
|
122
|
+
streams.should include('backups')
|
123
|
+
streams.should include('deployment')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
context "with an argument" do
|
127
|
+
it "should list annotation streams which match" do
|
128
|
+
streams = subject.list :name => 'back'
|
129
|
+
streams['annotations'].length.should == 1
|
130
|
+
streams = streams['annotations'].map{|i| i['name']}
|
131
|
+
streams.should include('backups')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -4,6 +4,45 @@ module Librato
|
|
4
4
|
describe Metrics do
|
5
5
|
before(:all) { prep_integration_tests }
|
6
6
|
|
7
|
+
describe "#annotate" do
|
8
|
+
before(:all) { @annotator = Metrics::Annotator.new }
|
9
|
+
before(:each) { delete_all_annotations }
|
10
|
+
|
11
|
+
it "should create new annotation" do
|
12
|
+
Metrics.annotate :deployment, "deployed v68"
|
13
|
+
annos = @annotator.fetch(:deployment, :start_time => Time.now.to_i-60)
|
14
|
+
annos["events"]["unassigned"].length.should == 1
|
15
|
+
annos["events"]["unassigned"][0]["title"].should == 'deployed v68'
|
16
|
+
end
|
17
|
+
it "should support sources" do
|
18
|
+
Metrics.annotate :deployment, 'deployed v69', :source => 'box1'
|
19
|
+
annos = @annotator.fetch(:deployment, :start_time => Time.now.to_i-60)
|
20
|
+
annos["events"]["box1"].length.should == 1
|
21
|
+
first = annos["events"]["box1"][0]
|
22
|
+
first['title'].should == 'deployed v69'
|
23
|
+
end
|
24
|
+
it "should support start and end times" do
|
25
|
+
start_time = Time.now.to_i-120
|
26
|
+
end_time = Time.now.to_i-30
|
27
|
+
Metrics.annotate :deployment, 'deployed v70', :start_time => start_time,
|
28
|
+
:end_time => end_time
|
29
|
+
annos = @annotator.fetch(:deployment, :start_time => Time.now.to_i-180)
|
30
|
+
annos["events"]["unassigned"].length.should == 1
|
31
|
+
first = annos["events"]["unassigned"][0]
|
32
|
+
first['title'].should == 'deployed v70'
|
33
|
+
first['start_time'].should == start_time
|
34
|
+
first['end_time'].should == end_time
|
35
|
+
end
|
36
|
+
it "should support description" do
|
37
|
+
Metrics.annotate :deployment, 'deployed v71', :description => 'deployed foobar!'
|
38
|
+
annos = @annotator.fetch(:deployment, :start_time => Time.now.to_i-180)
|
39
|
+
annos["events"]["unassigned"].length.should == 1
|
40
|
+
first = annos["events"]["unassigned"][0]
|
41
|
+
first['title'].should == 'deployed v71'
|
42
|
+
first['description'].should == 'deployed foobar!'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
7
46
|
describe "#delete" do
|
8
47
|
before(:each) { delete_all_metrics }
|
9
48
|
|
data/spec/spec_helper.rb
CHANGED
@@ -21,6 +21,16 @@ RSpec.configure do |config|
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
# purge all annotations from test account
|
25
|
+
def delete_all_annotations
|
26
|
+
annotator = Librato::Metrics::Annotator.new
|
27
|
+
streams = annotator.list
|
28
|
+
if streams['annotations']
|
29
|
+
names = streams['annotations'].map{|s| s['name']}
|
30
|
+
names.each { |name| annotator.delete name}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
24
34
|
# set up test account credentials for integration tests
|
25
35
|
def prep_integration_tests
|
26
36
|
raise 'no TEST_API_USER specified in environment' unless ENV['TEST_API_USER']
|
@@ -67,7 +67,7 @@ module Librato
|
|
67
67
|
:description => 'current disk utilization', :measure_time => measure_time,
|
68
68
|
:source => 'db2'}
|
69
69
|
expected = {:gauges => [{:value => 35.4, :name => 'disk_use', :period => 2,
|
70
|
-
:description => 'current disk utilization', :measure_time => measure_time,
|
70
|
+
:description => 'current disk utilization', :measure_time => measure_time.to_i,
|
71
71
|
:source => 'db2'}]}
|
72
72
|
subject.queued.should equal_unordered(expected)
|
73
73
|
end
|
@@ -116,7 +116,7 @@ module Librato
|
|
116
116
|
it "should accept time objects" do
|
117
117
|
time = Time.now-5
|
118
118
|
subject.add :foo => {:measure_time => time, :value => 123}
|
119
|
-
subject.queued[:gauges][0][:measure_time].should == time
|
119
|
+
subject.queued[:gauges][0][:measure_time].should == time.to_i
|
120
120
|
end
|
121
121
|
|
122
122
|
it "should accept integers" do
|
@@ -128,7 +128,7 @@ module Librato
|
|
128
128
|
it "should accept strings" do
|
129
129
|
time = '1336574713'
|
130
130
|
subject.add :foo => {:measure_time => time, :value => 123}
|
131
|
-
subject.queued[:gauges][0][:measure_time].should == time
|
131
|
+
subject.queued[:gauges][0][:measure_time].should == time.to_i
|
132
132
|
end
|
133
133
|
|
134
134
|
it "should raise exception in invalid time" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: librato-metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -173,6 +173,7 @@ files:
|
|
173
173
|
- benchmarks/array_vs_set.rb
|
174
174
|
- lib/librato/metrics.rb
|
175
175
|
- lib/librato/metrics/aggregator.rb
|
176
|
+
- lib/librato/metrics/annotator.rb
|
176
177
|
- lib/librato/metrics/client.rb
|
177
178
|
- lib/librato/metrics/collection.rb
|
178
179
|
- lib/librato/metrics/connection.rb
|
@@ -189,6 +190,7 @@ files:
|
|
189
190
|
- lib/librato/metrics/smart_json.rb
|
190
191
|
- lib/librato/metrics/version.rb
|
191
192
|
- librato-metrics.gemspec
|
193
|
+
- spec/integration/metrics/annotator_spec.rb
|
192
194
|
- spec/integration/metrics/connection_spec.rb
|
193
195
|
- spec/integration/metrics/middleware/count_requests_spec.rb
|
194
196
|
- spec/integration/metrics/queue_spec.rb
|
@@ -216,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
216
218
|
version: '0'
|
217
219
|
segments:
|
218
220
|
- 0
|
219
|
-
hash:
|
221
|
+
hash: 3364933911255209794
|
220
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
223
|
none: false
|
222
224
|
requirements:
|
@@ -230,6 +232,7 @@ signing_key:
|
|
230
232
|
specification_version: 2
|
231
233
|
summary: Ruby wrapper for Librato's Metrics API
|
232
234
|
test_files:
|
235
|
+
- spec/integration/metrics/annotator_spec.rb
|
233
236
|
- spec/integration/metrics/connection_spec.rb
|
234
237
|
- spec/integration/metrics/middleware/count_requests_spec.rb
|
235
238
|
- spec/integration/metrics/queue_spec.rb
|