influxdb 0.2.3 → 0.2.4

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 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