influxdb 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91c31bce05c5e0a514a22cef9375f6f51e1f7e3d
4
- data.tar.gz: 842b0127d866fb9ed3a3cf0e7d3b878c6d1c5d01
3
+ metadata.gz: a1cd5af0d4500c96303b8c3c336926772eefedde
4
+ data.tar.gz: f5b17bce835b6973d763a0b0faad0d1a4882beb1
5
5
  SHA512:
6
- metadata.gz: c3f979934171092ad2c2b3c5ff6041cd40663e55d87eaedc8473951097bb1f28d2089acf3448a8dda86e25e521f7ed606314eeb0a9399492a9427c35f39aaebf
7
- data.tar.gz: 71d9c02ef46b61c64b6357e2df5886f1cc68517cbdf76da11104223535cb76dc88b73ffa671ad5a83d5afb344c99621c7b46df9d4462461364808f1f7c39810a
6
+ metadata.gz: a9a1e9d0df4907d754ab2fe0b7898b5852a0f9541f2a36ac12d0c2d6e0701406b88ff7d58461ead70b4c6833dd3bffc0c6048c3003911b3788ab18e9878101a1
7
+ data.tar.gz: 6d6703b9f341b8d1bb791a4548172d588165d537896b122c8d4fc6f902ad88b97d872fb15c1e078ddb36a3ec1341e7c9d3113b54d082659a295f5f803887d5c9
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - 2.2.0
8
+ - 2.3.0
8
9
  - ruby-head
9
10
  - jruby-20mode
10
11
  - jruby-21mode
11
- - jruby-head
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  influxdb-ruby
2
2
  =============
3
3
 
4
- [![Build Status](https://travis-ci.org/influxdb/influxdb-ruby.png?branch=master)](https://travis-ci.org/influxdb/influxdb-ruby)
4
+ [![Build Status](https://travis-ci.org/influxdata/influxdb-ruby.svg?branch=master)](https://travis-ci.org/influxdata/influxdb-ruby)
5
5
 
6
- The official ruby client library for [InfluxDB](https://influxdb.com/).
6
+ The official ruby client library for [InfluxDB](https://influxdata.com/time-series-platform/influxdb/). Maintained by [@toddboom](https://github.com/toddboom).
7
7
 
8
8
  > **Support for InfluxDB v0.8.x is now deprecated**. The final version of this library that will support the older InfluxDB interface is `v0.1.9`, which is available as a gem and tagged on this repository. If you're reading this message, then you should only expect support for InfluxDB v0.9.1 and higher.
9
9
 
@@ -292,7 +292,7 @@ Write multiple points in a batch (performance boost):
292
292
  data = [
293
293
  {
294
294
  series: 'cpu',
295
- tags: { host: 'server_1', regios: 'us' },
295
+ tags: { host: 'server_1', region: 'us' },
296
296
  values: {internal: 5, external: 0.453345}
297
297
  },
298
298
  {
@@ -317,7 +317,7 @@ Write multiple points in a batch with a specific retention policy:
317
317
  data = [
318
318
  {
319
319
  series: 'cpu',
320
- tags: { host: 'server_1', regios: 'us' },
320
+ tags: { host: 'server_1', region: 'us' },
321
321
  values: {internal: 5, external: 0.453345}
322
322
  },
323
323
  {
@@ -477,7 +477,7 @@ Testing
477
477
  -------
478
478
 
479
479
  ```
480
- git clone git@github.com:influxdb/influxdb-ruby.git
480
+ git clone git@github.com:influxdata/influxdb-ruby.git
481
481
  cd influxdb-ruby
482
482
  bundle
483
483
  bundle exec rake
@@ -19,7 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_runtime_dependency "json"
22
- spec.add_runtime_dependency "cause"
22
+
23
+ if RUBY_VERSION < '2.1'
24
+ spec.add_runtime_dependency "cause"
25
+ end
23
26
 
24
27
  spec.add_development_dependency "bundler", "~> 1.3"
25
28
  spec.add_development_dependency "rake"
@@ -1,5 +1,6 @@
1
1
  require 'json'
2
- require 'cause'
2
+ require 'cause' if RUBY_VERSION < '2.1'
3
+ require 'thread'
3
4
 
4
5
  module InfluxDB
5
6
  # rubocop:disable Metrics/MethodLength
@@ -37,12 +37,11 @@ module InfluxDB
37
37
  private
38
38
 
39
39
  def connect_with_retry(&block)
40
- hosts = config.hosts.dup
40
+ host = config.next_host
41
41
  delay = config.initial_delay
42
42
  retry_count = 0
43
43
 
44
44
  begin
45
- hosts.push(host = hosts.shift)
46
45
  http = Net::HTTP.new(host, config.port)
47
46
  http.open_timeout = config.open_timeout
48
47
  http.read_timeout = config.read_timeout
@@ -1,10 +1,11 @@
1
+ require 'thread'
2
+
1
3
  module InfluxDB
2
4
  # InfluxDB client configuration
3
5
  class Config
4
6
  AUTH_METHODS = %w(params basic_auth)
5
7
 
6
- attr_accessor :hosts,
7
- :port,
8
+ attr_accessor :port,
8
9
  :username,
9
10
  :password,
10
11
  :database,
@@ -27,7 +28,13 @@ module InfluxDB
27
28
  # rubocop:disable all
28
29
  def initialize(opts = {})
29
30
  @database = opts[:database]
30
- @hosts = Array(opts[:hosts] || opts[:host] || ["localhost"])
31
+ @hosts_queue = Queue.new
32
+
33
+ # load the hosts into a Queue for thread safety
34
+ Array(opts[:hosts] || opts[:host] || ["localhost"]).each do |host|
35
+ @hosts_queue.push(host)
36
+ end
37
+
31
38
  @port = opts.fetch(:port, 8086)
32
39
  @prefix = opts.fetch(:prefix, '')
33
40
  @username = opts.fetch(:username, "root")
@@ -64,5 +71,19 @@ module InfluxDB
64
71
  def async?
65
72
  !!async
66
73
  end
74
+
75
+ def next_host
76
+ host = @hosts_queue.pop
77
+ @hosts_queue.push(host)
78
+ host
79
+ end
80
+
81
+ def hosts
82
+ Array.new(@hosts_queue.length) do
83
+ host = @hosts_queue.pop
84
+ @hosts_queue.push(host)
85
+ host
86
+ end
87
+ end
67
88
  end
68
89
  end
@@ -4,9 +4,24 @@ module InfluxDB
4
4
  attr_reader :series, :values, :tags, :timestamp
5
5
 
6
6
  def initialize(data)
7
- @series = data[:series].gsub(/\s/, '\ ').gsub(',', '\,')
8
- @values = data_to_string(data[:values], true)
9
- @tags = data_to_string(data[:tags])
7
+ @series = escape(data[:series], :measurement)
8
+
9
+ @values = data[:values].map{|k, v|
10
+ key = escape(k.to_s, :field_key)
11
+ val = if v.is_a?(String)
12
+ '"' + escape(v, :field_value) + '"'
13
+ else
14
+ v.to_s
15
+ end
16
+ "#{key}=#{val}"
17
+ }.join(',') if data[:values]
18
+
19
+ @tags = data[:tags].map{|k, v|
20
+ key = escape(k.to_s, :tag_key)
21
+ val = escape(v.to_s, :tag_value)
22
+ "#{key}=#{val}"
23
+ }.join(',') if data[:tags]
24
+
10
25
  @timestamp = data[:timestamp]
11
26
  end
12
27
 
@@ -20,31 +35,28 @@ module InfluxDB
20
35
 
21
36
  private
22
37
 
23
- def data_to_string(data, quote_escape = false)
24
- return nil unless data && !data.empty?
25
- mappings = map(data, quote_escape)
26
- mappings.join(',')
38
+ ESCAPES = {
39
+ measurement: [' ', ','],
40
+ tag_key: ['=', ' ', ','],
41
+ tag_value: ['=', ' ', ','],
42
+ field_key: ['=', ' ', ',', '"'],
43
+ field_value: ['"'],
44
+ }
45
+
46
+ def escape(s, type)
47
+ ESCAPES[type].each do |ch|
48
+ s = s.gsub(ch){ "\\#{ch}" }
49
+ end
50
+ s
27
51
  end
28
52
 
29
53
  def map(data, quote_escape)
30
54
  data.map do |k, v|
31
55
  key = escape_key(k)
32
56
  val = v.is_a?(String) ? escape_value(v, quote_escape) : v
57
+ val = val.is_a?(Integer) ? "#{val}i" : v
33
58
  "#{key}=#{val}"
34
59
  end
35
60
  end
36
-
37
- def escape_value(value, quote_escape)
38
- val = value.
39
- gsub(/\s/, '\ ').
40
- gsub(',', '\,').
41
- gsub('"', '\"')
42
- val = %("#{val}") if quote_escape
43
- val
44
- end
45
-
46
- def escape_key(key)
47
- key.to_s.gsub(/\s/, '\ ').gsub(',', '\,')
48
- end
49
61
  end
50
62
  end
@@ -6,6 +6,11 @@ module InfluxDB
6
6
  get "/ping"
7
7
  end
8
8
 
9
+ def version
10
+ resp = get "/ping"
11
+ resp.header['x-influxdb-version']
12
+ end
13
+
9
14
  # rubocop:disable Metrics/MethodLength
10
15
  def query(query, opts = {})
11
16
  denormalize = opts.fetch(:denormalize, config.denormalize)
@@ -78,9 +83,9 @@ module InfluxDB
78
83
  end
79
84
 
80
85
  def fetch_series(response)
81
- response.fetch('results', [])
82
- .fetch(0, {})
83
- .fetch('series', [])
86
+ response.fetch('results', []).flat_map{|result|
87
+ result.fetch('series', [])
88
+ }
84
89
  end
85
90
 
86
91
  def generate_payload(data)
@@ -1,3 +1,3 @@
1
1
  module InfluxDB # :nodoc:
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -179,4 +179,105 @@ describe InfluxDB::Client do
179
179
  end
180
180
  end
181
181
  end
182
+
183
+ describe "multiple select queries" do
184
+ context "with single series with multiple points" do
185
+ let(:response) do
186
+ { "results" => [{ "series" => [{ "name" => "cpu", "tags" => { "region" => "us" },
187
+ "columns" => %w(time temp value),
188
+ "values" => [["2015-07-07T14:58:37Z", 92, 0.3445], ["2015-07-07T14:59:09Z", 68, 0.8787]] }] },
189
+ { "series" => [{ "name" => "memory", "tags" => { "region" => "us" },
190
+ "columns" => %w(time free total),
191
+ "values" => [["2015-07-07T14:58:37Z", 96468992, 134217728], ["2015-07-07T14:59:09Z", 71303168, 134217728]] }] }] }
192
+ end
193
+ let(:expected_result) do
194
+ [{ "name" => "cpu", "tags" => { "region" => "us" },
195
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "temp" => 92, "value" => 0.3445 },
196
+ { "time" => "2015-07-07T14:59:09Z", "temp" => 68, "value" => 0.8787 }] },
197
+ { "name" => "memory", "tags" => { "region" => "us" },
198
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "free" => 92*2**20, "total" => 128*2**20 },
199
+ { "time" => "2015-07-07T14:59:09Z", "free" => 68*2**20, "total" => 128*2**20 }] }]
200
+ end
201
+ let(:query) { 'SELECT * FROM cpu; SELECT * FROM memory' }
202
+
203
+ before do
204
+ stub_request(:get, "http://influxdb.test:9999/query").with(
205
+ query: { q: query, u: "username", p: "password", precision: 's', db: database }
206
+ ).to_return(body: JSON.generate(response))
207
+ end
208
+
209
+ it "should return array with single hash containing multiple values" do
210
+ expect(subject.query(query)).to eq(expected_result)
211
+ end
212
+ end
213
+
214
+ context "with series with different tags" do
215
+ let(:response) do
216
+ { "results" => [{ "series" => [{ "name" => "cpu", "tags" => { "region" => "pl" }, "columns" => %w(time temp value), "values" => [["2015-07-07T15:13:04Z", 34, 0.343443]] },
217
+ { "name" => "cpu", "tags" => { "region" => "us" }, "columns" => %w(time temp value), "values" => [["2015-07-07T14:58:37Z", 92, 0.3445], ["2015-07-07T14:59:09Z", 68, 0.8787]] }] },
218
+ { "series" => [{ "name" => "memory", "tags" => { "region" => "pl" }, "columns" => %w(time free total), "values" => [["2015-07-07T15:13:04Z", 35651584, 134217728]] },
219
+ { "name" => "memory", "tags" => { "region" => "us" }, "columns" => %w(time free total), "values" => [["2015-07-07T14:58:37Z", 96468992, 134217728], ["2015-07-07T14:59:09Z", 71303168, 134217728]] }] }] }
220
+ end
221
+ let(:expected_result) do
222
+ [{ "name" => "cpu", "tags" => { "region" => "pl" },
223
+ "values" => [{ "time" => "2015-07-07T15:13:04Z", "temp" => 34, "value" => 0.343443 }] },
224
+ { "name" => "cpu", "tags" => { "region" => "us" },
225
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "temp" => 92, "value" => 0.3445 },
226
+ { "time" => "2015-07-07T14:59:09Z", "temp" => 68, "value" => 0.8787 }] },
227
+ { "name" => "memory", "tags" => { "region" => "pl" },
228
+ "values" => [{ "time" => "2015-07-07T15:13:04Z", "free" => 34*2**20, "total" => 128*2**20 }] },
229
+ { "name" => "memory", "tags" => { "region" => "us" },
230
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "free" => 92*2**20, "total" => 128*2**20 },
231
+ { "time" => "2015-07-07T14:59:09Z", "free" => 68*2**20, "total" => 128*2**20 }] }]
232
+ end
233
+ let(:query) { 'SELECT * FROM cpu; SELECT * FROM memory' }
234
+
235
+ before do
236
+ stub_request(:get, "http://influxdb.test:9999/query").with(
237
+ query: { q: query, u: "username", p: "password", precision: 's', db: database }
238
+ ).to_return(body: JSON.generate(response))
239
+ end
240
+
241
+ it "should return array with 2 elements grouped by tags" do
242
+ expect(subject.query(query)).to eq(expected_result)
243
+ end
244
+ end
245
+
246
+ context "with a block" do
247
+ let(:response) do
248
+ { "results" => [{ "series" => [{ "name" => "cpu", "tags" => { "region" => "pl" }, "columns" => %w(time temp value), "values" => [["2015-07-07T15:13:04Z", 34, 0.343443]] },
249
+ { "name" => "cpu", "tags" => { "region" => "us" }, "columns" => %w(time temp value), "values" => [["2015-07-07T14:58:37Z", 92, 0.3445], ["2015-07-07T14:59:09Z", 68, 0.8787]] }] },
250
+ { "series" => [{ "name" => "memory", "tags" => { "region" => "pl" }, "columns" => %w(time free total), "values" => [["2015-07-07T15:13:04Z", 35651584, 134217728]] },
251
+ { "name" => "memory", "tags" => { "region" => "us" }, "columns" => %w(time free total), "values" => [["2015-07-07T14:58:37Z", 96468992, 134217728], ["2015-07-07T14:59:09Z", 71303168, 134217728]] }] }] }
252
+ end
253
+
254
+ let(:expected_result) do
255
+ [{ "name" => "cpu", "tags" => { "region" => "pl" },
256
+ "values" => [{ "time" => "2015-07-07T15:13:04Z", "temp" => 34, "value" => 0.343443 }] },
257
+ { "name" => "cpu", "tags" => { "region" => "us" },
258
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "temp" => 92, "value" => 0.3445 },
259
+ { "time" => "2015-07-07T14:59:09Z", "temp" => 68, "value" => 0.8787 }] },
260
+ { "name" => "memory", "tags" => { "region" => "pl" },
261
+ "values" => [{ "time" => "2015-07-07T15:13:04Z", "free" => 34*2**20, "total" => 128*2**20 }] },
262
+ { "name" => "memory", "tags" => { "region" => "us" },
263
+ "values" => [{ "time" => "2015-07-07T14:58:37Z", "free" => 92*2**20, "total" => 128*2**20 },
264
+ { "time" => "2015-07-07T14:59:09Z", "free" => 68*2**20, "total" => 128*2**20 }] }]
265
+ end
266
+ let(:query) { 'SELECT * FROM cpu; SELECT * FROM memory' }
267
+
268
+ before do
269
+ stub_request(:get, "http://influxdb.test:9999/query").with(
270
+ query: { q: query, u: "username", p: "password", precision: 's', db: database }
271
+ ).to_return(body: JSON.generate(response))
272
+ end
273
+
274
+ it "should accept a block and yield name, tags and points" do
275
+ results = []
276
+ subject.query(query) do |name, tags, points|
277
+ results << { 'name' => name, 'tags' => tags, 'values' => points }
278
+ end
279
+ expect(results).to eq(expected_result)
280
+ end
281
+ end
282
+ end
182
283
  end
@@ -63,4 +63,33 @@ describe InfluxDB::Client do
63
63
  expect(subject.ping).to be_a(Net::HTTPNoContent)
64
64
  end
65
65
  end
66
+
67
+ describe "GET #version" do
68
+ it "returns 1.1.1" do
69
+ stub_request(:get, "http://influxdb.test:9999/ping").to_return(
70
+ { :status => 204, :headers => {'x-influxdb-version' => '1.1.1'} })
71
+
72
+ expect(subject.version).to eq('1.1.1')
73
+ end
74
+ end
75
+
76
+ describe "Load balancing" do
77
+ let(:args) { { hosts: hosts } }
78
+ let(:hosts) do
79
+ [
80
+ "influxdb.test0",
81
+ "influxdb.test1",
82
+ "influxdb.test2"
83
+ ]
84
+ end
85
+ let(:cycle) { 3 }
86
+ let!(:stubs) do
87
+ hosts.map { |host| stub_request(:get, "http://#{host}:9999/ping").to_return(status: 204) }
88
+ end
89
+
90
+ it "balance requests" do
91
+ (hosts.size * cycle).times { subject.ping }
92
+ stubs.cycle(cycle) { |stub| expect(stub).to have_been_requested.times(cycle) }
93
+ end
94
+ end
66
95
  end
@@ -1,43 +1,20 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe InfluxDB::PointValue do
4
- describe "whitespace escaping" do
5
- it 'should escape series name' do
6
- point = InfluxDB::PointValue.new(series: "Some Long String", values: { value: 5 })
7
- expect(point.series).to eq("Some\\ Long\\ String")
8
- end
9
-
10
- it 'should escape keys of passed value keys' do
11
- point = InfluxDB::PointValue.new(series: "responses",
12
- values: { 'some string key' => 5 })
13
- expect(point.values.split("=").first).to eq("some\\ string\\ key")
14
- end
15
-
16
- it 'should escape passed values' do
17
- point = InfluxDB::PointValue.new(series: "responses",
18
- values: { response_time: 0.34343 },
19
- tags: { city: "Twin Peaks" })
20
- expect(point.tags.split("=").last).to eq("Twin\\ Peaks")
21
- end
22
- end
23
-
24
- describe "comma escaping" do
25
- it 'should escape series name' do
26
- point = InfluxDB::PointValue.new(series: "Some Long String,", values: { value: 5 })
27
- expect(point.series).to eq("Some\\ Long\\ String\\,")
28
- end
29
-
30
- it 'should escape keys of passed value keys' do
31
- point = InfluxDB::PointValue.new(series: "responses",
32
- values: { 'some string key,' => 5 })
33
- expect(point.values.split("=").first).to eq("some\\ string\\ key\\,")
34
- end
35
-
36
- it 'should escape passed values' do
37
- point = InfluxDB::PointValue.new(series: "responses",
38
- values: { response_time: 0.34343 },
39
- tags: { city: "Twin Peaks," })
40
- expect(point.tags.split("=").last).to eq("Twin\\ Peaks\\,")
4
+ describe "escaping" do
5
+ let(:data) do
6
+ {
7
+ series: '1= ,"\\1',
8
+ tags: {'2= ,"\\2' => '3= ,"\\3'},
9
+ values: {'4= ,"\\4' => '5= ,"\\5'},
10
+ }
11
+ end
12
+
13
+ it 'should escape correctly' do
14
+ point = InfluxDB::PointValue.new(data)
15
+ expected = %(1=\\ \\,"\\1,2\\=\\ \\,"\\2=3\\=\\ \\,"\\3 )+
16
+ %(4\\=\\ \\,\\"\\4="5= ,\\"\\5")
17
+ expect(point.dump).to eq(expected)
41
18
  end
42
19
  end
43
20
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: influxdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Persen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-27 00:00:00.000000000 Z
11
+ date: 2016-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: cause
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: bundler
43
29
  requirement: !ruby/object:Gem::Requirement