tsdb_time_series 4.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +17 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +38 -0
- data/CONTRIBUTING.md +22 -0
- data/Gemfile +4 -0
- data/Guardfile +27 -0
- data/README.md +232 -0
- data/Rakefile +44 -0
- data/lib/time_series.rb +7 -0
- data/lib/time_series/metric.rb +56 -0
- data/lib/time_series/query.rb +170 -0
- data/lib/time_series/results/result.rb +40 -0
- data/lib/time_series/results/synthetic_result.rb +103 -0
- data/lib/time_series/ts_client.rb +169 -0
- data/lib/time_series/version.rb +9 -0
- data/spec/acceptance/lib/time_series/metric_spec.rb +27 -0
- data/spec/acceptance/lib/time_series/synthetic_result_spec.rb +27 -0
- data/spec/acceptance/lib/time_series/ts_client_spec.rb +146 -0
- data/spec/fixtures.rb +17 -0
- data/spec/fixtures/errors/no_metric.json +6 -0
- data/spec/fixtures/errors/no_tag_key.json +6 -0
- data/spec/fixtures/query/sys.numa.allocation.json +17 -0
- data/spec/fixtures/query/sys.numa.allocation.rate.json +17 -0
- data/spec/fixtures/query/sys.numa.zoneallocs.json +17 -0
- data/spec/fixtures/suggest/sys.json +1 -0
- data/spec/integration/lib/time_series/integration_spec.rb +129 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/lib/time_series/metric_spec.rb +48 -0
- data/spec/unit/lib/time_series/query_spec.rb +49 -0
- data/spec/unit/lib/time_series/synthetic_result_spec.rb +39 -0
- data/spec/unit/lib/time_series/ts_client_spec.rb +70 -0
- data/tsdb_time_series.gemspec +38 -0
- data/tsdb_time_series.reek +0 -0
- metadata +323 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OTY2MTQyZTM3YWMwYzc3YWZlOWQyNDk1ZTBhNWM5MGNjNzYzNmE2Zg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YmVkMjlhN2U1ODM5ODBmZGIzYzRkNDY5ZGViYjk1MWI5NGU5YWE2OQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzE5ZDk3OWNmMzMxZWYwOGFkNTM1YzA5OTdmNTg3NDI4MTNiNWE4NmYyNjIx
|
10
|
+
ZDZhNTc5ZDZhYjZiNTY4YzE4N2Q1NWI2MDg2NjE1ZmFhZjEwMmVmY2QyNjhm
|
11
|
+
ZmEwZmExNzU4MzgwMmU0N2E1ZjI4NjVmZWRlMDAwOWMyMDRlZTg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODNmOTdlODViODczNGQ1YzY1ZWEwMGM1NzQyNDExZjM1ODBhMGQ5OWNmNTQ2
|
14
|
+
NDRjNWVhYmUzZDUwZTAxMTg4NjhlMGQzZjY3MDQyNzAzN2YzZWY4Mzk5NTlj
|
15
|
+
NGQxZjBhMzQ0MjMzOWU5MzMxNzYxOGViMWRjOWNhMDUyMTdkYWM=
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.swp
|
19
|
+
*.swo
|
20
|
+
bin/
|
21
|
+
vendor/
|
22
|
+
.DS_Store
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
LineLength:
|
2
|
+
Enabled: true
|
3
|
+
Max: 128
|
4
|
+
|
5
|
+
Encoding:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
CaseIndentation:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# Annoying warning when dealing with Unix timestamps
|
12
|
+
NumericLiterals:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
# MethodLength is superseded by Reek's TooManyStatements smell-finder.
|
16
|
+
MethodLength:
|
17
|
+
Enabled: false
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3-p545
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# v4.1.2
|
2
|
+
- Renamed gem to `tsdb_time_series` for public use. (`time_series` is already taken)
|
3
|
+
- Cleaned up README.md a little bit
|
4
|
+
|
5
|
+
# v4.1.1
|
6
|
+
- Bumped Rubocop to `~> 0.28.0` and updated dependencies
|
7
|
+
- Fixed new Rubocop warnings
|
8
|
+
|
9
|
+
# v4.1.0
|
10
|
+
- Bumped RSpec to `~> 3.0`
|
11
|
+
- Updated tests to follow betterspecs.org guidelines
|
12
|
+
- Added integration tests using Docker
|
13
|
+
|
14
|
+
# v4.0.0
|
15
|
+
- Added initial support for synthetic metrics through formula calculations.
|
16
|
+
- Dropped OpenTSDB 1.1 support (includes dropping ASCII output support!)
|
17
|
+
- Dropped client-side validation support (done by OpenTSDB now)
|
18
|
+
|
19
|
+
# v3.0.0
|
20
|
+
- Updated response signatures to include status code, result count, and explicit error messages.
|
21
|
+
|
22
|
+
# v2.4.0
|
23
|
+
- Added multi-query support (persistent, pipelined HTTP requests)
|
24
|
+
|
25
|
+
# v2.3.0
|
26
|
+
- Deprecrated client-side validation for OpenTSDB 2.0 clients
|
27
|
+
|
28
|
+
# v2.2.0
|
29
|
+
- Switched to Excon from HTTParty
|
30
|
+
|
31
|
+
# v2.1.0
|
32
|
+
- Upgraded to Ruby 1.9.3
|
33
|
+
|
34
|
+
# v2.0.1
|
35
|
+
- Added proper rate support
|
36
|
+
|
37
|
+
# v2.0.0
|
38
|
+
- Initial OpenTSDB 2.0 support
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
## Contributing to TimeSeries
|
2
|
+
|
3
|
+
The best way to contribute code is to fork the main repo and send a pull request on GitHub.
|
4
|
+
|
5
|
+
Bug fixes should be done in the master branch. New features or major changes should be done in a feature branch. Alternatively, you can send a plain-text patch to the [mailing list](https://groups.google.com/forum/#!forum/opentsdb-clients).
|
6
|
+
|
7
|
+
Please break down your changes into as many small commits as possible.
|
8
|
+
|
9
|
+
Please respect the coding style of the code you're changing. TimeSeries uses Rubocop and reek to adhere to the Ruby style guide.
|
10
|
+
|
11
|
+
## Pull Request Requirements
|
12
|
+
|
13
|
+
*Before* sending a pull request, please make sure your changes meet the following criteria:
|
14
|
+
|
15
|
+
- You have run `bundle exec rake build` and your code:
|
16
|
+
- Maintains code coverage remains at 100%
|
17
|
+
- Has fully been fully documented (`yard` coverage at 100%)
|
18
|
+
- Has no `reek` warnings
|
19
|
+
- Has no `rubocop` warnings
|
20
|
+
- All RSpec tests pass
|
21
|
+
|
22
|
+
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# vim: ft=ruby
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
#
|
4
|
+
# More info also at https://github.com/guard/guard-rspec -- this one in
|
5
|
+
# particular details configuration options such as whether to run all tests
|
6
|
+
# after a failing test starts passing
|
7
|
+
|
8
|
+
guard :rspec, cli: '--tag ~slow' do
|
9
|
+
watch(/^spec\/.+_spec\.rb/)
|
10
|
+
watch(/^lib\/(.+)\.rb$/) do |match|
|
11
|
+
%w(unit integration acceptance).map do |kind|
|
12
|
+
"spec/#{kind}/lib/#{match[1]}_spec.rb"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
16
|
+
watch(%r{^spec/(fixtures|resources)(/|.rb)}) { 'spec' }
|
17
|
+
end
|
18
|
+
|
19
|
+
guard :rubocop, all_on_start: false do
|
20
|
+
watch('Guardfile')
|
21
|
+
watch(/.+\.rb$/)
|
22
|
+
watch(/(?:.+\/)?\.rubocop\.yml$/) { |m| File.dirname(m[0]) }
|
23
|
+
end
|
24
|
+
|
25
|
+
guard :reek do
|
26
|
+
watch(/^lib\/(.+)\.rb$/)
|
27
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
## tsdb_time_series
|
2
|
+
|
3
|
+
`tsdb_time_series` is a Ruby Gem for OpenTSDB that provides core tools when working with an OpenTSDB data store. With `tsdb_time_series`, you can search for registered metrics, tag keys and tag values, read from and write to the OpenTSDB, and submit multiple simultaneous queries to an OpenTSDB cluster.
|
4
|
+
|
5
|
+
### Installation
|
6
|
+
|
7
|
+
Download the Gem from a standard Gem server like rubygems.org and install it:
|
8
|
+
|
9
|
+
gem install tsdb_time_series
|
10
|
+
|
11
|
+
Alternatively, build it from source and install it:
|
12
|
+
|
13
|
+
git clone https://github.com/opower/time_series.git
|
14
|
+
cd time_series
|
15
|
+
gem build tsdb_time_series.gemspec
|
16
|
+
gem install tsdb_time_series-4.1.3.gem
|
17
|
+
|
18
|
+
### Usage
|
19
|
+
Once you have the OpenTSDB cluster set up, we can configure the TimeSeries Gem to talk to the API. The first step would be configuring a TimeSeries client. If no host is specified, the client connects to localhost by default. The client connects to port 4242 by default.
|
20
|
+
|
21
|
+
#### Configuring a TimeSeries Client
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
client = Opower::TimeSeries::TSClient.new('opentsdb.foo.com', 4242)
|
25
|
+
client.configure({ version: '2.0', dry_run: false, validation: true })
|
26
|
+
```
|
27
|
+
|
28
|
+
Here is a table that lists options supported by the TimeSeries client:
|
29
|
+
|
30
|
+
| Option | Type | Description| Default value |
|
31
|
+
| ------------- | ------------- | ------------- | ------------- |
|
32
|
+
| :version | Float | version of the OpentSDB cluster the client will be talking to. If you wish to use the new 2.0 endpoints, set version to 2.0 or higher. | 2.0 |
|
33
|
+
| :dry_run | Boolean | If set to true, this gem will not run any commands, only output the generated URLs or calls to OpenTSDB. | false |
|
34
|
+
| :validation | Boolean | With this flag set to true, client performs a check to validate the metric name. | false |
|
35
|
+
|
36
|
+
#### Search for a registered metric/tagk/tagv
|
37
|
+
|
38
|
+
Using a properly configured client, you can search an OpenTSDB cluster to find suggestions for a metric, tag key, or tag value. This employs the `/api/suggest` end point of the OpenTSDB API and works as a simple namespace search. It is useful when you do not know what metric labels are being written to the OpenTSDB.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
client.suggest('proc.stat.cpu') # suggest a metric
|
42
|
+
client.suggest('proc.stat.cpu', 'tagk') # suggest a tagk
|
43
|
+
client.suggest('proc.stat.cpu', 'tagv') # suggest a tagv
|
44
|
+
```
|
45
|
+
|
46
|
+
#### Writing to OpenTSDB
|
47
|
+
|
48
|
+
You can use a TimeSeries client to push telnet/netcat style writes to OpenTSDB. If no hostname and port are specified, this gem defaults to 127.0.0.1:4242. To insert a metric into OpenTSDB using a configured client, create a new `Metric` object first and then use the `client.write` call as shown below :
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
metric_config = {
|
52
|
+
name: 'proc.stat.cpu',
|
53
|
+
timestamp: Time.now.to_i,
|
54
|
+
value: 10,
|
55
|
+
tags: { host: 'somehost.foo.com', type: 'iowait' }
|
56
|
+
}
|
57
|
+
|
58
|
+
metric = Opower::TimeSeries::Metric.new(metric_config)
|
59
|
+
client.write(metric)
|
60
|
+
```
|
61
|
+
|
62
|
+
|
63
|
+
#### Reading from OpenTSDB
|
64
|
+
|
65
|
+
We can use a TimeSeries client to read metric data from an OpenTSDB cluster. To read data from OpenTSDB, you would first create a query object to run against the specified client. This query object supports all the standard options in the 2.0 API. Here is an example :
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
query_config = {
|
69
|
+
format: :png,
|
70
|
+
start: '2013/01/01-01:00:00',
|
71
|
+
end: '2013/02/01-01:00:00',
|
72
|
+
m: [{ aggregator: 'sum', metric: 'proc.stat.cpu', tags: { type: 'iowait' } }],
|
73
|
+
nocache: true
|
74
|
+
}
|
75
|
+
|
76
|
+
query = Opower::TimeSeries::Query.new(query_config)
|
77
|
+
client.run_query(query)
|
78
|
+
```
|
79
|
+
|
80
|
+
The `Query` object accepts the following parameters:
|
81
|
+
|
82
|
+
|
83
|
+
| Option | Type | Description| Default value |
|
84
|
+
| ------------- | ------------- | ------------- | ------------- |
|
85
|
+
| :format | String | Specifies the output format. supported values include : `ascii`, `json`, `png`. | 'json' |
|
86
|
+
| :start | `String` / `Integer` / `DateTime` | The query's start date/time expressed as '2013/01/01-01:00:00' (string), '5m-ago' (String, indicating data for last 5 minutes), 1232323232 (time since epoch, Integer) or as a Ruby DateTime object. This is a required field. | none |
|
87
|
+
| :end | `String` / `Integer` / `DateTime` | The query's end date. This field supports the same types as `:start` field. This field is optional | Time.now (current time) |
|
88
|
+
| :m | `Array` | Array of JSON objects with the `aggregator`, `metrics`, and `tags` as fields: | none |
|
89
|
+
|
90
|
+
Here is a sample metrics object , that goes into the :m object .
|
91
|
+
```ruby
|
92
|
+
m: [{ aggregator: 'sum', metric: 'proc.stat.cpu', tags: { type: 'iowait', version: 2.1 } }]
|
93
|
+
```
|
94
|
+
|
95
|
+
Other options available to the REST API can be used here as well. Here is a list of options that have been tested to work with this gem. See the [OpenTSDB documentation](http://opentsdb.net/http-api.html#/q_Parameters) for more information :
|
96
|
+
|
97
|
+
```
|
98
|
+
|
99
|
+
# * o Rendering options.
|
100
|
+
# * wxh The dimensions of the graph.
|
101
|
+
# * yrange The range of the left Y axis.
|
102
|
+
# * y2range The range of the right Y axis.
|
103
|
+
# * ylabel Label for the left Y axis.
|
104
|
+
# * y2label Label for the right Y axis.
|
105
|
+
# * yformat Format string for the left Y axis.
|
106
|
+
# * y2formatFormat string for the right Y axis.
|
107
|
+
# * ylog Enables log scale for the left Y axis.
|
108
|
+
# * y2log Enables log scale for the right Y axis.
|
109
|
+
# * key Options for the key (legend) of the graph.
|
110
|
+
# * nokey Removes the key (legend) from the graph.
|
111
|
+
# * nocache Forces TSD to ignore cache and fetch results from HBase.
|
112
|
+
|
113
|
+
```
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
#### Example Queries
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
query_config = {
|
121
|
+
format: :ascii,
|
122
|
+
start: 14535353,
|
123
|
+
end: 16786786,
|
124
|
+
m: [{ aggregator: 'sum', metric: 'proc.stat.cpu', rate: true, tags: { type: 'iowait' } }]
|
125
|
+
}
|
126
|
+
|
127
|
+
query = Opower::TimeSeries::Query.new(query_config)
|
128
|
+
client.run_query(query)
|
129
|
+
```
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
query_config = {
|
133
|
+
format: :json,
|
134
|
+
start: '3m-ago',
|
135
|
+
m: [{ aggregator: 'max', metric: 'proc.stat.cpu', tags: { type: 'iowait' } }],
|
136
|
+
nocache: true
|
137
|
+
}
|
138
|
+
|
139
|
+
query = Opower::TimeSeries::Query.new(query_config)
|
140
|
+
client.run_query(query)
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Running Multiple Queries Simultaneously
|
144
|
+
|
145
|
+
If you need to query multiple metrics at the same time, TimeSeries provides support for that as well:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
queries = []
|
149
|
+
3.times do
|
150
|
+
query_config = {
|
151
|
+
format: :ascii,
|
152
|
+
start: 14535353,
|
153
|
+
end: 16786786,
|
154
|
+
m: [{ aggregator: 'sum', metric: 'proc.stat.cpu', rate: true, tags: { type: 'iowait' } }]
|
155
|
+
}
|
156
|
+
|
157
|
+
queries << Opower::TimeSeries::Query.new(query_config)
|
158
|
+
end
|
159
|
+
|
160
|
+
client.run_queries(queries)
|
161
|
+
```
|
162
|
+
|
163
|
+
#### Running Synthetic Metric Queries
|
164
|
+
|
165
|
+
Sometimes, you might need to create a new time series using metrics data from existing time series. We call these 'Synthetic Metric Queries'. Some examples could be disk utilization (expressed as disk used/total disk available) or CPU itilization (expressed as cpu cycles used/total cpu cycles).
|
166
|
+
|
167
|
+
TimeSeries also provides the capability to create synthetic metric queries through the use of a formula and any number of queries against OpenTSDB. Here is an example that creates a formula which adds two time series ( `x + y` ) and feeds the calculation with data from OpenTSDB :
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
metric_x = [{ metric: 'sys.numa.allocation', tags: { host: 'somehost.foo.com' } }]
|
171
|
+
query_config_x = { format: :json, start: '1h-ago', m: metric_x }
|
172
|
+
@query_metric_x = Opower::TimeSeries::Query.new(query_config_x)
|
173
|
+
|
174
|
+
metric_y = [{ metric: 'sys.numa.foreign_allocs', tags: { host: 'somehost.foo.com' } }]
|
175
|
+
query_config_y = { format: :json, start: '1h-ago', m: metric_y }
|
176
|
+
@query_metric_y = Opower::TimeSeries::Query.new(query_config_y)
|
177
|
+
|
178
|
+
name = 'My Synthetic Metric Alias'
|
179
|
+
formula = 'x + y'
|
180
|
+
query_hash = { x: @query_metric_x, y: @query_metric_y }
|
181
|
+
client.run_synthetic_query(name, formula, query_hash)
|
182
|
+
```
|
183
|
+
|
184
|
+
The above example illustrates how you pass in a hash object to the client in order to run a sythentic query. This also indicates how the key maps to the parameters in the formula, with their corresponding values consisting of a Query object. When the calculation is performed, it will only operate on matching timestamps. If there are no matching data-points, it will return nothing.
|
185
|
+
|
186
|
+
For more information about what can be done with the formula parameters, read the documentation for the [Dentaku Calculator](https://github.com/rubysolo/dentaku). This gem expects any parameter in the formula to have a matching query in the query hash.
|
187
|
+
|
188
|
+
##### Built-in Ruby Math support
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
name = 'My Synthetic Metric Alias'
|
192
|
+
formula = 'cos(x) + y'
|
193
|
+
query_hash = { x: @query_metric_x, y: @query_metric_y }
|
194
|
+
client.run_synthetic_query(name, formula, query_hash)
|
195
|
+
```
|
196
|
+
|
197
|
+
Formulas in time-series can use all of the basic methods provided by the Math module from Ruby.
|
198
|
+
|
199
|
+
You must wrap nested mathematical expressions in formulas or Dentaku will attempt to pass them as separate arguments into the lambda below!
|
200
|
+
|
201
|
+
For example:
|
202
|
+
Assume x = 1, y = 2
|
203
|
+
- cos(x + y) is translated into cos(1, 'add', 2) - this calls Math.cos(1, 'add', 2) - this obviously throws an error
|
204
|
+
- cos((x + y)) is translated into cos(3) - this correctly calls Math.cos(3)
|
205
|
+
|
206
|
+
This is due to the way Dentaku handles the order of precedence; unless you wrap nested arguments, it will pass them separately.
|
207
|
+
|
208
|
+
#### Testing time_series
|
209
|
+
|
210
|
+
Test cases should be added for any new code added to this project.
|
211
|
+
|
212
|
+
Run acceptance/unit tests locally:
|
213
|
+
|
214
|
+
```
|
215
|
+
rake spec
|
216
|
+
```
|
217
|
+
|
218
|
+
Running integration tests:
|
219
|
+
```
|
220
|
+
docker pull opower/opentsdb
|
221
|
+
rake integration
|
222
|
+
```
|
223
|
+
|
224
|
+
Integration tests requires you have a `Docker` installed and have ran `docker pull opower/opentsdb` before-hand.
|
225
|
+
|
226
|
+
#### Generating Documentation
|
227
|
+
|
228
|
+
To generate the documentation for this gem, run the following:
|
229
|
+
|
230
|
+
```
|
231
|
+
yard doc
|
232
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# rubocop: disable LeadingCommentSpace
|
2
|
+
#! /usr/bin/env rake
|
3
|
+
# rubocop: enable LeadingCommentSpace
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
require 'yard'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'reek/rake/task'
|
8
|
+
require 'rubocop/rake_task'
|
9
|
+
|
10
|
+
task default: :build
|
11
|
+
|
12
|
+
# If there are test failures, you'll need to write code to address them.
|
13
|
+
# So no point in continuing to run the style tests.
|
14
|
+
desc 'Runs unit/acceptance tests'
|
15
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
16
|
+
task.pattern = 'spec/acceptance/**/*.rb,spec/unit/**/*.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'Runs integration tests'
|
20
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
21
|
+
task.pattern = 'spec/integration/**/*.rb'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Runs yard'
|
25
|
+
YARD::Rake::YardocTask.new(:yard)
|
26
|
+
|
27
|
+
desc 'smells the lib directory, which Reek defaults to anyway'
|
28
|
+
Reek::Rake::Task.new(:reek) do |task|
|
29
|
+
task.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'smells the spec directory, which is less important than lib'
|
33
|
+
Reek::Rake::Task.new(:reek_tests) do |task|
|
34
|
+
task.source_files = 'spec/**/*.rb'
|
35
|
+
task.verbose = true
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'runs Rubocop'
|
39
|
+
RuboCop::RakeTask.new
|
40
|
+
|
41
|
+
desc 'Runs test and code cleanliness suite: Rubocop, Reek, rspec, and yard'
|
42
|
+
task run_guards: [:spec, :yard, :reek, :reek_tests, :rubocop]
|
43
|
+
|
44
|
+
task build: :run_guards
|
data/lib/time_series.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Opower
|
4
|
+
module TimeSeries
|
5
|
+
# Represents a metric that can be inserted into OpenTSDB instance through a [TSDBClient] object.
|
6
|
+
class Metric
|
7
|
+
attr_reader :name, :value, :timestamp, :tags
|
8
|
+
|
9
|
+
# Initializer for the Metric class.
|
10
|
+
#
|
11
|
+
# @param [Hash] config configuration hash consisting of the following values:
|
12
|
+
# @option config [String] :name The metric name (required)
|
13
|
+
# @option config [String] :value The metric value (required)
|
14
|
+
# @option config [String, Integer, Timestamp] :timestamp The timestamp in either epoch or a TimeStamp object.
|
15
|
+
# @option config [Array] :tags Array of tags to set for this metric. (tag_key => value)
|
16
|
+
#
|
17
|
+
# @return [Metric] a new Metric object
|
18
|
+
def initialize(config = {})
|
19
|
+
validate(config, [:name, :value])
|
20
|
+
|
21
|
+
@name = config[:name]
|
22
|
+
@value = config[:value]
|
23
|
+
@timestamp = config[:timestamp] || Time.now.to_i
|
24
|
+
@tags = config[:tags] || {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Converts the metric into the format required for use by `put` to insert into OpenTSDB.
|
28
|
+
#
|
29
|
+
# @return [String] put string
|
30
|
+
def to_s
|
31
|
+
result = ''
|
32
|
+
# Format the string for OpenTSDB
|
33
|
+
@tags.each { |key, value| result += "#{key}=#{value} " }
|
34
|
+
[@name, @timestamp, @value, result.rstrip].join(' ')
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Validates the metric inputs
|
40
|
+
#
|
41
|
+
# @param [Hash] config The configuration to validate.
|
42
|
+
# @param [Array] required_fields The required fields to be set inside the configuration.
|
43
|
+
def validate(config = {}, required_fields)
|
44
|
+
# Required fields check
|
45
|
+
required_fields.each do |field|
|
46
|
+
next if config.include?(field)
|
47
|
+
fail(ArgumentError, "#{field} is required to write into OpenTSDB.")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Reject if user provided timestamp as not numeric
|
51
|
+
timestamp = config[:timestamp]
|
52
|
+
fail(ArgumentError, 'Timestamp must be numeric') if timestamp && !(timestamp.is_a? Fixnum)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|