influxdb-client 1.9.0.pre.1301 → 1.10.0.pre.1408
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +9 -1
- data/README.md +1 -1
- data/lib/influxdb2/client/client.rb +2 -0
- data/lib/influxdb2/client/default_api.rb +25 -0
- data/lib/influxdb2/client/flux_csv_parser.rb +13 -5
- data/lib/influxdb2/client/version.rb +1 -1
- data/lib/influxdb2/client/worker.rb +4 -0
- data/test/influxdb/default_api_test.rb +60 -0
- data/test/influxdb/flux_csv_parser_test.rb +43 -0
- data/test/influxdb/write_api_batching_test.rb +31 -1
- data/test/test_helper.rb +12 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '013876e9eaa68bd87570e052b14006ac79fd316ddaf0cf71173b8db024ea271e'
|
4
|
+
data.tar.gz: 24c018d6b548cd9d2acd1b6f7b179976862cd01dcf7e8b136fb3f4ef19bcaa74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2b4774d72b7b64c6c5cafef67159fd3abb4b1f3d10d3d3c3d51950a12e27776ab216cc62216c4cf190d1718f7a7dabf20fd80db35e4ea01a53306d6331bafe9
|
7
|
+
data.tar.gz: 8bcced7536d8495664de2e5ed33da09f980934ae08b3a5bc867383c7edf768334c4bc3192ad1b7d8ccf628b662d5fa6c1342d04ab7844fabb66a160f86e9cce8
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
## 1.
|
1
|
+
## 1.10.0 [unreleased]
|
2
|
+
|
3
|
+
### Features
|
4
|
+
1. [#59](https://github.com/influxdata/influxdb-client-ruby/pull/59): CSV parser is able to parse export from UI
|
5
|
+
|
6
|
+
## 1.9.0 [2020-10-30]
|
7
|
+
|
8
|
+
### Features
|
9
|
+
1. [#55](https://github.com/influxdata/influxdb-client-runy/pull/55): Improved logging message for retries
|
2
10
|
|
3
11
|
## 1.8.0 [2020-10-02]
|
4
12
|
|
data/README.md
CHANGED
@@ -43,6 +43,7 @@ module InfluxDB2
|
|
43
43
|
# @option options [Integer] :read_timeout Number of seconds to wait for one block of data to be read
|
44
44
|
# @option options [Integer] :max_redirect_count Maximal number of followed HTTP redirects
|
45
45
|
# @option options [bool] :use_ssl Turn on/off SSL for HTTP communication
|
46
|
+
# @option options [Logger] :logger Logger used for logging. Disable logging by set to false.
|
46
47
|
# @option options [Hash] :tags Default tags which will be added to each point written by api.
|
47
48
|
# the body line-protocol
|
48
49
|
def initialize(url, token, options = nil)
|
@@ -50,6 +51,7 @@ module InfluxDB2
|
|
50
51
|
@options = options ? options.dup : {}
|
51
52
|
@options[:url] = url if url.is_a? String
|
52
53
|
@options[:token] = token if token.is_a? String
|
54
|
+
@options[:logger] = @options[:logger].nil? ? DefaultApi.create_logger : @options[:logger]
|
53
55
|
@closed = false
|
54
56
|
|
55
57
|
at_exit { close! }
|
@@ -18,6 +18,8 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require 'logger'
|
22
|
+
|
21
23
|
module InfluxDB2
|
22
24
|
# default api
|
23
25
|
class DefaultApi
|
@@ -32,6 +34,29 @@ module InfluxDB2
|
|
32
34
|
@max_redirect_count = @options[:max_redirect_count] || DEFAULT_REDIRECT_COUNT
|
33
35
|
end
|
34
36
|
|
37
|
+
def log(level, message)
|
38
|
+
return unless @options[:logger]
|
39
|
+
|
40
|
+
log_level = case level
|
41
|
+
when :debug then
|
42
|
+
Logger::DEBUG
|
43
|
+
when :warn then
|
44
|
+
Logger::WARN
|
45
|
+
when :error then
|
46
|
+
Logger::ERROR
|
47
|
+
when :fatal then
|
48
|
+
Logger::FATAL
|
49
|
+
else
|
50
|
+
Logger::INFO
|
51
|
+
end
|
52
|
+
|
53
|
+
@options[:logger].add(log_level) { message }
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.create_logger
|
57
|
+
Logger.new(STDOUT)
|
58
|
+
end
|
59
|
+
|
35
60
|
private
|
36
61
|
|
37
62
|
def _parse_uri(api_path)
|
@@ -54,6 +54,7 @@ module InfluxDB2
|
|
54
54
|
@table_id = -1
|
55
55
|
@start_new_table = false
|
56
56
|
@table = nil
|
57
|
+
@groups = []
|
57
58
|
@parsing_state_error = false
|
58
59
|
|
59
60
|
@closed = false
|
@@ -102,14 +103,20 @@ module InfluxDB2
|
|
102
103
|
|
103
104
|
private
|
104
105
|
|
106
|
+
ANNOTATION_DATATYPE = '#datatype'.freeze
|
107
|
+
ANNOTATION_GROUP = '#group'.freeze
|
108
|
+
ANNOTATION_DEFAULT = '#default'.freeze
|
109
|
+
ANNOTATIONS = [ANNOTATION_DATATYPE, ANNOTATION_GROUP, ANNOTATION_DEFAULT].freeze
|
110
|
+
|
105
111
|
def _parse_line(csv)
|
106
112
|
token = csv[0]
|
107
113
|
|
108
114
|
# start new table
|
109
|
-
if token
|
115
|
+
if (ANNOTATIONS.include? token) && !@start_new_table
|
110
116
|
# Return already parsed DataFrame
|
111
117
|
@start_new_table = true
|
112
118
|
@table = InfluxDB2::FluxTable.new
|
119
|
+
@groups = []
|
113
120
|
|
114
121
|
@tables[@table_index] = @table unless @stream
|
115
122
|
|
@@ -120,13 +127,13 @@ module InfluxDB2
|
|
120
127
|
end
|
121
128
|
|
122
129
|
# # datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string
|
123
|
-
if token ==
|
130
|
+
if token == ANNOTATION_DATATYPE
|
124
131
|
_add_data_types(@table, csv)
|
125
132
|
|
126
|
-
elsif token ==
|
127
|
-
|
133
|
+
elsif token == ANNOTATION_GROUP
|
134
|
+
@groups = csv
|
128
135
|
|
129
|
-
elsif token ==
|
136
|
+
elsif token == ANNOTATION_DEFAULT
|
130
137
|
_add_default_empty_values(@table, csv)
|
131
138
|
else
|
132
139
|
_parse_values(csv)
|
@@ -170,6 +177,7 @@ module InfluxDB2
|
|
170
177
|
def _parse_values(csv)
|
171
178
|
# parse column names
|
172
179
|
if @start_new_table
|
180
|
+
_add_groups(@table, @groups)
|
173
181
|
_add_column_names_and_tags(@table, csv)
|
174
182
|
@start_new_table = false
|
175
183
|
return
|
@@ -116,6 +116,10 @@ module InfluxDB2
|
|
116
116
|
e.retry_after.to_f
|
117
117
|
end
|
118
118
|
|
119
|
+
message = 'The retriable error occurred during writing of data. '\
|
120
|
+
"Reason: '#{e.message}'. Retry in: #{timeout}s."
|
121
|
+
|
122
|
+
@api_client.log(:warn, message)
|
119
123
|
sleep timeout
|
120
124
|
_write_raw(key, points, attempts + 1, retry_interval * @write_options.exponential_base)
|
121
125
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# The MIT License
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'test_helper'
|
22
|
+
require 'influxdb2/client/default_api'
|
23
|
+
|
24
|
+
class DefaultApiTest < MiniTest::Test
|
25
|
+
def setup
|
26
|
+
@logger = MockLogger.new
|
27
|
+
@api = InfluxDB2::DefaultApi.new(options: { logger: @logger })
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_level
|
31
|
+
@api.log(:debug, 'debug message')
|
32
|
+
@api.log(:warn, 'warn message')
|
33
|
+
@api.log(:error, 'error message')
|
34
|
+
@api.log(:info, 'info message')
|
35
|
+
@api.log(:others, 'others message')
|
36
|
+
|
37
|
+
assert_equal 5, @logger.messages.count
|
38
|
+
|
39
|
+
assert_equal Logger::DEBUG, @logger.messages[0][0]
|
40
|
+
assert_equal 'debug message', @logger.messages[0][1]
|
41
|
+
|
42
|
+
assert_equal Logger::WARN, @logger.messages[1][0]
|
43
|
+
assert_equal 'warn message', @logger.messages[1][1]
|
44
|
+
|
45
|
+
assert_equal Logger::ERROR, @logger.messages[2][0]
|
46
|
+
assert_equal 'error message', @logger.messages[2][1]
|
47
|
+
|
48
|
+
assert_equal Logger::INFO, @logger.messages[3][0]
|
49
|
+
assert_equal 'info message', @logger.messages[3][1]
|
50
|
+
|
51
|
+
assert_equal Logger::INFO, @logger.messages[4][0]
|
52
|
+
assert_equal 'others message', @logger.messages[4][1]
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_supports_false
|
56
|
+
@api = InfluxDB2::DefaultApi.new(options: { logger: false })
|
57
|
+
|
58
|
+
@api.log(:info, 'without error')
|
59
|
+
end
|
60
|
+
end
|
@@ -324,6 +324,32 @@ class FluxCsvParserErrorTest < MiniTest::Test
|
|
324
324
|
assert_equal 'Unable to parse CSV response. FluxTable definition was not found.', error.message
|
325
325
|
end
|
326
326
|
|
327
|
+
def test_response_with_error
|
328
|
+
data = "#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" \
|
329
|
+
"#group,false,false,true,true,true,true,false,false,true\n" \
|
330
|
+
"#default,t1,,,,,,,,\n" \
|
331
|
+
",result,table,_field,_measurement,_start,_stop,_time,_value,tag\n" \
|
332
|
+
",,0,value,python,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test1\n" \
|
333
|
+
",,0,value,python,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test1\n" \
|
334
|
+
",,0,value,python,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test1\n" \
|
335
|
+
",,0,value,python,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test1\n" \
|
336
|
+
"\n" \
|
337
|
+
"#datatype,string,string\n" \
|
338
|
+
"#group,true,true\n" \
|
339
|
+
"#default,,\n" \
|
340
|
+
",error,reference\n" \
|
341
|
+
',"engine: unknown field type for value: xyz",'
|
342
|
+
|
343
|
+
parser = InfluxDB2::FluxCsvParser.new(data)
|
344
|
+
|
345
|
+
error = assert_raises InfluxDB2::FluxQueryError do
|
346
|
+
parser.parse
|
347
|
+
end
|
348
|
+
|
349
|
+
assert_equal 'engine: unknown field type for value: xyz', error.message
|
350
|
+
assert_equal 0, error.reference
|
351
|
+
end
|
352
|
+
|
327
353
|
def test_multiple_queries
|
328
354
|
data = "#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" \
|
329
355
|
"#group,false,false,true,true,true,true,false,false,true\n" \
|
@@ -398,4 +424,21 @@ class FluxCsvParserErrorTest < MiniTest::Test
|
|
398
424
|
assert_equal 7, tables[0].records.size
|
399
425
|
assert_equal 7, tables[1].records.size
|
400
426
|
end
|
427
|
+
|
428
|
+
def test_parse_export_from_ui
|
429
|
+
data = "#group,false,false,true,true,true,true,true,true,false,false\n" \
|
430
|
+
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,string,double,dateTime:RFC3339\n" \
|
431
|
+
"#default,mean,,,,,,,,,\n" \
|
432
|
+
",result,table,_start,_stop,_field,_measurement,city,location,_value,_time\n" \
|
433
|
+
",,0,1754-06-26T11:30:27.613654848Z,2040-10-27T12:13:46.485Z,temp,weather,Lon,us,30,1975-09-01T16:59:54.5Z\n" \
|
434
|
+
",,1,1754-06-26T11:30:27.613654848Z,2040-10-27T12:13:46.485Z,temp,weather,Lon,us,86,1975-09-01T16:59:54.5Z\n"
|
435
|
+
|
436
|
+
tables = InfluxDB2::FluxCsvParser.new(data).parse.tables
|
437
|
+
assert_equal 2, tables.size
|
438
|
+
assert_equal 1, tables[0].records.size
|
439
|
+
assert_equal false, tables[0].columns[0].group
|
440
|
+
assert_equal false, tables[0].columns[1].group
|
441
|
+
assert_equal true, tables[0].columns[2].group
|
442
|
+
assert_equal 1, tables[1].records.size
|
443
|
+
end
|
401
444
|
end
|
@@ -226,6 +226,7 @@ class WriteApiRetryStrategyTest < MiniTest::Test
|
|
226
226
|
def setup
|
227
227
|
WebMock.disable_net_connect!
|
228
228
|
|
229
|
+
@logger = MockLogger.new
|
229
230
|
@write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
|
230
231
|
batch_size: 2, flush_interval: 5_000, retry_interval: 2_000)
|
231
232
|
@client = InfluxDB2::Client.new('http://localhost:8086',
|
@@ -233,7 +234,8 @@ class WriteApiRetryStrategyTest < MiniTest::Test
|
|
233
234
|
bucket: 'my-bucket',
|
234
235
|
org: 'my-org',
|
235
236
|
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
236
|
-
use_ssl: false
|
237
|
+
use_ssl: false,
|
238
|
+
logger: @logger)
|
237
239
|
|
238
240
|
@write_client = @client.create_write_api(write_options: @write_options)
|
239
241
|
end
|
@@ -594,4 +596,32 @@ class WriteApiRetryStrategyTest < MiniTest::Test
|
|
594
596
|
assert_requested(:post, 'http://localhost:8086/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
595
597
|
times: 1, body: 'h2o,location=europe level=2.0 1')
|
596
598
|
end
|
599
|
+
|
600
|
+
def test_retry_contains_message
|
601
|
+
error_body = '{"code":"temporarily unavailable","message":"Server is temporarily unavailable to accept writes."}'
|
602
|
+
|
603
|
+
stub_request(:post, 'http://localhost:8086/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
604
|
+
.to_return(status: 429, headers: { 'X-Platform-Error-Code' => 'temporarily unavailable', 'Retry-After' => '3' },
|
605
|
+
body: error_body).then
|
606
|
+
.to_return(status: 204)
|
607
|
+
|
608
|
+
request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
|
609
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'
|
610
|
+
|
611
|
+
@write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
|
612
|
+
InfluxDB2::Point.new(name: 'h2o_feet')
|
613
|
+
.add_tag('location', 'coyote_creek')
|
614
|
+
.add_field('water_level', 2.0)
|
615
|
+
.time(2, InfluxDB2::WritePrecision::NANOSECOND)])
|
616
|
+
|
617
|
+
sleep(5)
|
618
|
+
|
619
|
+
assert_requested(:post, 'http://localhost:8086/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
620
|
+
times: 2, body: request)
|
621
|
+
|
622
|
+
message = 'The retriable error occurred during writing of data. '\
|
623
|
+
"Reason: 'Server is temporarily unavailable to accept writes.'. Retry in: 3.0s."
|
624
|
+
|
625
|
+
assert_equal(message, @logger.messages[0][1])
|
626
|
+
end
|
597
627
|
end
|
data/test/test_helper.rb
CHANGED
@@ -37,3 +37,15 @@ require 'minitest/reporters'
|
|
37
37
|
Minitest::Reporters.use!
|
38
38
|
|
39
39
|
require 'webmock/minitest'
|
40
|
+
|
41
|
+
class MockLogger
|
42
|
+
attr_accessor :messages
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
@messages = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def add(level, &block)
|
49
|
+
@messages << [level, yield(block)]
|
50
|
+
end
|
51
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: influxdb-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0.pre.1408
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Bednar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/influxdb2/client/worker.rb
|
169
169
|
- lib/influxdb2/client/write_api.rb
|
170
170
|
- test/influxdb/client_test.rb
|
171
|
+
- test/influxdb/default_api_test.rb
|
171
172
|
- test/influxdb/delete_api_integration_test.rb
|
172
173
|
- test/influxdb/delete_api_test.rb
|
173
174
|
- test/influxdb/flux_csv_parser_test.rb
|
@@ -207,6 +208,7 @@ specification_version: 4
|
|
207
208
|
summary: Ruby library for InfluxDB 2.
|
208
209
|
test_files:
|
209
210
|
- test/influxdb/client_test.rb
|
211
|
+
- test/influxdb/default_api_test.rb
|
210
212
|
- test/influxdb/delete_api_integration_test.rb
|
211
213
|
- test/influxdb/delete_api_test.rb
|
212
214
|
- test/influxdb/flux_csv_parser_test.rb
|