wavefront-sdk 2.3.0 → 2.4.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.
- checksums.yaml +4 -4
- data/HISTORY.md +14 -0
- data/README.md +190 -37
- data/lib/wavefront-sdk/core/exception.rb +1 -0
- data/lib/wavefront-sdk/defs/version.rb +1 -1
- data/lib/wavefront-sdk/distribution.rb +3 -1
- data/lib/wavefront-sdk/metric_helper.rb +181 -0
- data/lib/wavefront-sdk/write.rb +19 -6
- data/lib/wavefront-sdk/writers/core.rb +8 -4
- data/lib/wavefront-sdk/writers/socket.rb +3 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/wavefront-sdk/distribution_spec.rb +7 -8
- data/spec/wavefront-sdk/metric_helper_spec.rb +279 -0
- data/spec/wavefront-sdk/writers/core_spec.rb +4 -0
- data/spec/wavefront-sdk/writers/socket_spec.rb +0 -8
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae4a49d72cb51beb4506cf0ea7049cc992e59d7699c37e7e59be1312c7b8d3b0
|
4
|
+
data.tar.gz: 8f0c3227f635bf86bdb1eca4e0091d9fb31abf0a99ada3cfcacd57e20a90655c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd4638fdafec9d0bc5afc327451f81a5d1dd8ef36409f4249e868e948ceb836528bed3bfa369f568dc0b959817a44c83aa5340eee20145d4347ac0a61a1d7904
|
7
|
+
data.tar.gz: c1b87ee6385563a046e6d76c9e914ff5f4b635c4cdcf9179f84f44c1db6f87967028df4fdfb40ba25a0dca745f83a1bd43c229e91ae6893e170eba7c66b34dbc
|
data/HISTORY.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 2.4.0 (28/01/2019)
|
4
|
+
* New `Wavefront::MetricHelper` class creates and in-memory buffer
|
5
|
+
to which you can instantaneously add metrics, flushing it to
|
6
|
+
Wavefront when appropriate. All `Writer` types are supported.
|
7
|
+
* Add `noauto` option to `Write` class. This lets you manage the
|
8
|
+
connection yourself without having to pass `false` as the second
|
9
|
+
argument to every single `Write#write` call. (Though this still
|
10
|
+
works.)
|
11
|
+
* Improve error handling when proxy socket is not available.
|
12
|
+
* Raise an exception if an interval is not given when writing a
|
13
|
+
histogram.
|
14
|
+
* Improve `README` instructions on writing metrics.
|
15
|
+
* Support Ruby 2.6.
|
16
|
+
|
3
17
|
## 2.3.0 (06/01/2019)
|
4
18
|
* When sending points via the API, send bundles of up to 100 points
|
5
19
|
with each `POST`, rather than a call per point.
|
data/README.md
CHANGED
@@ -47,6 +47,7 @@ object. Map objects can be interrogated in various ways. For
|
|
47
47
|
instance `map['items']`, `map[:items]` and `map.items` will all get
|
48
48
|
you to the same place.
|
49
49
|
|
50
|
+
### Standard API Calls
|
50
51
|
|
51
52
|
```ruby
|
52
53
|
# Define our API endpoint. (This is not a valid token!)
|
@@ -120,6 +121,32 @@ last 10 minutes, with one minute bucket granularity. We will
|
|
120
121
|
describe the time as a Ruby object, but could also use an epoch
|
121
122
|
timestamp. The SDK happily converts between the two.
|
122
123
|
|
124
|
+
### Credentials
|
125
|
+
|
126
|
+
The SDK provides a helper class for extracting credentials from a
|
127
|
+
configuration file. If you don't supply a file, defaults will be
|
128
|
+
used. You can even override things with environment variables.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
require 'wavefront-sdk/credentials'
|
132
|
+
|
133
|
+
c = Wavefront::Credentials.new
|
134
|
+
|
135
|
+
# Now use that to list the alerts in our account
|
136
|
+
|
137
|
+
require 'wavefront-sdk/alert'
|
138
|
+
|
139
|
+
p Wavefront::Alert.new(c.creds).list
|
140
|
+
|
141
|
+
# To get proxy configuration, use the `proxy` method. This is
|
142
|
+
# required by the Write class. You can also use c.all, which
|
143
|
+
# includes proxy and API configuration.
|
144
|
+
|
145
|
+
wf = Wavefront::Write.new(c.proxy)
|
146
|
+
wf = Wavefront::Write.new(c.all)
|
147
|
+
```
|
148
|
+
|
149
|
+
### Queries
|
123
150
|
|
124
151
|
```ruby
|
125
152
|
require 'wavefront-sdk/query'
|
@@ -131,68 +158,194 @@ Wavefront::Query.new(CREDS).query(
|
|
131
158
|
)
|
132
159
|
```
|
133
160
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
161
|
+
### Sending Metrics
|
162
|
+
|
163
|
+
The `Wavefront::Write` and `Wavefront::Distribution` classes lets
|
164
|
+
you send points to Wavefront in a number of ways.
|
165
|
+
|
166
|
+
#### Sending Points
|
167
|
+
|
168
|
+
Use `Wavefront::Write` to send points. Points are described as an
|
169
|
+
array of hashes. For example:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.proxy)
|
173
|
+
wf.write([{ path: 'dev.test.sdk', value: 10 }])
|
174
|
+
```
|
175
|
+
|
176
|
+
The point hash also accepts optional `source`, `ts`, and `tag` keys.
|
177
|
+
`tag` is a hash describing point tags. For example.
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
wf.write({ path: 'dev.test.sdk',
|
181
|
+
value: 10,
|
182
|
+
ts: Time.now,
|
183
|
+
source: 'example',
|
184
|
+
tags: { language: 'ruby',
|
185
|
+
level: 'beginner'})
|
186
|
+
```
|
187
|
+
|
188
|
+
As the example shows, if you are sending a single point, you can
|
189
|
+
send a naked hash, omitting the array syntax.
|
190
|
+
|
191
|
+
By default, `Wavefront::Write#write` will open a connection to
|
192
|
+
Wavefront on each call, closing it after use.
|
193
|
+
|
194
|
+
If you prefer to manage the connection yourself, supply `noauto:
|
195
|
+
true` in the options hash when instantiating the `Write` class.
|
140
196
|
|
141
197
|
```ruby
|
142
|
-
|
198
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.proxy, noauto: true)
|
199
|
+
wf.open
|
200
|
+
wf.write(path: 'dev.test.sdk', value: 10)
|
201
|
+
wf.close
|
202
|
+
```
|
143
203
|
|
144
|
-
|
204
|
+
Alternatively, pass `false` as the second argument to `Write#write`.
|
205
|
+
(This is the legacy method, kept in for backward compatability.)
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.proxy)
|
209
|
+
wf.open
|
210
|
+
wf.write([{ path: 'dev.test.sdk', value: 10 }], false)
|
211
|
+
wf.close
|
212
|
+
```
|
213
|
+
|
214
|
+
By default, `Write#write` speaks to a TCP socket on a nearby proxy,
|
215
|
+
but other methods are supported via the `writer` option.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# To send points via the API
|
219
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.creds, writer: :api)
|
145
220
|
|
146
|
-
|
221
|
+
# To send points via a local Unix socket
|
222
|
+
wf = Wavefront::Write.new(socket: '/tmp/wf_sock', { writer: :unix })
|
147
223
|
|
148
|
-
|
149
|
-
|
150
|
-
|
224
|
+
# To send points over HTTP
|
225
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.creds, writer: :http)
|
226
|
+
|
227
|
+
# Then call wf.write as before.
|
228
|
+
```
|
229
|
+
|
230
|
+
`Write` can output verbose and debug info, and the response object
|
231
|
+
provides a `summary` object.
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.proxy, verbose: true)
|
235
|
+
wf.write([{ path: 'dev.test.sdk', value: 11, tags: { tag1: 'mytag'} }])
|
236
|
+
# SDK INFO: dev.test.sdk 11 source=box tag1="mytag"
|
237
|
+
|
238
|
+
wf = Wavefront::Write.new(Wavefront::Credentials.new.proxy, debug: true)
|
239
|
+
wf.write([{ path: 'dev.test.sdk', value: 11, tags: { tag1: 'mytag'} }])
|
240
|
+
# SDK DEBUG: Connecting to wavefront:2878.
|
241
|
+
# SDK INFO: dev.test.sdk 11 source=box tag1="mytag"
|
151
242
|
# SDK DEBUG: Closing connection to proxy.
|
152
|
-
|
153
|
-
|
243
|
+
|
244
|
+
task = wf.write([{ path: 'dev.test.sdk_1', value: 1 },
|
245
|
+
{ path: 'dev.test.sdk_2', value: 2 }])
|
246
|
+
p task.response
|
247
|
+
# {"sent"=>2, "rejected"=>0, "unsent"=>0}
|
154
248
|
puts task.ok?
|
155
249
|
# true
|
156
250
|
```
|
157
251
|
|
158
|
-
You can send delta metrics
|
159
|
-
|
160
|
-
|
252
|
+
You can send delta metrics my prefixing your `path` with a delta
|
253
|
+
symbol, or by using the `Write#write_delta()` method. This is called in
|
254
|
+
exactly the same way as `Write#write`, and supports all the same
|
255
|
+
options.
|
256
|
+
|
257
|
+
#### Sending Distributions
|
161
258
|
|
162
|
-
|
163
|
-
|
259
|
+
Use the `Wavefront::Distribution` class to send distributions via a
|
260
|
+
proxy. This is an extension of `Wavefront::Write`, so usage is
|
261
|
+
almost the same. All you have to do differently is specify an
|
262
|
+
interval size (`m`, `h`, or `d`), and use a distribution as your
|
263
|
+
`value`. We give you methods to help with this. For instance:
|
164
264
|
|
165
265
|
```ruby
|
166
|
-
wf = Wavefront::
|
266
|
+
wf = Wavefront::Distribution.new(CREDS.proxy)
|
167
267
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
268
|
+
dist = wf.mk_distribution([7, 7, 7, 8, 8, 9, 10, 10])
|
269
|
+
|
270
|
+
p dist
|
271
|
+
|
272
|
+
# [[3, 7.0], [2, 8.0], [1, 9.0], [2, 10.0]]
|
273
|
+
|
274
|
+
p wf.write({ path: 'dev.test.dist', value: dist, interval: :m }).response
|
173
275
|
# {"sent"=>1, "rejected"=>0, "unsent"=>0}
|
174
|
-
puts task.ok?
|
175
|
-
# true
|
176
276
|
```
|
177
277
|
|
178
|
-
|
179
|
-
|
180
|
-
|
278
|
+
#### Metric Helpers
|
279
|
+
|
280
|
+
The `Wavefront::MetricHelper` class gives you simple ways to write
|
281
|
+
metrics to in-memory buffers, and flush those buffer whenever you see
|
282
|
+
fit. It aims to be a little bit like Dropwizard.
|
283
|
+
|
284
|
+
`MetricHelper` gives you less control over the metrics you send. For
|
285
|
+
instance, the source and timestamp are automatically sent. You can
|
286
|
+
view the buffer at any time with the `buf` `attr_accessor`.
|
181
287
|
|
182
288
|
```ruby
|
183
|
-
require 'wavefront-sdk/
|
289
|
+
require 'wavefront-sdk/metric_helper'
|
184
290
|
|
185
|
-
|
291
|
+
wf = Wavefront::MetricHelper.new(CREDS.proxy, verbose: true)
|
186
292
|
|
187
|
-
|
293
|
+
wf.gauge('my.gauge', 1)
|
294
|
+
wf.gauge('my.gauge', 2, { tag1: 'val1' })
|
295
|
+
wf.gauge('my.gauge', 3, { tag1: 'val2' })
|
296
|
+
wf.counter('my.counter')
|
297
|
+
wf.counter('my.counter', 1, { tag1: 'val1' } )
|
298
|
+
wf.counter('my.counter')
|
188
299
|
|
189
|
-
|
300
|
+
pp wf.buf
|
190
301
|
|
191
|
-
|
302
|
+
# {:gauges=>
|
303
|
+
# [{:path=>"my.gauge", :ts=>1548633249, :value=>1},
|
304
|
+
# {:path=>"my.gauge", :ts=>1548633249, :value=>2, :tags=>{:tag1=>"val1"}},
|
305
|
+
# {:path=>"my.gauge", :ts=>1548633249, :value=>3, :tags=>{:tag1=>"val2"}}],
|
306
|
+
# :counters=>{["my.counter", nil]=>2, ["my.counter", {:tag1=>"val1"}]=>1}}
|
192
307
|
|
193
|
-
|
308
|
+
wf.flush
|
194
309
|
|
195
|
-
|
310
|
+
# SDK INFO: my.gauge 1 1548633515 source=box
|
311
|
+
# SDK INFO: my.gauge 2 1548633515 source=box tag1="val1"
|
312
|
+
# SDK INFO: my.gauge 3 1548633515 source=box tag1="val2"
|
313
|
+
# SDK INFO: ∆my.counter 2 1548633515 source=box
|
314
|
+
# SDK INFO: ∆my.counter 1 1548633515 source=box tag1="val1"
|
315
|
+
|
316
|
+
pp wf.buf
|
317
|
+
|
318
|
+
# {:gauges=>[], :counters=>[]}
|
319
|
+
```
|
320
|
+
|
321
|
+
Note that gauges are sent individually, timestamped at the time they
|
322
|
+
are created. All counters are aggregated as you go along, and when
|
323
|
+
flushed, they send their value at that moment as a *single delta
|
324
|
+
metric*, the timestamp being the time of the flush.
|
325
|
+
|
326
|
+
You can also work with distributions. To do this, you must add
|
327
|
+
`dist_port` to your options hash, giving the number of the proxy
|
328
|
+
port listening for Wavefront format distributions. Numbers can be added
|
329
|
+
to distributions individually, or in an array. You must specify the
|
330
|
+
distribution interval.
|
331
|
+
|
332
|
+
```ruby
|
333
|
+
wf = Wavefront::MetricHelper.new(CREDS.proxy, { verbose: true, dist_port: 40000 })
|
334
|
+
|
335
|
+
wf.dist('my.dist', :m, 10)
|
336
|
+
wf.dist('my.dist', :m, 10)
|
337
|
+
wf.dist('my.dist', :m, [8, 8, 8, 9, 10, 10])
|
338
|
+
wf.dist('my.dist', :m, 8)
|
339
|
+
|
340
|
+
pp wf.buf
|
341
|
+
|
342
|
+
# {:gauges=>[],
|
343
|
+
# :counters=>{},
|
344
|
+
# :dists=>{["my.dist", :m, nil]=>[10, 10, 8, 8, 8, 9, 10, 10, 8]}}
|
345
|
+
|
346
|
+
wf.flush
|
347
|
+
|
348
|
+
# SDK INFO: !M 1548634226 #4 10.0 #4 8.0 #1 9.0 my.dist source=box
|
196
349
|
```
|
197
350
|
|
198
351
|
## Contributing
|
@@ -43,6 +43,7 @@ module Wavefront
|
|
43
43
|
class InvalidVersion < RuntimeError; end
|
44
44
|
class InvalidWebhookId < RuntimeError; end
|
45
45
|
class NotImplemented < RuntimeError; end
|
46
|
+
class SocketError < RuntimeError; end
|
46
47
|
class UnparseableResponse < RuntimeError; end
|
47
48
|
class UnsupportedWriter < RuntimeError; end
|
48
49
|
class ValueOutOfRange < RuntimeError; end
|
@@ -1 +1 @@
|
|
1
|
-
WF_SDK_VERSION = '2.
|
1
|
+
WF_SDK_VERSION = '2.4.0'.freeze
|
@@ -51,8 +51,10 @@ module Wavefront
|
|
51
51
|
# rubocop:disable Metrics/AbcSize
|
52
52
|
def hash_to_wf(dist)
|
53
53
|
logger.log("writer subclass #{writer}", :debug)
|
54
|
+
raise unless dist.key?(:interval)
|
55
|
+
|
54
56
|
format('!%s %i %s %s source=%s %s %s',
|
55
|
-
dist[:interval].to_s.upcase
|
57
|
+
dist[:interval].to_s.upcase,
|
56
58
|
parse_time(dist.fetch(:ts, Time.now)),
|
57
59
|
array2dist(dist[:value]),
|
58
60
|
dist[:path] || raise,
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require_relative 'write'
|
2
|
+
|
3
|
+
module Wavefront
|
4
|
+
#
|
5
|
+
# A helper class for quickly and efficiently sending metrics.
|
6
|
+
# This class creates an in-memory buffer to which you can write
|
7
|
+
# information using a number of methods. When the buffer is
|
8
|
+
# flushed, the points are send to Wavefront using any Writer
|
9
|
+
# class. You can currently write gauges, counters, and
|
10
|
+
# distributions. This list may grow in the future.
|
11
|
+
#
|
12
|
+
class MetricHelper
|
13
|
+
attr_reader :opts, :buf, :writer, :dist_writer
|
14
|
+
|
15
|
+
# See Wavefront::Write#initialize for parameters. Additionally,
|
16
|
+
# dist_port: proxy port to write distributions to. If this is
|
17
|
+
# unset, distributions will not be handled.
|
18
|
+
#
|
19
|
+
def initialize(creds, opts = {})
|
20
|
+
@opts = opts
|
21
|
+
@buf = { gauges: empty_gauges,
|
22
|
+
counters: empty_counters }
|
23
|
+
@writer = setup_writer(creds, opts)
|
24
|
+
@dist_writer = setup_dist_writer(creds, opts) if opts[:dist_port]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Writes a simple path/metric point, with optional tags,
|
28
|
+
# to the buffer. The timestamp is automatically set to the
|
29
|
+
# current epoch second. For more control, use
|
30
|
+
# Wavefront::Write#write
|
31
|
+
# @param path [String] metric path
|
32
|
+
# @param value [Numeric] metric value
|
33
|
+
# @param tags [Hash] hash of point tags
|
34
|
+
#
|
35
|
+
def gauge(path, value, tags = nil)
|
36
|
+
gauge = { path: path, ts: Time.now.to_i, value: value }
|
37
|
+
gauge[:tags] = tags if tags
|
38
|
+
@buf[:gauges].<< gauge
|
39
|
+
end
|
40
|
+
|
41
|
+
# These counters are internal, and specific to the SDK. When
|
42
|
+
# the buffer is flushed, a single value is sent to Wavefront
|
43
|
+
# for each counter. The value sent is a Wavefront delta metric.
|
44
|
+
#
|
45
|
+
# @param path [String] metric path
|
46
|
+
# @param value [Numeric] value to add to counter
|
47
|
+
# @param tags [Hash] point tags
|
48
|
+
#
|
49
|
+
def counter(path, value = 1, tags = nil)
|
50
|
+
key = [path, tags]
|
51
|
+
@buf[:counters][key] += value
|
52
|
+
end
|
53
|
+
|
54
|
+
# These distributions are stored in memory, and sent to
|
55
|
+
# Wavefront as native distibutions when the buffer is flushed.
|
56
|
+
# @param path [String] metric path
|
57
|
+
# @param value [Array, Numeric] value(s) to add to distribution
|
58
|
+
# @param interval [Symbol, String] distribution interval, :m,
|
59
|
+
# :h, or :d
|
60
|
+
# @param tags [Hash] point tags
|
61
|
+
#
|
62
|
+
def dist(path, interval, value, tags = nil)
|
63
|
+
key = [path, interval, tags]
|
64
|
+
@buf[:dists][key] += [value].flatten
|
65
|
+
end
|
66
|
+
|
67
|
+
# Flush all stored metrics. Though you can flush by individual
|
68
|
+
# type, this is the preferred method
|
69
|
+
#
|
70
|
+
def flush
|
71
|
+
flush_gauges(buf[:gauges])
|
72
|
+
flush_counters(buf[:counters])
|
73
|
+
flush_dists(buf[:dists]) if opts.key?(:dist_port)
|
74
|
+
end
|
75
|
+
|
76
|
+
# When we are asked to flush the buffers, duplicate the current
|
77
|
+
# one, hand it off to the writer class, and clear. If writer
|
78
|
+
# tells us there was an error, dump the old buffer into the
|
79
|
+
# the new one for the next flush.
|
80
|
+
#
|
81
|
+
def flush_gauges(gauges)
|
82
|
+
return if gauges.empty?
|
83
|
+
|
84
|
+
to_flush = gauges.dup
|
85
|
+
@buf[:gauges] = empty_gauges
|
86
|
+
|
87
|
+
writer.write(gauges_to_wf(gauges)).tap do |resp|
|
88
|
+
@buf[:gauges] += to_flush unless resp.ok?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def flush_counters(counters)
|
93
|
+
return if counters.empty?
|
94
|
+
|
95
|
+
to_flush = counters.dup
|
96
|
+
@buf[:counters] = empty_counters
|
97
|
+
|
98
|
+
writer.write_delta(counters_to_wf(counters)).tap do |resp|
|
99
|
+
replay_counters(to_flush) unless resp.ok?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def flush_dists(dists)
|
104
|
+
return if dists.empty?
|
105
|
+
|
106
|
+
to_flush = dists.dup
|
107
|
+
@buf[:dists] = empty_dists
|
108
|
+
|
109
|
+
dist_writer.write(dists_to_wf(dists)).tap do |resp|
|
110
|
+
replay_dists(to_flush) unless resp.ok?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Play a failed flush full of counters back into the system
|
115
|
+
#
|
116
|
+
def replay_counters(buffer)
|
117
|
+
buffer.each { |k, v| counter(k[0], v, k[1]) }
|
118
|
+
end
|
119
|
+
|
120
|
+
def replay_dists(buffer)
|
121
|
+
buffer.each { |k, v| dist(k[0], k[1], v, k[2]) }
|
122
|
+
end
|
123
|
+
|
124
|
+
# These are already Wavefront-format points
|
125
|
+
#
|
126
|
+
def gauges_to_wf(gauges)
|
127
|
+
gauges
|
128
|
+
end
|
129
|
+
|
130
|
+
def counters_to_wf(counters)
|
131
|
+
counters.map do |k, v|
|
132
|
+
path, tags = k
|
133
|
+
metric = { path: path, value: v, ts: Time.now.utc.to_i }
|
134
|
+
metric[:tags] = tags unless tags.nil?
|
135
|
+
metric
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def dists_to_wf(dists)
|
140
|
+
dists.map do |k, v|
|
141
|
+
path, interval, tags = k
|
142
|
+
dist = { path: path,
|
143
|
+
value: dist_writer.mk_distribution(v),
|
144
|
+
ts: Time.now.utc.to_i,
|
145
|
+
interval: interval }
|
146
|
+
dist[:tags] = tags unless tags.nil?
|
147
|
+
dist
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [Hash] options hash, with :port replaced by :dist_port
|
152
|
+
#
|
153
|
+
def dist_creds(creds, opts)
|
154
|
+
creds.dup.tap { |o| o[:port] = opts[:dist_port] }
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def empty_gauges
|
160
|
+
[]
|
161
|
+
end
|
162
|
+
|
163
|
+
def empty_counters
|
164
|
+
Hash.new(0)
|
165
|
+
end
|
166
|
+
|
167
|
+
def empty_dists
|
168
|
+
Hash.new([])
|
169
|
+
end
|
170
|
+
|
171
|
+
def setup_writer(creds, opts)
|
172
|
+
Wavefront::Write.new(creds, opts)
|
173
|
+
end
|
174
|
+
|
175
|
+
def setup_dist_writer(creds, opts)
|
176
|
+
require_relative 'distribution'
|
177
|
+
@buf[:dists] = empty_dists
|
178
|
+
Wavefront::Distribution.new(dist_creds(creds, opts), opts)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
data/lib/wavefront-sdk/write.rb
CHANGED
@@ -21,11 +21,10 @@ module Wavefront
|
|
21
21
|
# writing points to Wavefront. The actual writing is handled by
|
22
22
|
# a Wavefront::Writer:: subclass.
|
23
23
|
#
|
24
|
-
# @param creds [Hash] credentials
|
25
|
-
# signature.
|
26
|
-
# @param options [Hash] can contain the following keys:
|
24
|
+
# @param creds [Hash] credentials: can contain keys:
|
27
25
|
# proxy [String] the address of the Wavefront proxy. ('wavefront')
|
28
26
|
# port [Integer] the port of the Wavefront proxy
|
27
|
+
# @param options [Hash] can contain the following keys:
|
29
28
|
# tags [Hash] point tags which will be applied to every point
|
30
29
|
# noop [Bool] if true, no proxy connection will be made, and
|
31
30
|
# instead of sending the points, they will be printed in
|
@@ -38,12 +37,16 @@ module Wavefront
|
|
38
37
|
# debug [Bool]
|
39
38
|
# writer [Symbol, String] the name of the writer class to use.
|
40
39
|
# Defaults to :socket
|
40
|
+
# noauto [Bool] if this is false, #write will automatically
|
41
|
+
# open a connection to Wavefront on each invocation. Set
|
42
|
+
# this to true to manually manage the connection.
|
41
43
|
#
|
42
44
|
def initialize(creds = {}, opts = {})
|
43
45
|
defaults = { tags: nil,
|
44
46
|
writer: :socket,
|
45
47
|
noop: false,
|
46
48
|
novalidate: false,
|
49
|
+
noauto: false,
|
47
50
|
verbose: false,
|
48
51
|
debug: false }
|
49
52
|
|
@@ -76,10 +79,20 @@ module Wavefront
|
|
76
79
|
# appropriate class documentation for @return information etc.
|
77
80
|
# The signature is always the same.
|
78
81
|
#
|
79
|
-
def write(points = [], openclose =
|
82
|
+
def write(points = [], openclose = manage_conn, prefix = nil)
|
80
83
|
writer.write(points, openclose, prefix)
|
81
84
|
end
|
82
85
|
|
86
|
+
# Wrapper around writer class's #flush method
|
87
|
+
#
|
88
|
+
def flush
|
89
|
+
writer.flush
|
90
|
+
end
|
91
|
+
|
92
|
+
def manage_conn
|
93
|
+
opts[:noauto] ? false : true
|
94
|
+
end
|
95
|
+
|
83
96
|
# A wrapper method around #write() which guarantees all points
|
84
97
|
# will be sent as deltas. You can still manually prefix any
|
85
98
|
# metric with a delta symbol and use #write(), but depending on
|
@@ -89,7 +102,7 @@ module Wavefront
|
|
89
102
|
# @param points [Array[Hash]] see #write()
|
90
103
|
# @param openclose [Bool] see #write()
|
91
104
|
#
|
92
|
-
def write_delta(points, openclose =
|
105
|
+
def write_delta(points, openclose = manage_conn)
|
93
106
|
write(paths_to_deltas(points), openclose)
|
94
107
|
end
|
95
108
|
|
@@ -129,7 +142,7 @@ module Wavefront
|
|
129
142
|
# open a socket to the proxy before sending points, and
|
130
143
|
# afterwards, close it.
|
131
144
|
#
|
132
|
-
def raw(points, openclose =
|
145
|
+
def raw(points, openclose = manage_conn)
|
133
146
|
writer.open if openclose && writer.respond_to?(:open)
|
134
147
|
|
135
148
|
begin
|
@@ -30,6 +30,7 @@ module Wavefront
|
|
30
30
|
@creds = calling_class.creds
|
31
31
|
@opts = calling_class.opts
|
32
32
|
@logger = calling_class.logger
|
33
|
+
@manage_conn = calling_class.manage_conn
|
33
34
|
@summary = Wavefront::Writer::Summary.new
|
34
35
|
|
35
36
|
validate_credentials(creds) if respond_to?(:validate_credentials)
|
@@ -47,11 +48,14 @@ module Wavefront
|
|
47
48
|
# @raise any unhandled point validation error is passed through
|
48
49
|
# @return [Wavefront::Response]
|
49
50
|
#
|
50
|
-
def write(points = [], openclose =
|
51
|
-
open if openclose && respond_to?(:open)
|
52
|
-
|
51
|
+
def write(points = [], openclose = manage_conn, prefix = nil)
|
53
52
|
points = screen_points(points)
|
54
53
|
points = prefix_points(points, prefix)
|
54
|
+
do_write(points, openclose, prefix)
|
55
|
+
end
|
56
|
+
|
57
|
+
def do_write(points, openclose, _prefix)
|
58
|
+
open if openclose && respond_to?(:open)
|
55
59
|
|
56
60
|
begin
|
57
61
|
write_loop(points)
|
@@ -78,7 +82,7 @@ module Wavefront
|
|
78
82
|
true
|
79
83
|
rescue StandardError => e
|
80
84
|
summary.unsent += 1
|
81
|
-
logger.log('
|
85
|
+
logger.log('Failed to send point.', :warn)
|
82
86
|
logger.log(e.to_s, :debug)
|
83
87
|
false
|
84
88
|
end
|
@@ -51,9 +51,12 @@ module Wavefront
|
|
51
51
|
|
52
52
|
# @param point [String] point or points in native Wavefront
|
53
53
|
# format.
|
54
|
+
# @raise [SocketError] if point cannot be written
|
54
55
|
#
|
55
56
|
def _send_point(point)
|
56
57
|
conn.puts(point)
|
58
|
+
rescue StandardError
|
59
|
+
raise Wavefront::Exception::SocketError
|
57
60
|
end
|
58
61
|
|
59
62
|
# return [Integer] the port to connect to, if none is supplied
|
data/spec/spec_helper.rb
CHANGED
@@ -171,3 +171,23 @@ class Hash
|
|
171
171
|
Marshal.load(Marshal.dump(self))
|
172
172
|
end
|
173
173
|
end
|
174
|
+
|
175
|
+
# A mock socket
|
176
|
+
#
|
177
|
+
class Mocket
|
178
|
+
def puts(socket); end
|
179
|
+
|
180
|
+
def close; end
|
181
|
+
|
182
|
+
def ok?
|
183
|
+
true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# A mock socket which says things went wrong.
|
188
|
+
#
|
189
|
+
class BadMocket < Mocket
|
190
|
+
def ok?
|
191
|
+
false
|
192
|
+
end
|
193
|
+
end
|
@@ -61,6 +61,13 @@ class WavefrontDistributionTest < MiniTest::Test
|
|
61
61
|
'!M 1538865613 #5 11 #15 2.533 #8 -15 #12 1000000.0 ' \
|
62
62
|
"test.distribution source=#{Socket.gethostname} " \
|
63
63
|
'tag1="val1" tag2="val2"')
|
64
|
+
|
65
|
+
bad_dist = DIST.dup
|
66
|
+
bad_dist.delete(:interval)
|
67
|
+
|
68
|
+
assert_raises(Wavefront::Exception::InvalidDistribution) do
|
69
|
+
wf.hash_to_wf(bad_dist)
|
70
|
+
end
|
64
71
|
end
|
65
72
|
|
66
73
|
def test_array2dist
|
@@ -68,11 +75,3 @@ class WavefrontDistributionTest < MiniTest::Test
|
|
68
75
|
assert_equal(wf.array2dist([[12, 4.235]]), '#12 4.235')
|
69
76
|
end
|
70
77
|
end
|
71
|
-
|
72
|
-
# A mock socket
|
73
|
-
#
|
74
|
-
class Mocket
|
75
|
-
def puts(socket); end
|
76
|
-
|
77
|
-
def close; end
|
78
|
-
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'spy'
|
5
|
+
require 'spy/integration'
|
6
|
+
require_relative '../spec_helper'
|
7
|
+
require_relative '../../lib/wavefront-sdk/metric_helper'
|
8
|
+
|
9
|
+
ND_CREDS = { proxy: 'wavefront' }.freeze
|
10
|
+
WH_TAGS = { t1: 'v1', t2: 'v2' }.freeze
|
11
|
+
|
12
|
+
# Tests for the MetricHelper class.
|
13
|
+
#
|
14
|
+
# rubocop:disable Style/NumericLiterals
|
15
|
+
class WavefrontMetricHelperTest < MiniTest::Test
|
16
|
+
attr_reader :wf, :wfd
|
17
|
+
|
18
|
+
def setup
|
19
|
+
@wf = Wavefront::MetricHelper.new(ND_CREDS, {})
|
20
|
+
@wfd = Wavefront::MetricHelper.new(ND_CREDS, dist_port: 40000)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_gauge_1
|
24
|
+
wf.gauge('test.gauge', 123)
|
25
|
+
b = wf.buf
|
26
|
+
refute_empty(b[:gauges])
|
27
|
+
assert_empty(b[:counters])
|
28
|
+
assert_instance_of(Array, b[:gauges])
|
29
|
+
assert_equal(1, b[:gauges].size)
|
30
|
+
assert_equal(123, b[:gauges][0][:value])
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_gauge_tags
|
34
|
+
wf.gauge('test.gauge', 9.5, WH_TAGS)
|
35
|
+
b = wf.buf
|
36
|
+
refute_empty(b[:gauges])
|
37
|
+
assert_empty(b[:counters])
|
38
|
+
assert_instance_of(Array, b[:gauges])
|
39
|
+
assert_equal(1, b[:gauges].size)
|
40
|
+
assert_equal(9.5, b[:gauges][0][:value])
|
41
|
+
assert_equal(WH_TAGS, b[:gauges][0][:tags])
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_counter
|
45
|
+
wf.counter('test.counter')
|
46
|
+
wf.counter('test.counter')
|
47
|
+
wf.counter('test.counter', 2)
|
48
|
+
b = wf.buf
|
49
|
+
assert_empty(b[:gauges])
|
50
|
+
refute_empty(b[:counters])
|
51
|
+
assert_instance_of(Hash, b[:counters])
|
52
|
+
assert_equal(4, b[:counters][['test.counter', nil]])
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_counter_tags
|
56
|
+
wf.counter('test.counter')
|
57
|
+
wf.counter('test.counter', 1, WH_TAGS)
|
58
|
+
wf.counter('test.counter', 2)
|
59
|
+
wf.counter('test.counter', 3, WH_TAGS)
|
60
|
+
b = wf.buf
|
61
|
+
assert_empty(b[:gauges])
|
62
|
+
refute_empty(b[:counters])
|
63
|
+
assert_instance_of(Hash, b[:counters])
|
64
|
+
assert_equal(3, b[:counters][['test.counter', nil]])
|
65
|
+
assert_equal(4, b[:counters][['test.counter', WH_TAGS]])
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_dist_nodist
|
69
|
+
refute wf.buf.key?(:dists)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_dist
|
73
|
+
wfd.dist('test.dist', :m, 10)
|
74
|
+
wfd.dist('test.dist', :h, 456)
|
75
|
+
wfd.dist('test.dist', :h, 123, WH_TAGS)
|
76
|
+
wfd.dist('test.dist', :m, [10, 12, 13, 14])
|
77
|
+
b = wfd.buf
|
78
|
+
assert_empty(b[:gauges])
|
79
|
+
assert_empty(b[:counters])
|
80
|
+
refute_empty(b[:dists])
|
81
|
+
assert_equal(3, b[:dists].size)
|
82
|
+
assert_equal([10, 10, 12, 13, 14], b[:dists][['test.dist', :m, nil]])
|
83
|
+
assert_equal([456], b[:dists][['test.dist', :h, nil]])
|
84
|
+
assert_equal([123], b[:dists][['test.dist', :h, WH_TAGS]])
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_gauges_to_wf
|
88
|
+
input = [{ path: 'm1.p', ts: 1548636080, value: 0 },
|
89
|
+
{ path: 'm1.p', ts: 1548636081, value: 1 },
|
90
|
+
{ path: 'm2.p', ts: 1548636081, value: 9 }]
|
91
|
+
|
92
|
+
assert_equal(input, wf.gauges_to_wf(input))
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_counters_to_wf
|
96
|
+
input = { ['test.counter1', nil] => 7,
|
97
|
+
['test.counter1', WH_TAGS] => 8,
|
98
|
+
['test.counter2', nil] => 9 }
|
99
|
+
|
100
|
+
out = wf.counters_to_wf(input)
|
101
|
+
assert_instance_of(Array, out)
|
102
|
+
assert_equal(3, out.size)
|
103
|
+
out.each { |o| assert_instance_of(Hash, o) }
|
104
|
+
assert_equal('test.counter1', out.first[:path])
|
105
|
+
assert_equal(9, out.last[:value])
|
106
|
+
refute(out.first[:tags])
|
107
|
+
assert_equal(WH_TAGS, out[1][:tags])
|
108
|
+
assert_kind_of(Numeric, out[2][:ts])
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_dists_to_wf
|
112
|
+
input = { ['test.dist1', :m, nil] => [10, 10, 11, 12],
|
113
|
+
['test.dist1', :m, WH_TAGS] => [123, 456, 789],
|
114
|
+
['test.dist1', :h, nil] => [6, 6, 7, 4, 6, 4, 8] }
|
115
|
+
|
116
|
+
out = wfd.dists_to_wf(input)
|
117
|
+
assert_instance_of(Array, out)
|
118
|
+
assert_equal(3, out.size)
|
119
|
+
assert_equal(1, out.select do |o|
|
120
|
+
o[:value] == [[2, 10.0], [1, 11.0],
|
121
|
+
[1, 12.0]]
|
122
|
+
end .size)
|
123
|
+
assert_equal(1, out.select { |o| o[:tags] == WH_TAGS }.size)
|
124
|
+
assert_equal(3, out.select { |o| o[:path] == 'test.dist1' }.size)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_flush_gauges
|
128
|
+
assert_nil(wf.flush_gauges([]))
|
129
|
+
|
130
|
+
input = [{ path: 'm1.p', ts: 1548636080, value: 0 },
|
131
|
+
{ path: 'm1.p', ts: 1548636081, value: 1, tags: WH_TAGS },
|
132
|
+
{ path: 'm2.p', ts: 1548636081, value: 9 }]
|
133
|
+
|
134
|
+
mocket = Mocket.new
|
135
|
+
spy = Spy.on(wf.writer.writer, :write).and_return(mocket)
|
136
|
+
|
137
|
+
out = wf.flush_gauges(input)
|
138
|
+
args = spy.calls.first.args.first
|
139
|
+
assert_instance_of(Mocket, out)
|
140
|
+
assert spy.has_been_called?
|
141
|
+
assert_equal(input, args)
|
142
|
+
assert(args.any? { |a| a.key?(:tags) && a[:tags] == WH_TAGS })
|
143
|
+
refute(args.all? { |a| a.key?(:tags) })
|
144
|
+
assert_empty(wf.buf[:gauges])
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_flush_gauges_fail
|
148
|
+
input = [{ path: 'm1.p', ts: 1548636080, value: 0 }]
|
149
|
+
|
150
|
+
mocket = BadMocket.new
|
151
|
+
spy = Spy.on(wf.writer.writer, :write).and_return(mocket)
|
152
|
+
out = wf.flush_gauges(input)
|
153
|
+
assert_instance_of(BadMocket, out)
|
154
|
+
wf.gauge('m2.p', 9)
|
155
|
+
wf.gauge('m3.p', 9)
|
156
|
+
assert spy.has_been_called?
|
157
|
+
assert_equal(input, spy.calls.first.args.first)
|
158
|
+
assert_equal(3, wf.buf[:gauges].size)
|
159
|
+
assert_includes(wf.buf[:gauges],
|
160
|
+
path: 'm1.p', ts: 1548636080, value: 0)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_flush_counters
|
164
|
+
assert_nil(wf.flush_counters([]))
|
165
|
+
|
166
|
+
input = { ['test.counter1', nil] => 7,
|
167
|
+
['test.counter1', WH_TAGS] => 8,
|
168
|
+
['test.counter2', nil] => 9 }
|
169
|
+
|
170
|
+
mocket = Mocket.new
|
171
|
+
spy = Spy.on(wf.writer.writer, :write).and_return(mocket)
|
172
|
+
|
173
|
+
out = wf.flush_counters(input)
|
174
|
+
args = spy.calls.first.args.first
|
175
|
+
|
176
|
+
assert_instance_of(Mocket, out)
|
177
|
+
assert spy.has_been_called?
|
178
|
+
assert_equal(3, args.size)
|
179
|
+
|
180
|
+
args.each do |a|
|
181
|
+
assert_instance_of(Hash, a)
|
182
|
+
assert_includes(a.keys, :path)
|
183
|
+
assert_includes(a.keys, :ts)
|
184
|
+
assert_includes(a.keys, :value)
|
185
|
+
assert(a[:path].start_with?(DELTA))
|
186
|
+
end
|
187
|
+
|
188
|
+
assert(args.any? { |a| a.key?(:tags) && a[:tags] == WH_TAGS })
|
189
|
+
refute(args.all? { |a| a.key?(:tags) })
|
190
|
+
assert_empty(wf.buf[:counters])
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_flush_counters_fail
|
194
|
+
input = { ['test.counter1', nil] => 7,
|
195
|
+
['test.counter1', WH_TAGS] => 8,
|
196
|
+
['test.counter2', nil] => 9 }
|
197
|
+
|
198
|
+
mocket = BadMocket.new
|
199
|
+
spy = Spy.on(wf.writer.writer, :write).and_return(mocket)
|
200
|
+
|
201
|
+
out = wf.flush_counters(input)
|
202
|
+
args = spy.calls.first.args.first
|
203
|
+
|
204
|
+
assert_instance_of(BadMocket, out)
|
205
|
+
assert spy.has_been_called?
|
206
|
+
assert_equal(3, args.size)
|
207
|
+
|
208
|
+
wf.counter('test.counter1', 10)
|
209
|
+
wf.counter('test.counter1', 10)
|
210
|
+
wf.counter('test.counter2', 100)
|
211
|
+
|
212
|
+
assert(args.any? { |a| a.key?(:tags) && a[:tags] == WH_TAGS })
|
213
|
+
refute(args.all? { |a| a.key?(:tags) })
|
214
|
+
buf = wf.buf[:counters]
|
215
|
+
refute_empty(buf)
|
216
|
+
assert_equal(3, buf.size)
|
217
|
+
assert_equal(8, buf[['test.counter1', WH_TAGS]])
|
218
|
+
assert_equal(27, buf[['test.counter1', nil]])
|
219
|
+
assert_equal(109, buf[['test.counter2', nil]])
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_flush_dists
|
223
|
+
assert_nil(wfd.flush_dists([]))
|
224
|
+
|
225
|
+
input = { ['test.dist1', :m, nil] => [10, 10, 11, 12],
|
226
|
+
['test.dist1', :m, WH_TAGS] => [123, 456, 789],
|
227
|
+
['test.dist1', :h, nil] => [6, 6, 7, 4, 6, 4, 8] }
|
228
|
+
|
229
|
+
mocket = Mocket.new
|
230
|
+
spy = Spy.on(wfd.dist_writer.writer, :write).and_return(mocket)
|
231
|
+
|
232
|
+
out = wfd.flush_dists(input)
|
233
|
+
args = spy.calls.first.args.first
|
234
|
+
|
235
|
+
assert_instance_of(Mocket, out)
|
236
|
+
assert spy.has_been_called?
|
237
|
+
assert_equal(3, args.size)
|
238
|
+
|
239
|
+
args.each do |a|
|
240
|
+
assert_instance_of(Hash, a)
|
241
|
+
assert_includes(a.keys, :path)
|
242
|
+
assert_includes(a.keys, :ts)
|
243
|
+
assert_includes(a.keys, :value)
|
244
|
+
assert_instance_of(Array, a[:value])
|
245
|
+
assert_kind_of(Numeric, a[:ts])
|
246
|
+
end
|
247
|
+
|
248
|
+
assert(args.any? { |a| a.key?(:tags) && a[:tags] == WH_TAGS })
|
249
|
+
refute(args.all? { |a| a.key?(:tags) })
|
250
|
+
assert_empty(wfd.buf[:dists])
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_flush_dists_fail
|
254
|
+
input = { ['test.dist1', :m, nil] => [10, 10, 11, 12],
|
255
|
+
['test.dist1', :m, WH_TAGS] => [123, 456, 789],
|
256
|
+
['test.dist1', :h, nil] => [6, 6, 7, 4, 6, 4, 8] }
|
257
|
+
|
258
|
+
mocket = BadMocket.new
|
259
|
+
spy = Spy.on(wfd.dist_writer.writer, :write).and_return(mocket)
|
260
|
+
|
261
|
+
out = wfd.flush_dists(input)
|
262
|
+
args = spy.calls.first.args.first
|
263
|
+
|
264
|
+
assert_instance_of(BadMocket, out)
|
265
|
+
assert spy.has_been_called?
|
266
|
+
assert_equal(3, args.size)
|
267
|
+
refute_empty(wfd.buf[:dists])
|
268
|
+
assert_equal(input, wfd.buf[:dists])
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_dist_creds
|
272
|
+
opts = { verbose: true, dist_port: 40000 }
|
273
|
+
o = wfd.dist_creds(ND_CREDS, opts)
|
274
|
+
assert_equal(40000, o[:port])
|
275
|
+
assert_equal({ verbose: true, dist_port: 40000 }, opts)
|
276
|
+
assert_equal('wavefront', o[:proxy])
|
277
|
+
end
|
278
|
+
end
|
279
|
+
# rubocop:enable Style/NumericLiterals
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wavefront-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Fisher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -212,6 +212,7 @@ files:
|
|
212
212
|
- lib/wavefront-sdk/maintenancewindow.rb
|
213
213
|
- lib/wavefront-sdk/message.rb
|
214
214
|
- lib/wavefront-sdk/metric.rb
|
215
|
+
- lib/wavefront-sdk/metric_helper.rb
|
215
216
|
- lib/wavefront-sdk/notificant.rb
|
216
217
|
- lib/wavefront-sdk/paginator/base.rb
|
217
218
|
- lib/wavefront-sdk/paginator/delete.rb
|
@@ -258,6 +259,7 @@ files:
|
|
258
259
|
- spec/wavefront-sdk/integration_spec.rb
|
259
260
|
- spec/wavefront-sdk/maintenancewindow_spec.rb
|
260
261
|
- spec/wavefront-sdk/message_spec.rb
|
262
|
+
- spec/wavefront-sdk/metric_helper_spec.rb
|
261
263
|
- spec/wavefront-sdk/metric_spec.rb
|
262
264
|
- spec/wavefront-sdk/notificant_spec.rb
|
263
265
|
- spec/wavefront-sdk/paginator/base_spec.rb
|
@@ -327,6 +329,7 @@ test_files:
|
|
327
329
|
- spec/wavefront-sdk/integration_spec.rb
|
328
330
|
- spec/wavefront-sdk/maintenancewindow_spec.rb
|
329
331
|
- spec/wavefront-sdk/message_spec.rb
|
332
|
+
- spec/wavefront-sdk/metric_helper_spec.rb
|
330
333
|
- spec/wavefront-sdk/metric_spec.rb
|
331
334
|
- spec/wavefront-sdk/notificant_spec.rb
|
332
335
|
- spec/wavefront-sdk/paginator/base_spec.rb
|