influxdb-client 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
@@ -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