fluent-plugin-out-kafka-rest 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4df0762c0b4f96b734f8492c8a4ae198260bc421
4
+ data.tar.gz: cc1534fdd3a60a3221d0f4259ef200917dc4cec9
5
+ SHA512:
6
+ metadata.gz: db0a371008c9c3b9dbf9762570345dbcaad5d0b0446995431746b30ffe8498bef47876296d7c76bdabd1f8b66a350608cf6cdd0e7db665f4d71500355eddd417
7
+ data.tar.gz: 6595f68524f2c242bce7b7cb4e034d83385a87e99919fc099c05e7ec8cc52f24ce033a9c030b34f6ed26cb7b87d0bfb8486bf80dd0bdda6a68c4020c12576be0
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *~
2
+ \#*
3
+ .\#*
4
+ *.gem
5
+ .bundle
6
+ Gemfile.lock
7
+ vendor
8
+ .idea
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-out-kafka-rest.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,11 @@
1
+ Licensed under the Apache License, Version 2.0 (the "License");
2
+ you may not use this file except in compliance with the License.
3
+ You may obtain a copy of the License at
4
+
5
+ http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # fluent-plugin-out-kafka-rest, a plugin for [Fluentd](http://fluentd.org) (WIP)
2
+
3
+ A [fluentd][1] output plugin for sending logs to Kafka REST Proxy.
4
+ This plugin does not use the native library of Apache Kafka itself.
5
+ Please refer to Confluent's [kakfa-rest](https://github.com/confluentinc/kafka-rest)
6
+ for the detail of REST Proxy service.
7
+
8
+ ## Configs
9
+
10
+ <match *>
11
+ type kafka-rest
12
+ endpoint_url https://localhost.local/api/
13
+ # use_ssl false
14
+ # include_tag false
15
+ # include_timestamp false
16
+ # http_method post
17
+ # serializer one
18
+ # rate_limit_msec 0
19
+ # authentication basic # default: nil
20
+ # username alice
21
+ # password bobpop
22
+ </match>
23
+
24
+ ## ToDo
25
+
26
+ * Change tests
27
+ * Fix the function to include tags and timestamps.
28
+ We should include such information into the request body.
29
+ * Add function to submit multiple records at once.
30
+ * Try SSL via ELB
31
+ * Avro support
32
+
33
+ ## Note
34
+
35
+ * Set `use_ssl` to true to use https connection
36
+ * Set `include_tag` to true to include fluentd tag in the event log as a property
37
+ * Set `include_timestamp` to true to include timestamp (UNIX time) in the event log as a property
38
+ * Set `serializer` to any to use your own serializer rule except for Kafka REST Proxy's JSON protocol
39
+ * By default, it does not verify the https server. Use VERIFY_PEER and place the cert.pem to the location specified by OpenSSL::X509::DEFAULT_CERT_FILE.
40
+ * Majority of the code are cloned from [fluent-plugin-out-https][2]
41
+
42
+ [1]: http://fluentd.org/
43
+ [2]: https://github.com/kazunori279/fluent-plugin-out-https
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "fluent-plugin-out-kafka-rest"
5
+ gem.version = "0.1.0"
6
+ gem.authors = ["dobachi"]
7
+ gem.email = ["dobachi1983oss@gmail.com"]
8
+ gem.summary = %q{A fluentd output plugin for sending logs to Kafka REST Proxy}
9
+ gem.description = gem.summary
10
+ gem.homepage = "https://github.com/dobachi/fluent-plugin-out-kafka-rest"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+
17
+ gem.add_runtime_dependency "yajl-ruby", "~> 1.0"
18
+ gem.add_runtime_dependency "fluentd", "~> 0.10.0"
19
+ gem.add_development_dependency "bundler"
20
+ gem.add_development_dependency "rake"
21
+ end
@@ -0,0 +1,170 @@
1
+ class Fluent::KafkaRestOutput < Fluent::Output
2
+ Fluent::Plugin.register_output('kafka-rest', self)
3
+
4
+ def initialize
5
+ super
6
+ require 'net/https'
7
+ require 'openssl'
8
+ require 'uri'
9
+ require 'yajl'
10
+ require 'base64'
11
+ end
12
+
13
+ # https or http
14
+ config_param :use_ssl, :bool, :default => false
15
+
16
+ # include tag
17
+ config_param :include_tag, :bool, :default => false
18
+
19
+ # include timestamp
20
+ config_param :include_timestamp, :bool, :default => false
21
+
22
+ # Endpoint URL ex. localhost.local/api/
23
+ config_param :endpoint_url, :string
24
+
25
+ # HTTP method
26
+ config_param :http_method, :string, :default => :post
27
+
28
+ # json_bin ( Should support avro in the future)
29
+ config_param :serializer, :string, :default => :json_bin
30
+
31
+ # Content-Type
32
+ config_param :content_type, :string, :default => 'application/json'
33
+
34
+ # Simple rate limiting: ignore any records within `rate_limit_msec`
35
+ # since the last one.
36
+ config_param :rate_limit_msec, :integer, :default => 0
37
+
38
+ # nil | 'none' | 'basic'
39
+ config_param :authentication, :string, :default => nil
40
+ config_param :username, :string, :default => ''
41
+ config_param :password, :string, :default => ''
42
+
43
+ def configure(conf)
44
+ super
45
+
46
+ @use_ssl = conf['use_ssl']
47
+ @include_tag = conf['include_tag']
48
+ @include_timestamp = conf['include_timestamp']
49
+
50
+ serializers = [:json_bin] # Should support :avro in the future
51
+ @serializer = if serializers.include? @serializer.intern
52
+ @serializer.intern
53
+ else
54
+ :json_bin
55
+ end
56
+
57
+ @content_type = conf['content_type']
58
+
59
+ # Kafka REST Proxy accepts only POST method at the moment
60
+ http_methods = [:post]
61
+ @http_method = if http_methods.include? @http_method.intern
62
+ @http_method.intern
63
+ else
64
+ :post
65
+ end
66
+
67
+ @auth = case @authentication
68
+ when 'basic' then :basic
69
+ else
70
+ :none
71
+ end
72
+ end
73
+
74
+ def start
75
+ super
76
+ end
77
+
78
+ def shutdown
79
+ super
80
+ end
81
+
82
+ def format_url(tag, time, record)
83
+ @endpoint_url
84
+ end
85
+
86
+ def set_body(req, tag, time, record)
87
+ # TODO: Add avro support
88
+ if @include_tag
89
+ record['tag'] = tag
90
+ end
91
+ if @include_timestamp
92
+ record['timestamp'] = Time.now.to_i
93
+ end
94
+ if @serializer == :json_bin
95
+ set_json_body(req, record)
96
+ # elsif @serializer == :avro
97
+ # set_avro_body(req, record)
98
+ end
99
+ req
100
+ end
101
+
102
+ def set_header(req, tag, time, record)
103
+ req
104
+ end
105
+
106
+ def set_json_body(req, data)
107
+ dumped_data = Yajl.dump(data)
108
+ encoded_data = Base64.encode64(dumped_data)
109
+ req.body = Yajl.dump({ "records" => [{ "value" => encoded_data }] })
110
+ req['Content-Type'] = 'application/vnd.kafka.binary.v1+json'
111
+ end
112
+
113
+ def set_avro_body(req, data)
114
+ # TODO: Implement avro body parser
115
+ end
116
+
117
+ def create_request(tag, time, record)
118
+ url = format_url(tag, time, record)
119
+ uri = URI.parse(url)
120
+ req = Net::HTTP.const_get(@http_method.to_s.capitalize).new(uri.path)
121
+ set_body(req, tag, time, record)
122
+ set_header(req, tag, time, record)
123
+ return req, uri
124
+ end
125
+
126
+ def send_request(req, uri)
127
+ is_rate_limited = (@rate_limit_msec != 0 and not @last_request_time.nil?)
128
+ if is_rate_limited and ((Time.now.to_f - @last_request_time) * 1000.0 < @rate_limit_msec)
129
+ $log.info('Dropped request due to rate limiting')
130
+ return
131
+ end
132
+
133
+ res = nil
134
+ begin
135
+ if @auth and @auth == :basic
136
+ req.basic_auth(@username, @password)
137
+ end
138
+ @last_request_time = Time.now.to_f
139
+ https = Net::HTTP.new(uri.host, uri.port)
140
+ https.use_ssl = @use_ssl
141
+ https.ca_file = OpenSSL::X509::DEFAULT_CERT_FILE
142
+ # https.verify_mode = OpenSSL::SSL::VERIFY_PEER
143
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
144
+ res = https.start {|http| http.request(req) }
145
+ rescue IOError, EOFError, SystemCallError
146
+ # server didn't respond
147
+ $log.warn "Net::HTTP.#{req.method.capitalize} raises exception: #{$!.class}, '#{$!.message}'"
148
+ end
149
+ unless res and res.is_a?(Net::HTTPSuccess)
150
+ res_summary = if res
151
+ "#{res.code} #{res.message} #{res.body}"
152
+ else
153
+ "res=nil"
154
+ end
155
+ $log.warn "failed to #{req.method} #{uri} (#{res_summary})"
156
+ end
157
+ end
158
+
159
+ def handle_record(tag, time, record)
160
+ req, uri = create_request(tag, time, record)
161
+ send_request(req, uri)
162
+ end
163
+
164
+ def emit(tag, es, chain)
165
+ es.each do |time, record|
166
+ handle_record(tag, time, record)
167
+ end
168
+ chain.next
169
+ end
170
+ end
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'test/unit'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+
17
+ require 'fluent/test'
18
+
19
+ unless ENV.has_key?('VERBOSE')
20
+ nulllogger = Object.new
21
+ nulllogger.instance_eval {|obj|
22
+ def method_missing(method, *args)
23
+ # pass
24
+ end
25
+ }
26
+ $log = nulllogger
27
+ end
28
+
29
+ class Test::Unit::TestCase
30
+ end
31
+
32
+ require 'webrick'
33
+
34
+ # to handle POST/PUT/DELETE ...
35
+ module WEBrick::HTTPServlet
36
+ class ProcHandler < AbstractServlet
37
+ alias do_POST do_GET
38
+ alias do_PUT do_GET
39
+ alias do_DELETE do_GET
40
+ end
41
+ end
42
+
43
+ def get_code(server, port, path, headers={})
44
+ require 'net/https'
45
+ https = Net::HTTP.new(server, port)
46
+ https.use_ssl = true
47
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
48
+ https.start {|http|
49
+ http.get(path, headers).code
50
+ }
51
+ end
52
+ def get_content(server, port, path, headers={})
53
+ require 'net/https'
54
+ https = Net::HTTP.new(server, port)
55
+ https.use_ssl = true
56
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
57
+ https.start {|http|
58
+ http.get(path, headers).body
59
+ }
60
+ end
@@ -0,0 +1,270 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'yajl'
5
+ require 'fluent/test/https_output_test'
6
+ require 'fluent/plugin/out_kafka_rest'
7
+ require 'webrick'
8
+ require 'webrick/https'
9
+ require 'base64'
10
+
11
+ TEST_LISTEN_PORT = 5126
12
+
13
+
14
+ class HTTPSOutputTestBase < Test::Unit::TestCase
15
+ # setup / teardown for servers
16
+ def setup
17
+ Fluent::Test.setup
18
+ @posts = []
19
+ @puts = []
20
+ @prohibited = 0
21
+ @requests = 0
22
+ @auth = false
23
+ @dummy_server_thread = Thread.new do
24
+ srv = if ENV['VERBOSE']
25
+ WEBrick::HTTPServer.new({:BindAddress => '127.0.0.1', :Port => TEST_LISTEN_PORT, SSLEnable => true, :SSLCertName => [ [ 'CN', WEBrick::Utils::getservername ] ]})
26
+ else
27
+ logger = WEBrick::Log.new('/dev/null', WEBrick::BasicLog::DEBUG)
28
+ WEBrick::HTTPServer.new({:BindAddress => '127.0.0.1', :Port => TEST_LISTEN_PORT, :Logger => logger, :AccessLog => [], :SSLEnable => true, :SSLCertName => [ [ 'CN', WEBrick::Utils::getservername ] ]})
29
+ end
30
+ begin
31
+ # Kafka REST Proxy accepts only POST method at the moment
32
+ allowed_methods = %w(POST)
33
+ srv.mount_proc('/api/') { |req,res|
34
+ @requests += 1
35
+ unless allowed_methods.include? req.request_method
36
+ res.status = 405
37
+ res.body = 'request method mismatch'
38
+ next
39
+ end
40
+ if @auth and req.header['authorization'][0] == 'Basic YWxpY2U6c2VjcmV0IQ==' # pattern of user='alice' passwd='secret!'
41
+ # ok, authorized
42
+ elsif @auth
43
+ res.status = 403
44
+ @prohibited += 1
45
+ next
46
+ else
47
+ # ok, authorization not required
48
+ end
49
+
50
+ record = {:auth => nil}
51
+ if req.content_type == 'application/vnd.kafka.binary.v1+json'
52
+ raw_content = Yajl.load(req.body)
53
+ record[:body] = raw_content["records"].map{|s| Base64.decode64(s["value"])}
54
+ else
55
+ record[:form] = Hash[*(req.body.split('&').map{|kv|kv.split('=')}.flatten)]
56
+ end
57
+
58
+ instance_variable_get("@#{req.request_method.downcase}s").push(record)
59
+
60
+ res.status = 200
61
+ }
62
+ srv.mount_proc('/') { |req,res|
63
+ res.status = 200
64
+ res.body = 'running'
65
+ }
66
+ srv.start
67
+ ensure
68
+ srv.shutdown
69
+ end
70
+ end
71
+
72
+ # to wait completion of dummy server.start()
73
+ require 'thread'
74
+ cv = ConditionVariable.new
75
+ watcher = Thread.new {
76
+ connected = false
77
+ while not connected
78
+ begin
79
+ get_content('localhost', TEST_LISTEN_PORT, '/')
80
+ connected = true
81
+ rescue Errno::ECONNREFUSED
82
+ sleep 0.1
83
+ rescue StandardError => e
84
+ p e
85
+ sleep 0.1
86
+ end
87
+ end
88
+ cv.signal
89
+ }
90
+ mutex = Mutex.new
91
+ mutex.synchronize {
92
+ cv.wait(mutex)
93
+ }
94
+ end
95
+
96
+ def test_dummy_server
97
+ host = '127.0.0.1'
98
+ port = TEST_LISTEN_PORT
99
+ https = Net::HTTP.new(host, port)
100
+ https.use_ssl = true
101
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
102
+ client = https.start()
103
+
104
+ assert_equal '200', client.request_get('/').code
105
+ assert_equal '200', client.request_post('/api/service/metrics/hoge', 'number=1&mode=gauge').code
106
+
107
+ assert_equal 1, @posts.size
108
+
109
+ assert_equal '1', @posts[0][:form]['number']
110
+ assert_equal 'gauge', @posts[0][:form]['mode']
111
+ assert_nil @posts[0][:auth]
112
+
113
+ @auth = true
114
+
115
+ assert_equal '403', client.request_post('/api/service/metrics/pos', 'number=30&mode=gauge').code
116
+
117
+ req_with_auth = lambda do |number, mode, user, pass|
118
+ url = URI.parse("https://#{host}:#{port}/api/service/metrics/pos")
119
+ req = Net::HTTP::Post.new(url.path)
120
+ req.basic_auth user, pass
121
+ req.set_form_data({'number'=>number, 'mode'=>mode})
122
+ req
123
+ end
124
+
125
+ assert_equal '403', client.request(req_with_auth.call(500, 'count', 'alice', 'wrong password!')).code
126
+
127
+ assert_equal '403', client.request(req_with_auth.call(500, 'count', 'alice', 'wrong password!')).code
128
+
129
+ assert_equal 1, @posts.size
130
+
131
+ assert_equal '200', client.request(req_with_auth.call(500, 'count', 'alice', 'secret!')).code
132
+
133
+ assert_equal 2, @posts.size
134
+
135
+ end
136
+
137
+ def teardown
138
+ @dummy_server_thread.kill
139
+ @dummy_server_thread.join
140
+ end
141
+ end
142
+
143
+ class HTTPSOutputTest < HTTPSOutputTestBase
144
+ CONFIG = %[
145
+ use_ssl true
146
+ endpoint_url https://127.0.0.1:#{TEST_LISTEN_PORT}/api/
147
+ ]
148
+
149
+ CONFIG_JSON_BIN = %[
150
+ use_ssl true
151
+ endpoint_url https://127.0.0.1:#{TEST_LISTEN_PORT}/api/
152
+ serializer json_bin
153
+ ]
154
+
155
+ CONFIG_HTTP_ERROR = %[
156
+ use_ssl true
157
+ endpoint_url https://127.0.0.1:#{TEST_LISTEN_PORT + 1}/api/
158
+ ]
159
+
160
+ RATE_LIMIT_MSEC = 1200
161
+
162
+ CONFIG_RATE_LIMIT = %[
163
+ use_ssl true
164
+ endpoint_url https://127.0.0.1:#{TEST_LISTEN_PORT}/api/
165
+ rate_limit_msec #{RATE_LIMIT_MSEC}
166
+ ]
167
+
168
+ def create_driver(conf=CONFIG, tag='test.metrics')
169
+ Fluent::Test::OutputTestDriver.new(Fluent::KafkaRestOutput, tag).configure(conf)
170
+ end
171
+
172
+ def test_configure
173
+ d = create_driver
174
+ assert_equal "https://127.0.0.1:#{TEST_LISTEN_PORT}/api/", d.instance.endpoint_url
175
+ assert_equal :json_bin, d.instance.serializer
176
+
177
+ d = create_driver CONFIG_JSON_BIN
178
+ assert_equal "https://127.0.0.1:#{TEST_LISTEN_PORT}/api/", d.instance.endpoint_url
179
+ assert_equal :json_bin, d.instance.serializer
180
+ end
181
+
182
+ def test_emit_json_bin
183
+ binary_string = "\xe3\x81\x82".force_encoding("ascii-8bit")
184
+ d = create_driver CONFIG_JSON_BIN
185
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1, 'binary' => binary_string })
186
+ d.run
187
+
188
+ assert_equal 1, @posts.size
189
+ record = @posts[0]
190
+ body = Yajl.load(record[:body][0])
191
+
192
+ assert_equal 50, body['field1']
193
+ assert_equal 20, body['field2']
194
+ assert_equal 10, body['field3']
195
+ assert_equal 1, body['otherfield']
196
+ assert_equal binary_string, body['binary']
197
+ assert_nil record[:auth]
198
+ end
199
+
200
+ def test_http_error
201
+ d = create_driver CONFIG_HTTP_ERROR
202
+ d.emit({ 'field1' => 50 })
203
+ d.run
204
+ # drive asserts the next output chain is called;
205
+ # so no exception means our plugin handled the error
206
+
207
+ assert_equal 0, @requests
208
+ end
209
+
210
+ def test_rate_limiting
211
+ d = create_driver CONFIG_RATE_LIMIT
212
+ record = { :k => 1 }
213
+
214
+ last_emit = _current_msec
215
+ d.emit(record)
216
+ d.run
217
+
218
+ assert_equal 1, @posts.size
219
+
220
+ d.emit({})
221
+ d.run
222
+ assert last_emit + RATE_LIMIT_MSEC > _current_msec, "Still under rate limiting interval"
223
+ assert_equal 1, @posts.size
224
+
225
+ sleep (last_emit + RATE_LIMIT_MSEC - _current_msec) * 0.001
226
+
227
+ assert last_emit + RATE_LIMIT_MSEC < _current_msec, "No longer under rate limiting interval"
228
+ d.emit(record)
229
+ d.run
230
+ assert_equal 2, @posts.size
231
+ end
232
+
233
+ def _current_msec
234
+ Time.now.to_f * 1000
235
+ end
236
+
237
+ def test_auth
238
+ @auth = true # enable authentication of dummy server
239
+
240
+ d = create_driver(CONFIG, 'test.metrics')
241
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
242
+ d.run # failed in background, and output warn log
243
+
244
+ assert_equal 0, @posts.size
245
+ assert_equal 1, @prohibited
246
+
247
+ d = create_driver(CONFIG + %[
248
+ authentication basic
249
+ username alice
250
+ password wrong_password
251
+ ], 'test.metrics')
252
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
253
+ d.run # failed in background, and output warn log
254
+
255
+ assert_equal 0, @posts.size
256
+ assert_equal 2, @prohibited
257
+
258
+ d = create_driver(CONFIG + %[
259
+ authentication basic
260
+ username alice
261
+ password secret!
262
+ ], 'test.metrics')
263
+ d.emit({ 'field1' => 50, 'field2' => 20, 'field3' => 10, 'otherfield' => 1 })
264
+ d.run # failed in background, and output warn log
265
+
266
+ assert_equal 1, @posts.size
267
+ assert_equal 2, @prohibited
268
+ end
269
+
270
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-out-kafka-rest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - dobachi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yajl-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fluentd
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.10.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.10.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A fluentd output plugin for sending logs to Kafka REST Proxy
70
+ email:
71
+ - dobachi1983oss@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - CHANGELOG.md
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - fluent-plugin-out-kafka-rest.gemspec
83
+ - lib/fluent/plugin/out_kafka_rest.rb
84
+ - lib/fluent/test/https_output_test.rb
85
+ - test/plugin/test_out_https.rb
86
+ homepage: https://github.com/dobachi/fluent-plugin-out-kafka-rest
87
+ licenses: []
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.2.5
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: A fluentd output plugin for sending logs to Kafka REST Proxy
109
+ test_files:
110
+ - test/plugin/test_out_https.rb