logstash-output-webhdfs 3.1.0-java

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,261 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/outputs/base"
4
+ require "stud/buffer"
5
+ require "logstash/outputs/webhdfs_helper"
6
+
7
+ # This plugin sends Logstash events into files in HDFS via
8
+ # the https://hadoop.apache.org/docs/r1.0.4/webhdfs.html[webhdfs] REST API.
9
+ #
10
+ # ==== Dependencies
11
+ # This plugin has no dependency on jars from hadoop, thus reducing configuration and compatibility
12
+ # problems. It uses the webhdfs gem from Kazuki Ohta and TAGOMORI Satoshi (@see: https://github.com/kzk/webhdfs).
13
+ # Optional dependencies are zlib if you use the compression functionality.
14
+ #
15
+ # ==== Operational Notes
16
+ # If you get an error like:
17
+ #
18
+ # Max write retries reached. Exception: initialize: name or service not known {:level=>:error}
19
+ #
20
+ # make sure that the hostname of your namenode is resolvable on the host running Logstash. When creating/appending
21
+ # to a file, webhdfs somtime sends a `307 TEMPORARY_REDIRECT` with the `HOSTNAME` of the machine its running on.
22
+ #
23
+ # ==== Usage
24
+ # This is an example of Logstash config:
25
+ #
26
+ # [source,ruby]
27
+ # ----------------------------------
28
+ # input {
29
+ # ...
30
+ # }
31
+ # filter {
32
+ # ...
33
+ # }
34
+ # output {
35
+ # webhdfs {
36
+ # host => "127.0.0.1" # (required)
37
+ # port => 50070 # (optional, default: 50070)
38
+ # path => "/user/logstash/dt=%{+YYYY-MM-dd}/logstash-%{+HH}.log" # (required)
39
+ # user => "hue" # (required)
40
+ # }
41
+ # }
42
+ # ----------------------------------
43
+
44
+ class LogStash::Outputs::WebHdfs < LogStash::Outputs::Base
45
+
46
+ include Stud::Buffer
47
+ include LogStash::Outputs::WebHdfsHelper
48
+
49
+ config_name "webhdfs"
50
+
51
+ MAGIC = "\x82SNAPPY\x0".force_encoding Encoding::ASCII_8BIT
52
+ DEFAULT_VERSION = 1
53
+ MINIMUM_COMPATIBLE_VERSION = 1
54
+
55
+ # The server name for webhdfs/httpfs connections.
56
+ config :host, :validate => :string, :required => true
57
+
58
+ # The server port for webhdfs/httpfs connections.
59
+ config :port, :validate => :number, :default => 50070
60
+
61
+ # Standby namenode for ha hdfs.
62
+ config :standby_host, :validate => :string, :default => false
63
+
64
+ # Standby namenode port for ha hdfs.
65
+ config :standby_port, :validate => :number, :default => 50070
66
+
67
+ # The Username for webhdfs.
68
+ config :user, :validate => :string, :required => true
69
+
70
+ # The path to the file to write to. Event fields can be used here,
71
+ # as well as date fields in the joda time format, e.g.:
72
+ # `/user/logstash/dt=%{+YYYY-MM-dd}/%{@source_host}-%{+HH}.log`
73
+ config :path, :validate => :string, :required => true
74
+
75
+ # Sending data to webhdfs in x seconds intervals.
76
+ config :idle_flush_time, :validate => :number, :default => 1
77
+
78
+ # Sending data to webhdfs if event count is above, even if `store_interval_in_secs` is not reached.
79
+ config :flush_size, :validate => :number, :default => 500
80
+
81
+ # WebHdfs open timeout, default 30s.
82
+ config :open_timeout, :validate => :number, :default => 30
83
+
84
+ # The WebHdfs read timeout, default 30s.
85
+ config :read_timeout, :validate => :number, :default => 30
86
+
87
+ # Use httpfs mode if set to true, else webhdfs.
88
+ config :use_httpfs, :validate => :boolean, :default => false
89
+
90
+ # Avoid appending to same file in multiple threads.
91
+ # This solves some problems with multiple logstash output threads and locked file leases in webhdfs.
92
+ # If this option is set to true, %{[@metadata][thread_id]} needs to be used in path config settting.
93
+ config :single_file_per_thread, :validate => :boolean, :default => false
94
+
95
+ # Retry some known webhdfs errors. These may be caused by race conditions when appending to same file, etc.
96
+ config :retry_known_errors, :validate => :boolean, :default => true
97
+
98
+ # How long should we wait between retries.
99
+ config :retry_interval, :validate => :number, :default => 0.5
100
+
101
+ # How many times should we retry. If retry_times is exceeded, an error will be logged and the event will be discarded.
102
+ config :retry_times, :validate => :number, :default => 5
103
+
104
+ # Compress output. One of ['none', 'snappy', 'gzip']
105
+ config :compression, :validate => ["none", "snappy", "gzip"], :default => "none"
106
+
107
+ # Set snappy chunksize. Only neccessary for stream format. Defaults to 32k. Max is 65536
108
+ # @see http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
109
+ config :snappy_bufsize, :validate => :number, :default => 32768
110
+
111
+ # Set snappy format. One of "stream", "file". Set to stream to be hive compatible.
112
+ config :snappy_format, :validate => ["stream", "file"], :default => "stream"
113
+
114
+ # Set kerberos authentication.
115
+ config :use_kerberos_auth, :validate => :boolean, :default => false
116
+
117
+ # Set kerberos keytab file. Note that the gssapi library needs to be available to use this.
118
+ config :kerberos_keytab, :validate => :string
119
+
120
+ # Set ssl authentication. Note that the openssl library needs to be available to use this.
121
+ config :use_ssl_auth, :validate => :boolean, :default => false
122
+
123
+ # Set ssl key file.
124
+ config :ssl_key, :validate => :string
125
+
126
+ # Set ssl cert file.
127
+ config :ssl_cert, :validate => :string
128
+
129
+ ## Set codec.
130
+ default :codec, 'line'
131
+
132
+ public
133
+
134
+ def register
135
+ load_module('webhdfs')
136
+
137
+ # in case of snappy the jars are already included and no wrapper module has to be loaded.
138
+ if @compression == "gzip"
139
+ load_module('zlib')
140
+ end
141
+ @main_namenode_failed = false
142
+ @standby_client = false
143
+ @files = {}
144
+ # Create and test standby client if configured.
145
+ if @standby_host
146
+ @standby_client = prepare_client(@standby_host, @standby_port, @user)
147
+ begin
148
+ test_client(@standby_client)
149
+ rescue => e
150
+ logger.warn("Could not connect to standby namenode #{@standby_client.host}. Error: #{e.message}. Trying main webhdfs namenode.")
151
+ end
152
+ end
153
+ @client = prepare_client(@host, @port, @user)
154
+ begin
155
+ test_client(@client)
156
+ rescue => e
157
+ # If no standy host is configured, we need to exit here.
158
+ if not @standby_host
159
+ raise
160
+ else
161
+ # If a standby host is configured, try this before giving up.
162
+ logger.error("Could not connect to #{@client.host}:#{@client.port}. Error: #{e.message}")
163
+ do_failover
164
+ end
165
+ end
166
+ # Make sure @path contains %{[@metadata][thread_id]} format value if @single_file_per_thread is set to true.
167
+ if @single_file_per_thread and !@path.include? "%{[@metadata][thread_id]}"
168
+ @logger.error("Please set %{[@metadata][thread_id]} format value in @path if @single_file_per_thread is active.")
169
+ raise LogStash::ConfigurationError
170
+ end
171
+ buffer_initialize(
172
+ :max_items => @flush_size,
173
+ :max_interval => @idle_flush_time,
174
+ :logger => @logger
175
+ )
176
+ @codec.on_event do |event, encoded_event|
177
+ encoded_event
178
+ end
179
+ end # def register
180
+
181
+ def receive(event)
182
+ buffer_receive(event)
183
+ end # def receive
184
+
185
+ def flush(events=nil, close=false)
186
+ return if not events
187
+ newline = "\n"
188
+ output_files = Hash.new { |hash, key| hash[key] = "" }
189
+ events.collect do |event|
190
+ # Add thread_id to event metadata to be used as format value in path configuration.
191
+ if @single_file_per_thread
192
+ event.set("[@metadata][thread_id]", Thread.current.object_id.to_s)
193
+ end
194
+ path = event.sprintf(@path)
195
+ event_as_string = @codec.encode(event)
196
+ event_as_string += newline unless event_as_string.end_with? newline
197
+ output_files[path] << event_as_string
198
+ end
199
+ output_files.each do |path, output|
200
+ if @compression == "gzip"
201
+ path += ".gz"
202
+ output = compress_gzip(output)
203
+ elsif @compression == "snappy"
204
+ path += ".snappy"
205
+ if @snappy_format == "file"
206
+ output = compress_snappy_file(output)
207
+ elsif
208
+ output = compress_snappy_stream(output)
209
+ end
210
+ end
211
+ write_data(path, output)
212
+ end
213
+ end
214
+
215
+ def write_data(path, data)
216
+ # Retry max_retry times. This can solve problems like leases being hold by another process. Sadly this is no
217
+ # KNOWN_ERROR in rubys webhdfs client.
218
+ write_tries = 0
219
+ begin
220
+ # Try to append to already existing file, which will work most of the times.
221
+ @client.append(path, data)
222
+ # File does not exist, so create it.
223
+ rescue WebHDFS::FileNotFoundError
224
+ # Add snappy header if format is "file".
225
+ if @compression == "snappy" and @snappy_format == "file"
226
+ @client.create(path, get_snappy_header! + data)
227
+ elsif
228
+ @client.create(path, data)
229
+ end
230
+ # Handle other write errors and retry to write max. @retry_times.
231
+ rescue => e
232
+ # Handle StandbyException and do failover. Still we want to exit if write_tries >= @retry_times.
233
+ if @standby_client && (e.message.match(/Failed to connect to host/) || e.message.match(/StandbyException/))
234
+ do_failover
235
+ write_tries += 1
236
+ retry
237
+ end
238
+ if write_tries < @retry_times
239
+ @logger.warn("webhdfs write caused an exception: #{e.message}. Maybe you should increase retry_interval or reduce number of workers. Retrying...")
240
+ sleep(@retry_interval * write_tries)
241
+ write_tries += 1
242
+ retry
243
+ else
244
+ # Issue error after max retries.
245
+ @logger.error("Max write retries reached. Events will be discarded. Exception: #{e.message}")
246
+ end
247
+ end
248
+ end
249
+
250
+ def do_failover
251
+ if not @standby_client
252
+ return
253
+ end
254
+ @logger.warn("Failing over from #{@client.host}:#{@client.port} to #{@standby_client.host}:#{@standby_client.port}.")
255
+ @client, @standby_client = @standby_client, @client
256
+ end
257
+
258
+ def close
259
+ buffer_flush(:final => true)
260
+ end # def close
261
+ end # class LogStash::Outputs::WebHdfs
@@ -0,0 +1,119 @@
1
+ require "logstash/namespace"
2
+
3
+ module LogStash
4
+ module Outputs
5
+ module WebHdfsHelper
6
+
7
+ # Load a module
8
+ # @param module_name [String] A module name
9
+ # @raise [LoadError] If the module count not be loaded
10
+ def load_module(module_name)
11
+ begin
12
+ require module_name
13
+ rescue LoadError
14
+ @logger.error("Module #{module_name} could not be loaded.")
15
+ raise
16
+ end
17
+ end
18
+
19
+ # Setup a WebHDFS client
20
+ # @param host [String] The WebHDFS location
21
+ # @param port [Number] The port used to do the communication
22
+ # @param username [String] A valid HDFS user
23
+ # @return [WebHDFS] An setup client instance
24
+ def prepare_client(host, port, username)
25
+ client = WebHDFS::Client.new(host, port, username)
26
+ if @use_kerberos_auth
27
+ require 'gssapi'
28
+ client.kerberos = true
29
+ client.kerberos_keytab = @kerberos_keytab
30
+ end
31
+ if @use_ssl_auth
32
+ require 'openssl'
33
+ client.ssl = true
34
+ client.ssl_key = OpenSSL::PKey::RSA.new(open(@ssl_key))
35
+ client.ssl_cert = OpenSSL::X509::Certificate.new(open(@ssl_cert))
36
+ end
37
+ client.httpfs_mode = @use_httpfs
38
+ client.open_timeout = @open_timeout
39
+ client.read_timeout = @read_timeout
40
+ client.retry_known_errors = @retry_known_errors
41
+ client.retry_interval = @retry_interval if @retry_interval
42
+ client.retry_times = @retry_times if @retry_times
43
+ client
44
+ end
45
+ # Test client connection.
46
+ #@param client [WebHDFS] webhdfs client object.
47
+ def test_client(client)
48
+ begin
49
+ client.list('/')
50
+ rescue => e
51
+ @logger.error("Webhdfs check request failed. (namenode: #{client.host}:#{client.port}, Exception: #{e.message})")
52
+ raise
53
+ end
54
+ end
55
+
56
+ # Compress data using the gzip methods.
57
+ # @param data [String] stream of data to be compressed
58
+ # @return [String] the compressed stream of data
59
+ def compress_gzip(data)
60
+ buffer = StringIO.new('','w')
61
+ compressor = Zlib::GzipWriter.new(buffer)
62
+ begin
63
+ compressor.write(data)
64
+ ensure
65
+ compressor.close()
66
+ end
67
+ buffer.string
68
+ end
69
+
70
+ # Compress snappy file.
71
+ # @param data [binary] stream of data to be compressed
72
+ # @return [String] the compressed stream of data
73
+ def compress_snappy_file(data)
74
+ # Encode data to ASCII_8BIT (binary)
75
+ data = data.encode(Encoding::ASCII_8BIT, "binary", :undef => :replace)
76
+ buffer = StringIO.new('', 'w')
77
+ buffer.set_encoding(Encoding::ASCII_8BIT)
78
+ compressed = snappy_deflate(data)
79
+ buffer << [compressed.size, compressed].pack("Na*")
80
+ buffer.string
81
+ end
82
+
83
+ def snappy_deflate(input)
84
+ raw_bytes = input.bytes.to_java :byte # to needed to force the instance to be a byte[] and match arguments type in subsequent Snappy call
85
+
86
+ compressed = Java::org.xerial.snappy.Snappy.compress(raw_bytes)
87
+
88
+ String.from_java_bytes(compressed)
89
+ end
90
+
91
+ def snappy_inflate(input)
92
+ raw_bytes = input.bytes.to_java :byte # to needed to force the instance to be a byte[] and match arguments type in subsequent Snappy call
93
+ uncompressed_length = Java::org.xerial.snappy.Snappy.uncompressedLength(raw_bytes, 0, raw_bytes.length)
94
+ uncompressed = Java::byte[uncompressed_length].new
95
+ Java::org.xerial.snappy.Snappy.uncompress(raw_bytes, 0, raw_bytes.length, uncompressed, 0)
96
+
97
+ String.from_java_bytes(uncompressed)
98
+ end
99
+
100
+ def compress_snappy_stream(data)
101
+ # Encode data to ASCII_8BIT (binary)
102
+ data = data.encode(Encoding::ASCII_8BIT, "binary", :undef => :replace)
103
+ buffer = StringIO.new
104
+ buffer.set_encoding(Encoding::ASCII_8BIT)
105
+ chunks = data.scan(/.{1,#{@snappy_bufsize}}/m)
106
+ chunks.each do |chunk|
107
+ compressed = snappy_deflate(chunk)
108
+ buffer << [chunk.size, compressed.size, compressed].pack("NNa*")
109
+ end
110
+ return buffer.string
111
+ end
112
+
113
+ def get_snappy_header!
114
+ [MAGIC, DEFAULT_VERSION, MINIMUM_COMPATIBLE_VERSION].pack("a8NN")
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,4 @@
1
+ # AUTOGENERATED BY THE GRADLE SCRIPT. DO NOT EDIT.
2
+
3
+ require 'jar_dependencies'
4
+ require_jar('org.xerial.snappy', 'snappy-java', '1.1.10.5')
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ Gem::Specification.new do |s|
3
+
4
+ s.name = 'logstash-output-webhdfs'
5
+ s.version = '3.1.0'
6
+ s.licenses = ['Apache License (2.0)']
7
+ s.summary = "Sends Logstash events to HDFS using the `webhdfs` REST API"
8
+ s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
9
+ s.authors = ["Björn Puttmann, loshkovskyi, Elastic"]
10
+ s.email = 'b.puttmann@dbap.de'
11
+ s.homepage = "http://www.dbap.de"
12
+ s.require_paths = ['lib', 'vendor/jar-dependencies']
13
+
14
+ # Files
15
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
16
+
17
+ # Tests
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+
20
+ # Special flag to let us know this is actually a logstash plugin
21
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
22
+
23
+ # Gem dependencies
24
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
25
+ s.add_runtime_dependency 'webhdfs'
26
+ s.add_development_dependency 'logstash-devutils'
27
+
28
+ s.add_development_dependency 'logstash-codec-line'
29
+ s.add_development_dependency 'logstash-codec-json'
30
+
31
+ s.platform = 'java'
32
+ end
@@ -0,0 +1,130 @@
1
+ # encoding: utf-8
2
+ require 'logstash/devutils/rspec/spec_helper'
3
+ require 'logstash/outputs/webhdfs'
4
+ require 'webhdfs'
5
+ require 'json'
6
+
7
+ describe LogStash::Outputs::WebHdfs, :integration => true do
8
+ let(:host) { 'localhost' }
9
+ let(:port) { 50070 }
10
+ let(:user) { 'test' }
11
+ let(:test_file) { '/user/' + user + '/%{host}.test' }
12
+ let(:hdfs_file_name) { 'user/' + user + '/localhost.test' }
13
+
14
+ let(:config) { { 'host' => host, 'user' => user, 'path' => test_file, 'compression' => 'none' } }
15
+
16
+ subject(:plugin) { LogStash::Plugin.lookup("output", "webhdfs").new(config) }
17
+
18
+ let(:webhdfs_client) { WebHDFS::Client.new(host, port, user) }
19
+
20
+ let(:event) { LogStash::Event.new('message' => 'Hello world!', 'source' => 'out of the blue',
21
+ 'type' => 'generator', 'host' => 'localhost' ) }
22
+
23
+ describe "register and close" do
24
+
25
+ it 'should register with default values' do
26
+ expect { subject.register }.to_not raise_error
27
+ end
28
+
29
+ end
30
+
31
+ describe '#write' do
32
+
33
+ let(:config) { { 'host' => host, 'user' => user, 'flush_size' => 10,
34
+ 'path' => test_file, 'compression' => 'none' } }
35
+
36
+ after(:each) do
37
+ webhdfs_client.delete(hdfs_file_name)
38
+ end
39
+
40
+ describe "writing plain files" do
41
+
42
+ before(:each) do
43
+ subject.register
44
+ subject.receive(event)
45
+ subject.close
46
+ end
47
+
48
+ it 'should use the correct filename pattern' do
49
+ expect { webhdfs_client.read(hdfs_file_name) }.to_not raise_error
50
+ end
51
+
52
+ context "using the line codec without format" do
53
+
54
+ let(:config) { { 'host' => host, 'user' => user, 'flush_size' => 10,
55
+ 'path' => test_file, 'compression' => 'none', 'codec' => 'line' } }
56
+
57
+ it 'should match the event data' do
58
+ expect(webhdfs_client.read(hdfs_file_name).strip()).to eq(event.to_s)
59
+ end
60
+
61
+ end
62
+
63
+ context "using the json codec" do
64
+
65
+ let(:config) { { 'host' => host, 'user' => user, 'flush_size' => 10,
66
+ 'path' => test_file, 'compression' => 'none', 'codec' => 'json' } }
67
+
68
+
69
+ it 'should match the event data' do
70
+ expect(webhdfs_client.read(hdfs_file_name).strip()).to eq(event.to_json)
71
+ end
72
+
73
+ end
74
+
75
+ context "when flushing events" do
76
+
77
+ let(:config) { { 'host' => host, 'user' => user, 'flush_size' => 10, 'idle_flush_time' => 2,
78
+ 'path' => test_file, 'compression' => 'none', 'codec' => 'json' } }
79
+
80
+ before(:each) do
81
+ webhdfs_client.delete(hdfs_file_name)
82
+ end
83
+
84
+ it 'should flush after configured idle time' do
85
+ subject.register
86
+ subject.receive(event)
87
+ expect { webhdfs_client.read(hdfs_file_name) }.to raise_error(error=WebHDFS::FileNotFoundError)
88
+ sleep 3
89
+ expect { webhdfs_client.read(hdfs_file_name) }.to_not raise_error
90
+ expect(webhdfs_client.read(hdfs_file_name).strip()).to eq(event.to_json)
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ describe "#compression" do
98
+
99
+ before(:each) do
100
+ subject.register
101
+ for _ in 0...500
102
+ subject.receive(event)
103
+ end
104
+ subject.close
105
+ end
106
+
107
+ context "when using no compression" do
108
+
109
+ let(:config) { { 'host' => host, 'user' => user, 'flush_size' => 10,
110
+ 'path' => test_file, 'compression' => 'none', 'codec' => 'line' } }
111
+
112
+ it 'should write some messages uncompressed' do
113
+ expect(webhdfs_client.read(hdfs_file_name).lines.count).to eq(500)
114
+ end
115
+
116
+ end
117
+
118
+ context "when using gzip compression" do
119
+
120
+ let(:config) { { 'host' => host, 'user' => user,
121
+ 'path' => test_file, 'compression' => 'gzip', 'codec' => 'line' } }
122
+
123
+ it 'should write some messages gzip compressed' do
124
+ expect(Zlib::Inflate.new(window_bits=47).inflate(webhdfs_client.read("#{hdfs_file_name}.gz")).lines.count ).to eq(500)
125
+ webhdfs_client.delete("#{hdfs_file_name}.gz")
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ require 'logstash/devutils/rspec/spec_helper'
3
+ require 'logstash/outputs/webhdfs'
4
+ require 'webhdfs'
5
+ require 'logstash-output-webhdfs_jars'
6
+
7
+
8
+ describe "webhdfs helpers" do
9
+
10
+ let(:host) { 'localhost' }
11
+ let(:user) { 'hadoop' }
12
+ let(:path) { '/test.log' }
13
+
14
+ let(:config) { { 'host' =>host, 'user' => user, 'path' => path, 'compression' => 'none' } }
15
+
16
+ let(:sample_data) { "Something very very very long to compress" }
17
+
18
+ subject(:plugin) { LogStash::Plugin.lookup("output", "webhdfs").new(config) }
19
+
20
+ context "when compressing using vendor snappy" do
21
+ it "should return a valid byte array" do
22
+ compressed = subject.compress_snappy_file(sample_data)
23
+
24
+ expect(compressed).not_to be(:nil)
25
+ end
26
+
27
+ it "should contains all the data" do
28
+ compressed = subject.compress_snappy_file(sample_data)
29
+
30
+ #remove the length integer (32 bit) added by compress_snappy_file, 4 bytes, from compressed
31
+ uncompressed = subject.snappy_inflate(compressed[4..-1])
32
+
33
+ expect(uncompressed).to eq(sample_data)
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ require 'logstash/devutils/rspec/spec_helper'
3
+ require 'logstash/outputs/webhdfs'
4
+ require 'webhdfs'
5
+ require 'json'
6
+
7
+ describe 'outputs/webhdfs' do
8
+
9
+ let(:host) { 'localhost' }
10
+ let(:user) { 'hadoop' }
11
+ let(:path) { '/test.log' }
12
+
13
+ let(:config) { { 'host' =>host, 'user' => user, 'path' => path, 'compression' => 'none' } }
14
+
15
+ subject(:plugin) { LogStash::Plugin.lookup("output", "webhdfs").new(config) }
16
+
17
+ describe '#initializing' do
18
+
19
+ it 'should fail to register without required values' do
20
+ plugin = LogStash::Plugin.lookup("output", "webhdfs")
21
+ expect { plugin.new }.to raise_error(error=LogStash::ConfigurationError)
22
+ end
23
+
24
+ context "default values" do
25
+
26
+ it 'should have default port' do
27
+ expect(subject.port).to eq(50070)
28
+ end
29
+
30
+ it 'should have default idle_flush_time' do
31
+ expect(subject.idle_flush_time).to eq(1)
32
+ end
33
+ it 'should have default flush_size' do
34
+ expect(subject.flush_size).to eq(500)
35
+ end
36
+
37
+ it 'should have default open_timeout' do
38
+ expect(subject.open_timeout).to eq(30)
39
+ end
40
+
41
+ it 'should have default read_timeout' do
42
+ expect(subject.read_timeout).to eq(30)
43
+ end
44
+
45
+ it 'should have default use_httpfs' do
46
+ expect(subject.use_httpfs).to eq(false)
47
+ end
48
+
49
+ it 'should have default retry_known_errors' do
50
+ expect(subject.retry_known_errors).to eq(true)
51
+ end
52
+
53
+ it 'should have default retry_interval' do
54
+ expect(subject.retry_interval).to eq(0.5)
55
+ end
56
+
57
+ it 'should have default retry_times' do
58
+ expect(subject.retry_times).to eq(5)
59
+ end
60
+
61
+ it 'should have default snappy_bufsize' do
62
+ expect(subject.snappy_bufsize).to eq(32768)
63
+ end
64
+
65
+ it 'should have default snappy_format' do
66
+ expect(subject.snappy_format).to eq('stream')
67
+ end
68
+
69
+ end
70
+ end
71
+ end