tsdb_time_series 4.1.2
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 +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
|