influxdb-client 1.0.0.beta

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.
@@ -0,0 +1,23 @@
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
+ module InfluxDB2
22
+ VERSION = '1.0.0.beta'.freeze
23
+ end
@@ -0,0 +1,154 @@
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
+ module InfluxDB2
22
+ # Precision constants.
23
+ #
24
+ class WritePrecision
25
+ SECOND = 's'.freeze
26
+ MILLISECOND = 'ms'.freeze
27
+ MICROSECOND = 'us'.freeze
28
+ NANOSECOND = 'ns'.freeze
29
+
30
+ def get_from_value(value)
31
+ constants = WritePrecision.constants.select { |c| WritePrecision.const_get(c) == value }
32
+ raise "The time precision #{value} is not supported." if constants.empty?
33
+
34
+ value
35
+ end
36
+ end
37
+
38
+ # Write time series data into InfluxDB.
39
+ #
40
+ class WriteApi
41
+ DEFAULT_TIMEOUT = 10
42
+ DEFAULT_REDIRECT_COUNT = 10
43
+
44
+ # @param [Hash] options The options to be used by the client.
45
+ def initialize(options:)
46
+ @options = options
47
+ @max_redirect_count = @options[:max_redirect_count] || DEFAULT_REDIRECT_COUNT
48
+ end
49
+
50
+ # Write data into specified Bucket.
51
+ #
52
+ # @example write(data:
53
+ # [
54
+ # {
55
+ # name: 'cpu',
56
+ # tags: { host: 'server_nl', region: 'us' },
57
+ # fields: {internal: 5, external: 6},
58
+ # time: 1422568543702900257
59
+ # },
60
+ # {name: 'gpu', fields: {value: 0.9999}}
61
+ # ],
62
+ # precision: InfluxDB::WritePrecision::NANOSECOND,
63
+ # bucket: 'my-bucket',
64
+ # org: 'my-org'
65
+ # )
66
+ #
67
+ # @example write(data: 'h2o,location=west value=33i 15')
68
+ #
69
+ # @example point = InfluxDB::Point.new(name: 'h2o')
70
+ # .add_tag('location', 'europe')
71
+ # .add_field('level', 2)
72
+ #
73
+ # hash = { name: 'h2o', tags: { host: 'aws', region: 'us' }, fields: { level: 5, saturation: '99%' }, time: 123 }
74
+ #
75
+ # write(data: ['h2o,location=west value=33i 15', point, hash])
76
+ #
77
+ # @param [Object] data DataPoints to write into InfluxDB. The data could be represent by [Hash], [Point], [String]
78
+ # or by collection of these types
79
+ # @param [WritePrecision] precision The precision for the unix timestamps within the body line-protocol
80
+ # @param [String] bucket specifies the destination bucket for writes
81
+ # @param [String] org specifies the destination organization for writes
82
+ def write(data:, precision: nil, bucket: nil, org: nil)
83
+ precision_param = precision || @options[:precision]
84
+ bucket_param = bucket || @options[:bucket]
85
+ org_param = org || @options[:org]
86
+ _check('precision', precision_param)
87
+ _check('bucket', bucket_param)
88
+ _check('org', org_param)
89
+
90
+ payload = _generate_payload(data)
91
+ return nil if payload.nil?
92
+
93
+ uri = URI.parse(File.join(@options[:url], '/api/v2/write'))
94
+ uri.query = URI.encode_www_form(bucket: bucket_param, org: org_param, precision: precision_param.to_s)
95
+
96
+ _post(payload, uri)
97
+ end
98
+
99
+ private
100
+
101
+ def _post(payload, uri, limit = @max_redirect_count)
102
+ raise InfluxError.from_message("Too many HTTP redirects. Exceeded limit: #{@max_redirect_count}") if limit.zero?
103
+
104
+ http = Net::HTTP.new(uri.host, uri.port)
105
+ http.open_timeout = @options[:open_timeout] || DEFAULT_TIMEOUT
106
+ http.write_timeout = @options[:write_timeout] || DEFAULT_TIMEOUT if Net::HTTP.method_defined? :write_timeout
107
+ http.read_timeout = @options[:read_timeout] || DEFAULT_TIMEOUT
108
+ http.use_ssl = @options[:use_ssl].nil? ? true : @options[:use_ssl]
109
+
110
+ request = Net::HTTP::Post.new(uri.request_uri)
111
+ request['Authorization'] = "Token #{@options[:token]}"
112
+ request.body = payload
113
+
114
+ begin
115
+ response = http.request(request)
116
+ case response
117
+ when Net::HTTPSuccess then
118
+ response
119
+ when Net::HTTPRedirection then
120
+ location = response['location']
121
+ _post(payload, URI.parse(location), limit - 1)
122
+ else
123
+ raise InfluxError.from_response(response)
124
+ end
125
+ ensure
126
+ http.finish if http.started?
127
+ end
128
+ end
129
+
130
+ def _check(key, value)
131
+ raise ArgumentError, "The '#{key}' should be defined as argument or default option: #{@options}" if value.nil?
132
+ end
133
+
134
+ def _generate_payload(data)
135
+ if data.nil?
136
+ nil
137
+ elsif data.is_a?(Point)
138
+ data.to_line_protocol
139
+ elsif data.is_a?(String)
140
+ if data.empty?
141
+ nil
142
+ else
143
+ data
144
+ end
145
+ elsif data.is_a?(Hash)
146
+ _generate_payload(Point.from_hash(data))
147
+ elsif data.respond_to? :map
148
+ data.map do |item|
149
+ _generate_payload(item)
150
+ end.reject(&:nil?).join("\n".freeze)
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,70 @@
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
+
23
+ class ClientTest < Minitest::Test
24
+ def test_defined_version_number
25
+ refute_nil ::InfluxDB2::VERSION
26
+ end
27
+
28
+ def test_client_new
29
+ refute_nil InfluxDB2::Client.new('http://localhost:9999', 'my-token')
30
+ end
31
+
32
+ def test_client_hash
33
+ client1 = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
34
+ client2 = InfluxDB2::Client.new('http://localhost:9999', 'my-token-diff')
35
+
36
+ refute_equal client1.hash, client2.hash
37
+ assert_equal client1.hash, client1.hash
38
+ end
39
+
40
+ def test_client_eq
41
+ client1 = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
42
+ client2 = InfluxDB2::Client.new('http://localhost:9999', 'my-token-diff')
43
+
44
+ refute_equal client1, client2
45
+ assert_equal client1, client1
46
+ end
47
+
48
+ def test_client_options
49
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
50
+
51
+ assert_equal 'http://localhost:9999', client.options[:url]
52
+ assert_equal 'my-token', client.options[:token]
53
+ end
54
+
55
+ def test_close
56
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
57
+
58
+ assert_equal true, client.close!
59
+ assert_equal true, client.close!
60
+ end
61
+
62
+ def test_get_write_api
63
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
64
+
65
+ write_api = client.create_write_api
66
+
67
+ refute_nil write_api
68
+ assert_instance_of InfluxDB2::WriteApi, write_api
69
+ end
70
+ end
@@ -0,0 +1,221 @@
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
+
23
+ class PointTest < MiniTest::Test
24
+ def test_to_line_protocol
25
+ point_args = InfluxDB2::Point.new(name: 'h2o',
26
+ tags: { host: 'aws', region: 'us' },
27
+ fields: { level: 5, saturation: '99%' }, time: 123)
28
+ assert_equal 'h2o,host=aws,region=us level=5i,saturation="99%" 123', point_args.to_line_protocol
29
+
30
+ point_hash = InfluxDB2::Point.from_hash(name: 'h2o',
31
+ tags: { host: 'aws', region: 'us' },
32
+ fields: { level: 5, saturation: '99%' }, time: 123)
33
+ assert_equal 'h2o,host=aws,region=us level=5i,saturation="99%" 123', point_hash.to_line_protocol
34
+ end
35
+
36
+ def test_measurement_escape
37
+ point = InfluxDB2::Point.new(name: 'h2 o', tags: { location: 'europe' }, fields: { level: 2 })
38
+ assert_equal 'h2\\ o,location=europe level=2i', point.to_line_protocol
39
+
40
+ point = InfluxDB2::Point.new(name: 'h2,o', tags: { location: 'europe' }, fields: { level: 2 })
41
+ assert_equal 'h2\\,o,location=europe level=2i', point.to_line_protocol
42
+ end
43
+
44
+ def test_tag_empty_key
45
+ point = InfluxDB2::Point.new(name: 'h2o', fields: { level: 2 }).add_tag('location', 'europe').add_tag('', 'warn')
46
+
47
+ assert_equal 'h2o,location=europe level=2i', point.to_line_protocol
48
+ end
49
+
50
+ def test_tag_empty_value
51
+ point = InfluxDB2::Point.new(name: 'h2o', fields: { level: 2 }).add_tag('location', 'europe').add_tag('log', '')
52
+
53
+ assert_equal 'h2o,location=europe level=2i', point.to_line_protocol
54
+ end
55
+
56
+ def test_override_tag_and_field
57
+ point = InfluxDB2::Point.new(name: 'h2o', fields: { level: '1' })
58
+ .add_tag('location', 'europe')
59
+ .add_tag('location', 'europe2')
60
+ .add_field(:level, 2)
61
+ .add_field(:level, 3)
62
+
63
+ assert_equal 'h2o,location=europe2 level=3i', point.to_line_protocol
64
+ end
65
+
66
+ def test_field_types
67
+ point = InfluxDB2::Point.new(name: 'h2o')
68
+ .add_tag('tag_b', 'b')
69
+ .add_tag('tag_a', 'a')
70
+ .add_field('n1', -2)
71
+ .add_field('n2', 10)
72
+ .add_field('n3', 1_265_437_718_438_866_624_512)
73
+ .add_field('n4', 5.5)
74
+ .add_field('bool', true)
75
+ .add_field('string', 'string value')
76
+
77
+ expected = 'h2o,tag_a=a,tag_b=b bool=true,n1=-2i,n2=10i,n3=1265437718438866624512i,n4=5.5,string="string value"'
78
+ assert_equal expected, point.to_line_protocol
79
+ end
80
+
81
+ def test_field_null_value
82
+ point = InfluxDB2::Point.new(name: 'h2o')
83
+ .add_tag('location', 'europe')
84
+ .add_field('level', 2)
85
+ .add_field('warning', nil)
86
+
87
+ assert_equal 'h2o,location=europe level=2i', point.to_line_protocol
88
+ end
89
+
90
+ def test_field_escape
91
+ point = InfluxDB2::Point.new(name: 'h2o')
92
+ .add_tag('location', 'europe')
93
+ .add_field('level', 'string esc\\ape value')
94
+
95
+ assert_equal 'h2o,location=europe level="string esc\\\\ape value"', point.to_line_protocol
96
+
97
+ point = InfluxDB2::Point.new(name: 'h2o')
98
+ .add_tag('location', 'europe')
99
+ .add_field('level', 'string esc"ape value')
100
+
101
+ assert_equal 'h2o,location=europe level="string esc\"ape value"', point.to_line_protocol
102
+ end
103
+
104
+ def test_time
105
+ point = InfluxDB2::Point.new(name: 'h2o')
106
+ .add_tag('location', 'europe')
107
+ .add_field('level', 2)
108
+ .time(123, InfluxDB2::WritePrecision::NANOSECOND)
109
+
110
+ assert_equal 'h2o,location=europe level=2i 123', point.to_line_protocol
111
+ end
112
+
113
+ def test_time_formatting
114
+ time = Time.utc(2015, 10, 15, 8, 20, 15)
115
+
116
+ point = InfluxDB2::Point.new(name: 'h2o')
117
+ .add_tag('location', 'europe')
118
+ .add_field('level', 2)
119
+ .time(time, InfluxDB2::WritePrecision::MILLISECOND)
120
+
121
+ assert_equal 'h2o,location=europe level=2i 1444897215000', point.to_line_protocol
122
+
123
+ point = InfluxDB2::Point.new(name: 'h2o')
124
+ .add_tag('location', 'europe')
125
+ .add_field('level', 2)
126
+ .time(time, InfluxDB2::WritePrecision::SECOND)
127
+
128
+ assert_equal 'h2o,location=europe level=2i 1444897215', point.to_line_protocol
129
+
130
+ point = InfluxDB2::Point.new(name: 'h2o')
131
+ .add_tag('location', 'europe')
132
+ .add_field('level', 2)
133
+ .time(time, InfluxDB2::WritePrecision::MICROSECOND)
134
+
135
+ assert_equal 'h2o,location=europe level=2i 1444897215000000', point.to_line_protocol
136
+
137
+ point = InfluxDB2::Point.new(name: 'h2o')
138
+ .add_tag('location', 'europe')
139
+ .add_field('level', 2)
140
+ .time(time, InfluxDB2::WritePrecision::NANOSECOND)
141
+
142
+ assert_equal 'h2o,location=europe level=2i 1444897215000000000', point.to_line_protocol
143
+ end
144
+
145
+ def test_time_formatting_default
146
+ time = Time.utc(2015, 10, 15, 8, 20, 15)
147
+
148
+ point = InfluxDB2::Point.new(name: 'h2o', time: time)
149
+ .add_tag('location', 'europe')
150
+ .add_field('level', 2)
151
+
152
+ assert_equal 'h2o,location=europe level=2i 1444897215000000000', point.to_line_protocol
153
+
154
+ point = InfluxDB2::Point.new(name: 'h2o')
155
+ .add_tag('location', 'europe')
156
+ .add_field('level', 2)
157
+ .time(time, nil)
158
+
159
+ assert_equal 'h2o,location=europe level=2i 1444897215000000000', point.to_line_protocol
160
+ end
161
+
162
+ def test_time_string
163
+ point_args = InfluxDB2::Point.new(name: 'h2o',
164
+ tags: { host: 'aws', region: 'us' },
165
+ fields: { level: 5 }, time: '123')
166
+
167
+ assert_equal 'h2o,host=aws,region=us level=5i 123', point_args.to_line_protocol
168
+ end
169
+
170
+ def test_time_float
171
+ point_args = InfluxDB2::Point.new(name: 'h2o',
172
+ tags: { host: 'aws', region: 'us' },
173
+ fields: { level: 5 }, time: 1.444897215e+18)
174
+
175
+ assert_equal 'h2o,host=aws,region=us level=5i 1444897215000000000', point_args.to_line_protocol
176
+
177
+ point_args = InfluxDB2::Point.new(name: 'h2o',
178
+ tags: { host: 'aws', region: 'us' },
179
+ fields: { level: 5 }, time: 102_030_405_060)
180
+
181
+ assert_equal 'h2o,host=aws,region=us level=5i 102030405060', point_args.to_line_protocol
182
+ end
183
+
184
+ def test_utf_8
185
+ point = InfluxDB2::Point.new(name: 'h2o')
186
+ .add_tag('location', 'Přerov')
187
+ .add_field('level', 2)
188
+ .time(123, InfluxDB2::WritePrecision::NANOSECOND)
189
+
190
+ assert_equal 'h2o,location=Přerov level=2i 123', point.to_line_protocol
191
+ end
192
+
193
+ def test_infinity_values
194
+ point = InfluxDB2::Point.new(name: 'h2o')
195
+ .add_tag('location', 'europe')
196
+ .add_field('infinity_constant', Float::INFINITY)
197
+ .add_field('infinity_positive', 1 / 0.0)
198
+ .add_field('infinity_negative', -1 / 0.0)
199
+ .add_field('level', 2)
200
+
201
+ assert_equal 'h2o,location=europe level=2i', point.to_line_protocol
202
+ end
203
+
204
+ def test_only_infinity_values
205
+ point = InfluxDB2::Point.new(name: 'h2o')
206
+ .add_tag('location', 'europe')
207
+ .add_field('infinity_constant', Float::INFINITY)
208
+ .add_field('infinity_positive', 1 / 0.0)
209
+ .add_field('infinity_negative', -1 / 0.0)
210
+
211
+ assert_nil point.to_line_protocol
212
+ end
213
+
214
+ def test_without_tags
215
+ point = InfluxDB2::Point.new(name: 'h2o')
216
+ .add_field('level', 2)
217
+ .time(123, InfluxDB2::WritePrecision::NANOSECOND)
218
+
219
+ assert_equal 'h2o level=2i 123', point.to_line_protocol
220
+ end
221
+ end