wavefront-client 3.2.0 → 3.3.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 +8 -8
- data/.travis.yml +1 -0
- data/README-cli.md +108 -1
- data/bin/wavefront +49 -11
- data/lib/wavefront/batch_writer.rb +247 -0
- data/lib/wavefront/cli/alerts.rb +50 -27
- data/lib/wavefront/cli/batch_write.rb +227 -0
- data/lib/wavefront/cli/events.rb +1 -1
- data/lib/wavefront/cli/ts.rb +2 -2
- data/lib/wavefront/cli/write.rb +89 -0
- data/lib/wavefront/cli.rb +19 -13
- data/lib/wavefront/client/version.rb +1 -1
- data/lib/wavefront/constants.rb +3 -0
- data/lib/wavefront/events.rb +39 -18
- data/lib/wavefront/exception.rb +8 -1
- data/lib/wavefront/mixins.rb +9 -2
- data/lib/wavefront/writer.rb +7 -2
- data/spec/spec_helper.rb +52 -1
- data/spec/wavefront/batch_writer_spec.rb +523 -0
- data/spec/wavefront/cli/alerts_spec.rb +153 -0
- data/spec/wavefront/cli/batch_write_spec.rb +251 -0
- data/spec/wavefront/cli/events_spec.rb +43 -0
- data/spec/wavefront/cli/resources/alert.human.erb +14 -0
- data/spec/wavefront/cli/resources/alert.human2 +14 -0
- data/spec/wavefront/cli/resources/alert.json +38 -0
- data/spec/wavefront/cli/resources/alert.raw +1 -0
- data/spec/wavefront/cli/resources/alert.ruby +1 -0
- data/spec/wavefront/cli/resources/write.parabola +49 -0
- data/spec/wavefront/cli/write_spec.rb +112 -0
- data/spec/wavefront/cli_spec.rb +68 -0
- data/spec/wavefront/events_spec.rb +111 -0
- data/spec/wavefront/mixins_spec.rb +16 -1
- data/spec/wavefront/writer_spec.rb +0 -7
- data/wavefront-client.gemspec +1 -1
- metadata +35 -6
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDNiNGYxMWY3Y2NmNWMzM2YwY2YxNDczZDIxNGU0MGEyN2IwNDQ0MQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MWI3YTFiNTc2MWJlOWY3NWMyNDgwNDg1YjlkNWZiNTU0MjdhMGRkNg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NDUwYjRjOWE3MWU4OWUzZTkyN2NiMDhiZWE4ODQ1YWU5ZDA0MWM0Mjc2OWVm
|
10
|
+
NzMxYjFiMTMzMWRiMWMyMDVkOGJlN2FmZjMyNThhYWY0YzdkMzIzZTczYTcw
|
11
|
+
ODRkMjJhOWY4M2ZiM2I1NjVhNjBmNDJjMDA4ZmRhNzlhMWEzYzA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTUzNTMxMzg1OTIwYzdmYWUzMDNiOTZkOGM3NzI2NTA3OWFkM2E5YzBiOGRm
|
14
|
+
ODZiNjhiNzNhMjYzODZkMDgwZDJkMGZmNGM0NmQ0NjBmYTEzMWIzNGM1ZDFl
|
15
|
+
MTU4Njk1NjFkMWRiYjBhMWM1OWEwMjFiYjA3Yzk4OGRiOThiN2E=
|
data/.travis.yml
CHANGED
data/README-cli.md
CHANGED
@@ -12,7 +12,6 @@ The following options are valid in almost all contexts.
|
|
12
12
|
```
|
13
13
|
-c, --config=FILE path to configuration file [default: ~/.wavefront]
|
14
14
|
-P, --profile=NAME profile in configuration file [default: default]
|
15
|
-
-E, --endpoint=URI cluster endpoint [default: metrics.wavefront.com]
|
16
15
|
-t, --token=TOKEN Wavefront authentication token
|
17
16
|
-D, --debug enable debug mode
|
18
17
|
-h, --help show help for command
|
@@ -32,6 +31,8 @@ Usage:
|
|
32
31
|
[-X bool] <query>
|
33
32
|
|
34
33
|
Options:
|
34
|
+
-E, --endpoint=URI cluster endpoint [default:
|
35
|
+
metrics.wavefront.com]
|
35
36
|
-S, --seconds query granularity of seconds
|
36
37
|
-m, --minutes query granularity of minutes
|
37
38
|
-H, --hours query granularity of hours
|
@@ -109,6 +110,7 @@ Usage:
|
|
109
110
|
[-f format] [-p tag] [ -s tag] <state>
|
110
111
|
|
111
112
|
Options:
|
113
|
+
-E, --endpoint=URI cluster endpoint [default: metrics.wavefront.com]
|
112
114
|
-f, --format=STRING output format (ruby, json, human)
|
113
115
|
[default: human]
|
114
116
|
-p, --private=TAG retrieve only alerts with named private tags,
|
@@ -167,6 +169,7 @@ Usage:
|
|
167
169
|
wavefront event --help
|
168
170
|
|
169
171
|
Options:
|
172
|
+
-E, --endpoint=URI cluster endpoint [default: metrics.wavefront.com]
|
170
173
|
-i, --instant create an instantaneous event
|
171
174
|
-V, --verbose be verbose
|
172
175
|
-s, --start=TIME time at which event begins
|
@@ -238,6 +241,110 @@ Closing event 'puppet_run'. [2016-06-27 19:25:16 +0100]
|
|
238
241
|
Removing state file /var/tmp/wavefront/events/rob/1467051916712::puppet_run.
|
239
242
|
```
|
240
243
|
|
244
|
+
## `write` Mode: Sending Points to Wavefront
|
245
|
+
|
246
|
+
The `write` command is used to put data points into Wavefront. It is
|
247
|
+
different from other commands in that it communicates with a
|
248
|
+
**proxy** rather than with the Wavefront API. This means it does
|
249
|
+
not require any credentials.
|
250
|
+
|
251
|
+
```
|
252
|
+
Usage:
|
253
|
+
wavefront write point [-DV] [-c file] [-P profile] [-E proxy] [-t time]
|
254
|
+
[-p port] [-H host] [-n] [-T tag...] <metric> <value>
|
255
|
+
wavefront write file [-DV] [-c file] [-P profile] [-E proxy] [-H host]
|
256
|
+
[-p port] [-n] [-F format] [-m metric] [-T tag...] <file>
|
257
|
+
|
258
|
+
Options:
|
259
|
+
-E, --proxy=URI proxy endpoint [default: wavefront]
|
260
|
+
-t, --time=TIME time of data point (omit to use current time)
|
261
|
+
-H, --host=STRING source host [default: box]
|
262
|
+
-p, --port=INT Wavefront proxy port [default: 2878]
|
263
|
+
-T, --tag=TAG point tag in key=value form
|
264
|
+
-F, --format=STRING format of input file or stdin [default: tmv]
|
265
|
+
-n, --noop show the metric without sending it
|
266
|
+
-m, --metric=STRING the metric path to which contents of a file will be
|
267
|
+
assigned. If the file contains a metric name, the two
|
268
|
+
will be concatenated
|
269
|
+
-V, --verbose be verbose
|
270
|
+
```
|
271
|
+
|
272
|
+
`write` has two sub-commands: `write point` and `write file`. Both
|
273
|
+
allow you to specify the proxy address and port either with
|
274
|
+
command-line switches, or by the `proxy` and `port` values in your
|
275
|
+
`.wavefront` file.
|
276
|
+
|
277
|
+
### `write point`
|
278
|
+
|
279
|
+
This provides a very quick method of putting a point into Wavefront.
|
280
|
+
It takes two mandatory arguments: the metric path, and the metric
|
281
|
+
value.
|
282
|
+
|
283
|
+
You can optionally add point tags with multiple uses of `-T
|
284
|
+
key=val`, and specify a timestamp with the `-t` option.
|
285
|
+
|
286
|
+
### `write file`
|
287
|
+
|
288
|
+
`write file` takes a whitespace-separated file, and turns it into a
|
289
|
+
series of points, which it sends to a Wavefront proxy. Each line
|
290
|
+
will be mapped to a single point.
|
291
|
+
|
292
|
+
Each line in the file must be of the same format, and must contain a
|
293
|
+
value. It can optionally contain metric path, a timestamp, and point
|
294
|
+
tags. The format of the file is passed in with the `-F` option, and
|
295
|
+
it must contain only the letters `t` (timestamp), `m` (metric path),
|
296
|
+
`v` (value) and `T` (point tags). If `T` is used, it must come
|
297
|
+
last: this allows you to have as many point tags as you like, and
|
298
|
+
you do not have to have the same number for each point.
|
299
|
+
|
300
|
+
The metric can also be, to some extent, described by options. If you
|
301
|
+
do not have a metric path in the file, you can use `-m` to supply a
|
302
|
+
path to which every point will be assigned. If you use `-m` *and* a
|
303
|
+
field in the file, the two will be concatenated, with `-m` used as a
|
304
|
+
global prefix.
|
305
|
+
|
306
|
+
Similarly, a global timestamp can be supplied with `-t` (timestamps
|
307
|
+
in files must be in epoch seconds, but `-t` can be any `strptime()`
|
308
|
+
parseable string), and global point tags with one or more `-T
|
309
|
+
key=val`s. If you supply tags with `-T` and in the file, the points
|
310
|
+
will get both.
|
311
|
+
|
312
|
+
The input file does not have to be on disk: following the Unix
|
313
|
+
convention, you can use `-` as the filename, and `wavefront` will
|
314
|
+
read from standard in, converting lines to points as it receives
|
315
|
+
them. All the same rules apply as with standard files.
|
316
|
+
|
317
|
+
`wavefront write file` takes some efforts to protect the user from
|
318
|
+
sending bad data. It will not allow metrics with less than two
|
319
|
+
components, and it will not permit timestamps prior to 2000-01-01,
|
320
|
+
or more than a year in the future. It also checks that every
|
321
|
+
potential data point conforms to the limits described in the
|
322
|
+
Wavefront wire format documentation.
|
323
|
+
|
324
|
+
### Examples
|
325
|
+
|
326
|
+
Tell Wavefront that the value of `dev.myvalue` at this moment is
|
327
|
+
123.
|
328
|
+
|
329
|
+
```
|
330
|
+
$ wavefront write point dev.myvalue 123
|
331
|
+
```
|
332
|
+
|
333
|
+
Write a file of retrospective data, whwere the fields are, in order,
|
334
|
+
a timestamp, the metric path, and the value. Tag all points with
|
335
|
+
`mytag` set to `my value`.
|
336
|
+
|
337
|
+
```
|
338
|
+
$ wavefront write file -F tmvT -T mytag="my value" datafile
|
339
|
+
```
|
340
|
+
|
341
|
+
The command `parabola.rb` prints a timestamp and a 'y' value every
|
342
|
+
second. Plot the parabola in Wavefront.
|
343
|
+
|
344
|
+
```
|
345
|
+
$ parabola.rb | wavefront write file -F tv -m cli.demo.parabola -
|
346
|
+
```
|
347
|
+
|
241
348
|
## Notes on Options
|
242
349
|
|
243
350
|
### Times
|
data/bin/wavefront
CHANGED
@@ -18,11 +18,12 @@ require 'pathname'
|
|
18
18
|
require 'wavefront/client'
|
19
19
|
require 'wavefront/cli'
|
20
20
|
require 'docopt'
|
21
|
+
require 'socket'
|
21
22
|
include Wavefront::Constants
|
22
23
|
|
23
24
|
def sanitize_keys(hash)
|
24
25
|
hash.each_with_object({}) do |(k, v), aggr|
|
25
|
-
aggr[k.
|
26
|
+
aggr[k.delete('-').to_sym] = v
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
@@ -31,12 +32,10 @@ DEF_CF = Pathname.new(ENV['HOME']) + '.wavefront'
|
|
31
32
|
|
32
33
|
# The global_opts are available in every command.
|
33
34
|
#
|
34
|
-
global_opts = %
|
35
|
+
global_opts = %(
|
35
36
|
Global options:
|
36
37
|
-c, --config=FILE path to configuration file [default: #{DEF_CF}]
|
37
38
|
-P, --profile=NAME profile in configuration file [default: default]
|
38
|
-
-E, --endpoint=URI cluster endpoint [default: #{DEFAULT_HOST}]
|
39
|
-
-t, --token=TOKEN Wavefront authentication token
|
40
39
|
-D, --debug enable debug mode
|
41
40
|
-h, --help show this message
|
42
41
|
)
|
@@ -45,13 +44,15 @@ Global options:
|
|
45
44
|
# commands we offer. They must include the global_opts.
|
46
45
|
#
|
47
46
|
usage = {
|
48
|
-
ts: %
|
47
|
+
ts: %(
|
49
48
|
Usage:
|
50
49
|
#{ME} ts [-c file] [-P profile] [-E endpoint] [-t token] [-OD]
|
51
50
|
[-S | -m | -H | -d] [-s time] [-e time] [-f format] [-p num]
|
52
51
|
[-X bool] <query>
|
53
52
|
#{global_opts}
|
54
53
|
Options:
|
54
|
+
-E, --endpoint=URI cluster endpoint [default: #{DEFAULT_HOST}]
|
55
|
+
-t, --token=TOKEN Wavefront authentication token
|
55
56
|
-S, --seconds query granularity of seconds
|
56
57
|
-m, --minutes query granularity of minutes
|
57
58
|
-H, --hours query granularity of hours
|
@@ -69,12 +70,14 @@ Options:
|
|
69
70
|
-O, --includeObsoleteMetrics include metrics unreported for > 4 weeks
|
70
71
|
),
|
71
72
|
|
72
|
-
alerts: %
|
73
|
+
alerts: %(
|
73
74
|
Usage:
|
74
75
|
#{ME} alerts [-c file] [-P profile] [-E endpoint] [-t token]
|
75
76
|
[-f format] [-p tag] [ -s tag] <state>
|
76
77
|
#{global_opts}
|
77
78
|
Options:
|
79
|
+
-E, --endpoint=URI cluster endpoint [default: #{DEFAULT_HOST}]
|
80
|
+
-t, --token=TOKEN Wavefront authentication token
|
78
81
|
-f, --format=STRING output format (#{ALERT_FORMATS.join(', ')})
|
79
82
|
[default: #{DEFAULT_ALERT_FORMAT}]
|
80
83
|
-p, --private=TAG retrieve only alerts with named private tags,
|
@@ -83,10 +86,10 @@ Options:
|
|
83
86
|
delimited.
|
84
87
|
),
|
85
88
|
|
86
|
-
event: %
|
89
|
+
event: %(
|
87
90
|
Usage:
|
88
91
|
#{ME} event create [-V] [-c file] [-P profile] [-E endpoint] [-t token]
|
89
|
-
[-d description] [-s time] [-i | -e time] [-l level] [-
|
92
|
+
[-d description] [-s time] [-i | -e time] [-l level] [-T type]
|
90
93
|
[-H host] [-n] <event>
|
91
94
|
#{ME} event close [-V] [-c file] [-P profile] [-E endpoint] [-t token]
|
92
95
|
[<event>] [<timestamp>]
|
@@ -106,7 +109,33 @@ Options:
|
|
106
109
|
|
107
110
|
View events in detail using the 'ts' command with the 'events()' function.
|
108
111
|
),
|
109
|
-
|
112
|
+
|
113
|
+
write: %(
|
114
|
+
Usage:
|
115
|
+
#{ME} write point [-DV] [-c file] [-P profile] [-E proxy] [-t time]
|
116
|
+
[-p port] [-H host] [-n] [-T tag...] <metric> <value>
|
117
|
+
#{ME} write file [-DV] [-c file] [-P profile] [-E proxy] [-H host]
|
118
|
+
[-p port] [-n] [-F format] [-m metric] [-T tag...] <file>
|
119
|
+
#{ME} write --help
|
120
|
+
#{global_opts}
|
121
|
+
Options:
|
122
|
+
-E, --proxy=URI proxy endpoint [default: #{DEFAULT_PROXY}]
|
123
|
+
-t, --time=TIME time of data point (omit to use current time)
|
124
|
+
-H, --host=STRING source host [default: #{Socket.gethostname}]
|
125
|
+
-p, --port=INT Wavefront proxy port [default: #{DEFAULT_PROXY_PORT}]
|
126
|
+
-T, --tag=TAG point tag in key=value form
|
127
|
+
-F, --format=STRING format of input file or stdin [default: #{DEFAULT_INFILE_FORMAT}]
|
128
|
+
-n, --noop show the metric without sending it
|
129
|
+
-m, --metric=STRING the metric path to which contents of a file will be
|
130
|
+
assigned. If the file contains a metric name, the two
|
131
|
+
will be concatenated
|
132
|
+
-V, --verbose be verbose
|
133
|
+
|
134
|
+
Files are whitespace separated, and fields can be defined with the -F
|
135
|
+
option. Use 't' for timestamp; 'm' for metric name; 'v' for value
|
136
|
+
and 'T' for tags. Put 'T' last.
|
137
|
+
),
|
138
|
+
default: %(
|
110
139
|
Wavefront CLI
|
111
140
|
|
112
141
|
Usage:
|
@@ -118,6 +147,7 @@ Commands:
|
|
118
147
|
ts view timeseries data
|
119
148
|
alerts view alerts
|
120
149
|
event open and close events
|
150
|
+
write send data points to a Wavefront proxy
|
121
151
|
|
122
152
|
Use '#{ME} <command> --help' for further information.)
|
123
153
|
}
|
@@ -126,13 +156,13 @@ Use '#{ME} <command> --help' for further information.)
|
|
126
156
|
# help/option parser generation.
|
127
157
|
#
|
128
158
|
begin
|
129
|
-
opts = Docopt
|
159
|
+
opts = Docopt.docopt(usage[:default], version: '3.2.0')
|
130
160
|
rescue Docopt::Exit => e
|
131
161
|
cmd = ARGV.length > 0 ? ARGV.first.to_sym : nil
|
132
162
|
|
133
163
|
if usage.keys.include?(cmd)
|
134
164
|
begin
|
135
|
-
opts = sanitize_keys(Docopt
|
165
|
+
opts = sanitize_keys(Docopt.docopt(usage[cmd]))
|
136
166
|
rescue Docopt::Exit => e
|
137
167
|
abort e.message
|
138
168
|
end
|
@@ -156,6 +186,14 @@ when :event
|
|
156
186
|
when :alerts
|
157
187
|
require 'wavefront/cli/alerts'
|
158
188
|
cli = Wavefront::Cli::Alerts.new(opts, [opts[:'<state>']])
|
189
|
+
when :write
|
190
|
+
if opts[:file]
|
191
|
+
require 'wavefront/cli/batch_write'
|
192
|
+
cli = Wavefront::Cli::BatchWrite.new(opts, [opts[:'<state>']])
|
193
|
+
else
|
194
|
+
require 'wavefront/cli/write'
|
195
|
+
cli = Wavefront::Cli::Write.new(opts, [opts[:'<state>']])
|
196
|
+
end
|
159
197
|
end
|
160
198
|
|
161
199
|
begin
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'wavefront/client/version'
|
2
|
+
require 'wavefront/exception'
|
3
|
+
require 'wavefront/constants'
|
4
|
+
require 'uri'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
HOSTNAME = Socket.gethostname
|
8
|
+
|
9
|
+
module Wavefront
|
10
|
+
#
|
11
|
+
# This class exists to facilitate sending of multiple data points
|
12
|
+
# to a Wavefront proxy. It sends points in native Wavefront
|
13
|
+
# format.
|
14
|
+
#
|
15
|
+
# When initializing the instance you can
|
16
|
+
# define point tags which will apply to all points sent via that
|
17
|
+
# instance.
|
18
|
+
#
|
19
|
+
# Though we provide methods to do it, it is the developer's
|
20
|
+
# responsibility to open and close the socket to the proxy. Points
|
21
|
+
# are sent by calling the write() method.
|
22
|
+
#
|
23
|
+
# The class keeps a count of the points the current instance has
|
24
|
+
# sent, dropped, and failed to send, in @summary. The socket is accessed
|
25
|
+
# through the instance variable @sock.
|
26
|
+
#
|
27
|
+
class BatchWriter
|
28
|
+
attr_reader :sock, :opts, :summary
|
29
|
+
include Wavefront::Constants
|
30
|
+
|
31
|
+
def initialize(options = {})
|
32
|
+
#
|
33
|
+
# options is of the form:
|
34
|
+
#
|
35
|
+
# {
|
36
|
+
# tags: a key-value hash of tags which will be applied to
|
37
|
+
# every point
|
38
|
+
# proxy: the address of the Wavefront proxy
|
39
|
+
# port: the port of the Wavefront proxy
|
40
|
+
# noop: if this is true, no proxy connection will be made,
|
41
|
+
# and instead of sending the points, they will
|
42
|
+
# be printed in Wavefront wire format.
|
43
|
+
# novalidate: if this is true, points will not be validated.
|
44
|
+
# This might make things go marginally quicker
|
45
|
+
# if you have done point validation higher up in
|
46
|
+
# the chain.
|
47
|
+
# verbose: if this is true, many of the methods will report
|
48
|
+
# their progress.
|
49
|
+
# debug: if this is true, debugging output will be
|
50
|
+
# printed.
|
51
|
+
# }
|
52
|
+
#
|
53
|
+
defaults = {
|
54
|
+
tags: false,
|
55
|
+
proxy: DEFAULT_PROXY,
|
56
|
+
port: DEFAULT_PROXY_PORT,
|
57
|
+
noop: false,
|
58
|
+
novalidate: false,
|
59
|
+
verbose: false,
|
60
|
+
debug: false,
|
61
|
+
}
|
62
|
+
|
63
|
+
@summary = { sent: 0,
|
64
|
+
rejected: 0,
|
65
|
+
unsent: 0,
|
66
|
+
}
|
67
|
+
@opts = setup_options(options, defaults)
|
68
|
+
|
69
|
+
if opts[:tags]
|
70
|
+
valid_tags?(opts[:tags])
|
71
|
+
@global_tags = opts[:tags]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_options(user, defaults)
|
76
|
+
#
|
77
|
+
# Fill in some defaults, if the user hasn't supplied them
|
78
|
+
#
|
79
|
+
defaults.merge(user)
|
80
|
+
end
|
81
|
+
|
82
|
+
def write(points = [], options = {})
|
83
|
+
#
|
84
|
+
# Points are defined as hashes of the following form:
|
85
|
+
# {
|
86
|
+
# path: metrics path. String. Mandatory.
|
87
|
+
# value: value of metric. Numeric. Mandatory.
|
88
|
+
# ts: timestamp as a Time or Date object. default:
|
89
|
+
# Time.now. May be omitted or false.
|
90
|
+
# source: originating source of metric. default: `hostname`
|
91
|
+
# tags: optional hash of key: value point tags
|
92
|
+
# }
|
93
|
+
#
|
94
|
+
# Send multiple points by using an array of the above hashes.
|
95
|
+
#
|
96
|
+
unless points.is_a?(Hash) || points.is_a?(Array)
|
97
|
+
summary[:rejected] += 1
|
98
|
+
return false
|
99
|
+
end
|
100
|
+
|
101
|
+
points = [points] if points.is_a?(Hash)
|
102
|
+
|
103
|
+
points.each do |p|
|
104
|
+
p[:ts] = Time.at(p[:ts]) if p[:ts].is_a?(Integer)
|
105
|
+
begin
|
106
|
+
valid_point?(p)
|
107
|
+
rescue Wavefront::Exception::InvalidMetricName,
|
108
|
+
Wavefront::Exception::InvalidMetricValue,
|
109
|
+
Wavefront::Exception::InvalidTimestamp,
|
110
|
+
Wavefront::Exception::InvalidSource,
|
111
|
+
Wavefront::Exception::InvalidTag => e
|
112
|
+
puts 'Invalid point, skipping.' if opts[:verbose]
|
113
|
+
puts "Invalid point: #{p}. (#{e})" if opts[:debug]
|
114
|
+
summary[:rejected] += 1
|
115
|
+
next
|
116
|
+
end
|
117
|
+
|
118
|
+
send_point(hash_to_wf(p))
|
119
|
+
end
|
120
|
+
return summary[:rejected] == 0 ? true : false
|
121
|
+
end
|
122
|
+
|
123
|
+
def valid_point?(point)
|
124
|
+
#
|
125
|
+
# Validate a point so it conforms to the standard described in
|
126
|
+
# https://community.wavefront.com/docs/DOC-1031
|
127
|
+
#
|
128
|
+
return true if opts.key?(:novalidate) && opts[:novalidate]
|
129
|
+
valid_path?(point[:path])
|
130
|
+
valid_value?(point[:value])
|
131
|
+
valid_ts?(point[:ts]) if point[:ts]
|
132
|
+
valid_source?(point[:source])
|
133
|
+
valid_tags?(point[:tags]) if point[:tags] && point[:tags].length > 0
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
def valid_path?(path)
|
138
|
+
fail Wavefront::Exception::InvalidMetricName unless \
|
139
|
+
path.is_a?(String) && path.match(/^[a-z0-9\-_\.]+$/) &&
|
140
|
+
path.length < 1024
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def valid_value?(value)
|
145
|
+
fail Wavefront::Exception::InvalidMetricValue unless value.is_a?(Numeric)
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
def valid_ts?(ts)
|
150
|
+
unless ts.is_a?(Time) || ts.is_a?(Date)
|
151
|
+
fail Wavefront::Exception::InvalidTimestamp
|
152
|
+
end
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def valid_source?(path)
|
157
|
+
unless path.is_a?(String) && path.match(/^[a-z0-9\-_\.]+$/) &&
|
158
|
+
path.length < 1024
|
159
|
+
fail Wavefront::Exception::InvalidSource
|
160
|
+
end
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def valid_tags?(tags)
|
165
|
+
tags.each do |k, v|
|
166
|
+
fail Wavefront::Exception::InvalidTag unless (k.length +
|
167
|
+
v.length < 254) && k.match(/^[a-z0-9\-_\.]+$/)
|
168
|
+
end
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
def hash_to_wf(p)
|
173
|
+
#
|
174
|
+
# Convert the hash received by the write() method to a string
|
175
|
+
# conforming with that defined in
|
176
|
+
# https://community.wavefront.com/docs/DOC-1031
|
177
|
+
#
|
178
|
+
fail ArgumentError unless p.key?(:path) && p.key?(:value) &&
|
179
|
+
p.key?(:source)
|
180
|
+
|
181
|
+
m = [p[:path], p[:value]]
|
182
|
+
m.<< p[:ts].to_i.to_s if p.key?(:ts) && p[:ts]
|
183
|
+
m.<< 'source=' + p[:source]
|
184
|
+
m.<< tag_hash_to_str(p[:tags]) if p.key?(:tags) && p[:tags]
|
185
|
+
m.<< tag_hash_to_str(opts[:tags]) if opts[:tags]
|
186
|
+
m.join(' ')
|
187
|
+
end
|
188
|
+
|
189
|
+
def tag_hash_to_str(tags)
|
190
|
+
#
|
191
|
+
# Convert a hash of tags into a string of key="val" tags. The
|
192
|
+
# quoting is recommended in the WF wire-format guide. No tag
|
193
|
+
# validation is done here: we assume you used valid_tags()
|
194
|
+
#
|
195
|
+
return '' unless tags.is_a?(Hash)
|
196
|
+
tags.map { |k, v| "#{k}=\"#{v}\"" }.join(' ')
|
197
|
+
end
|
198
|
+
|
199
|
+
def send_point(point)
|
200
|
+
#
|
201
|
+
# Send a point, which should already be in Wavefront wire
|
202
|
+
# format.
|
203
|
+
#
|
204
|
+
if opts[:noop]
|
205
|
+
puts "Would send: #{point}"
|
206
|
+
return
|
207
|
+
end
|
208
|
+
|
209
|
+
puts "Sending: #{point}" if opts[:verbose] || opts[:debug]
|
210
|
+
|
211
|
+
begin
|
212
|
+
sock.puts(point)
|
213
|
+
summary[:sent] += 1
|
214
|
+
return true
|
215
|
+
rescue
|
216
|
+
summary[:unsent] += 1
|
217
|
+
puts 'WARNING: failed to send point.'
|
218
|
+
return false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def open_socket
|
223
|
+
#
|
224
|
+
# Open a socket to a Wavefront proxy, putting the descriptor
|
225
|
+
# in instance variable @sock.
|
226
|
+
#
|
227
|
+
if opts[:noop]
|
228
|
+
puts 'No-op requested. Not opening connection to proxy.'
|
229
|
+
return true
|
230
|
+
end
|
231
|
+
|
232
|
+
puts "Connecting to #{opts[:proxy]}:#{opts[:port]}." if opts[:verbose]
|
233
|
+
|
234
|
+
begin
|
235
|
+
@sock = TCPSocket.new(opts[:proxy], opts[:port])
|
236
|
+
rescue
|
237
|
+
raise Wavefront::Exception::InvalidEndpoint
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def close_socket
|
242
|
+
return if opts[:noop]
|
243
|
+
puts 'Closing connection to proxy.' if opts[:verbose]
|
244
|
+
sock.close
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|