logstash-output-file 3.0.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 816218ba76195ff85b4c30a0876ec027daa7ae89
4
- data.tar.gz: 67ef9d3a53d5b0d94906da6ffa3cc110048edf6e
3
+ metadata.gz: 7519db3db3ff8bc30ac81db904b4141f518f326b
4
+ data.tar.gz: 4e0736f6ec2d53be5b3675ac0b2a3015d5a6ac6b
5
5
  SHA512:
6
- metadata.gz: 16d18bc194e55a7de0e1195db43e4984cc09d872982d9c6df64600e2e02cef4f78b3afa4f0a73692411d14e1ee3b358963e73aa5bd3b3c2f273acd53e146eaee
7
- data.tar.gz: 2f51482a17ad47a5889a29c01e87656f3e4ef22534704a70874ddc0a6b55d0fe9afacbf90e854b96bc32757e16f428078a03aeeeea40bbaa30c948f5f96a11d0
6
+ metadata.gz: 3fdd1d4e5edcb5025969a6298ec457d315386d345ebc961d36c34455ebfa1d0d4b7bc0c3791a83ac5a0dbadc674773fb73a6bb3981b442a42f03858f602d72bf
7
+ data.tar.gz: 2e357366f22791bd8024845f2ad6ee25e69bd06803cad29957d28c2bdc7899a9ef945bc2c61a123ef79fa4f449865548495ad78b51ef7b17634fc14acf6a0a0f
@@ -1,3 +1,7 @@
1
+ ## 4.0.0
2
+ - Make 'message_format' option obsolete
3
+ - Use new Logsash 2.4/5.0 APIs for working batchwise and with shared concurrency
4
+
1
5
  ## 3.0.2
2
6
  - Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
3
7
 
@@ -17,6 +17,8 @@ require "zlib"
17
17
  # }
18
18
  # }
19
19
  class LogStash::Outputs::File < LogStash::Outputs::Base
20
+ concurrency :shared
21
+
20
22
  FIELD_REF = /%\{[^}]+\}/
21
23
 
22
24
  config_name "file"
@@ -35,13 +37,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
35
37
  # E.g: `/%{myfield}/`, `/test-%{myfield}/` are not valid paths
36
38
  config :path, :validate => :string, :required => true
37
39
 
38
- # The format to use when writing events to the file. This value
39
- # supports any string and can include `%{name}` and other dynamic
40
- # strings.
41
- #
42
- # If this setting is omitted, the full json representation of the
43
- # event will be written as a single line.
44
- config :message_format, :validate => :string, :deprecated => "You can achieve the same behavior with the 'line' codec"
40
+ config :message_format, :validate => :string, :obsolete => "You can achieve the same behavior with the 'line' codec"
45
41
 
46
42
  # Flush interval (in seconds) for flushing writes to log files.
47
43
  # 0 will flush on every message.
@@ -76,10 +72,9 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
76
72
  def register
77
73
  require "fileutils" # For mkdir_p
78
74
 
79
- workers_not_supported
80
-
81
75
  @files = {}
82
-
76
+ @io_mutex = Mutex.new
77
+
83
78
  @path = File.expand_path(path)
84
79
 
85
80
  validate_path
@@ -91,6 +86,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
91
86
  end
92
87
  @failure_path = File.join(@file_root, @filename_failure)
93
88
 
89
+
94
90
  now = Time.now
95
91
  @last_flush_cycle = now
96
92
  @last_stale_cleanup_cycle = now
@@ -101,8 +97,6 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
101
97
  @codec = LogStash::Plugin.lookup("codec", "line").new
102
98
  @codec.format = @message_format
103
99
  end
104
-
105
- @codec.on_event(&method(:write_event))
106
100
  end # def register
107
101
 
108
102
  private
@@ -125,20 +119,37 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
125
119
  end
126
120
 
127
121
  public
128
- def receive(event)
129
- @codec.encode(event)
130
- close_stale_files
122
+ def multi_receive_encoded(events_and_encoded)
123
+ encoded_by_path = Hash.new {|h,k| h[k] = []}
124
+
125
+ events_and_encoded.each do |event,encoded|
126
+ file_output_path = event_path(event)
127
+ encoded_by_path[file_output_path] << encoded
128
+ end
129
+
130
+ @io_mutex.synchronize do
131
+ encoded_by_path.each do |path,chunks|
132
+ fd = open(path)
133
+ chunks.each {|chunk| fd.write(chunk) }
134
+ fd.flush
135
+ end
136
+
137
+ close_stale_files
138
+ end
131
139
  end # def receive
132
140
 
133
141
  public
134
142
  def close
135
- @logger.debug("Close: closing files")
136
- @files.each do |path, fd|
137
- begin
138
- fd.close
139
- @logger.debug("Closed file #{path}", :fd => fd)
140
- rescue Exception => e
141
- @logger.error("Exception while flushing and closing files.", :exception => e)
143
+ @io_mutex.synchronize do
144
+ @logger.debug("Close: closing files")
145
+
146
+ @files.each do |path, fd|
147
+ begin
148
+ fd.close
149
+ @logger.debug("Closed file #{path}", :fd => fd)
150
+ rescue Exception => e
151
+ @logger.error("Exception while flushing and closing files.", :exception => e)
152
+ end
142
153
  end
143
154
  end
144
155
  end
@@ -150,7 +161,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
150
161
  end
151
162
 
152
163
  private
153
- def write_event(event, data)
164
+ def event_path(event)
154
165
  file_output_path = generate_filepath(event)
155
166
  if path_with_field_ref? && !inside_file_root?(file_output_path)
156
167
  @logger.warn("File: the event tried to write outside the files root, writing the event to the failure file", :event => event, :filename => @failure_path)
@@ -159,10 +170,8 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
159
170
  file_output_path = @failure_path
160
171
  end
161
172
  @logger.debug("File, writing event to file.", :filename => file_output_path)
162
- fd = open(file_output_path)
163
- # TODO(sissel): Check if we should rotate the file.
164
- fd.write(data)
165
- flush(fd)
173
+
174
+ file_output_path
166
175
  end
167
176
 
168
177
  private
@@ -195,10 +204,12 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
195
204
  def flush_pending_files
196
205
  return unless Time.now - @last_flush_cycle >= flush_interval
197
206
  @logger.debug("Starting flush cycle")
207
+
198
208
  @files.each do |path, fd|
199
209
  @logger.debug("Flushing file", :path => path, :fd => fd)
200
210
  fd.flush
201
211
  end
212
+
202
213
  @last_flush_cycle = Time.now
203
214
  end
204
215
 
@@ -207,6 +218,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
207
218
  def close_stale_files
208
219
  now = Time.now
209
220
  return unless now - @last_stale_cleanup_cycle >= @stale_cleanup_interval
221
+
210
222
  @logger.info("Starting stale files cleanup cycle", :files => @files)
211
223
  inactive_files = @files.select { |path, fd| not fd.active }
212
224
  @logger.debug("%d stale files found" % inactive_files.count, :inactive_files => inactive_files)
@@ -222,7 +234,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
222
234
 
223
235
  private
224
236
  def cached?(path)
225
- @files.include?(path) && !@files[path].nil?
237
+ @files.include?(path) && !@files[path].nil?
226
238
  end
227
239
 
228
240
  private
@@ -234,7 +246,9 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
234
246
  def open(path)
235
247
  if !deleted?(path) && cached?(path)
236
248
  return @files[path]
237
- elsif deleted?(path)
249
+ end
250
+
251
+ if deleted?(path)
238
252
  if @create_if_deleted
239
253
  @logger.debug("Required path was deleted, creating the file again", :path => path)
240
254
  @files.delete(path)
@@ -242,8 +256,9 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
242
256
  return @files[path] if cached?(path)
243
257
  end
244
258
  end
245
- @logger.info("Opening file", :path => path)
246
259
 
260
+ @logger.info("Opening file", :path => path)
261
+
247
262
  dir = File.dirname(path)
248
263
  if !Dir.exist?(dir)
249
264
  @logger.info("Creating directory", :directory => dir)
@@ -253,6 +268,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
253
268
  FileUtils.mkdir_p(dir)
254
269
  end
255
270
  end
271
+
256
272
  # work around a bug opening fifos (bug JRUBY-6280)
257
273
  stat = File.stat(path) rescue nil
258
274
  if stat && stat.ftype == "fifo" && LogStash::Environment.jruby?
@@ -288,6 +304,7 @@ class IOWriter
288
304
  end
289
305
  def method_missing(method_name, *args, &block)
290
306
  if @io.respond_to?(method_name)
307
+
291
308
  @io.send(method_name, *args, &block)
292
309
  else
293
310
  super
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-output-file'
4
- s.version = '3.0.2'
4
+ s.version = '4.0.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "This output will write events to files on disk"
7
7
  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"
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
21
21
 
22
22
  # Gem dependencies
23
- s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
23
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 2.0.0", "< 2.99"
24
24
  s.add_runtime_dependency 'logstash-codec-json_lines'
25
25
  s.add_runtime_dependency 'logstash-codec-line'
26
26
 
@@ -47,7 +47,7 @@ describe LogStash::Outputs::File do
47
47
 
48
48
  describe "ship lots of events to a file gzipped" do
49
49
  Stud::Temporary.file('logstash-spec-output-file') do |tmp_file|
50
- event_count = 10000 + rand(500)
50
+ event_count = 100000 + rand(500)
51
51
 
52
52
  config <<-CONFIG
53
53
  input {
@@ -125,13 +125,14 @@ describe LogStash::Outputs::File do
125
125
 
126
126
  10.times do |i|
127
127
  event = LogStash::Event.new("event_id" => i)
128
- output.receive(event)
128
+ output.multi_receive([event])
129
129
  end
130
130
  FileUtils.rm(temp_file)
131
131
  10.times do |i|
132
132
  event = LogStash::Event.new("event_id" => i+10)
133
- output.receive(event)
133
+ output.multi_receive([event])
134
134
  end
135
+
135
136
  expect(FileTest.size(temp_file.path)).to be > 0
136
137
  end
137
138
 
@@ -147,12 +148,12 @@ describe LogStash::Outputs::File do
147
148
 
148
149
  10.times do |i|
149
150
  event = LogStash::Event.new("event_id" => i)
150
- output.receive(event)
151
+ output.multi_receive([event])
151
152
  end
152
153
  FileUtils.rm(temp_file)
153
154
  10.times do |i|
154
155
  event = LogStash::Event.new("event_id" => i+10)
155
- output.receive(event)
156
+ output.multi_receive([event])
156
157
  end
157
158
  expect(FileTest.exist?(temp_file.path)).to be_falsey
158
159
  expect(FileTest.size(output.failure_path)).to be > 0
@@ -184,7 +185,7 @@ describe LogStash::Outputs::File do
184
185
 
185
186
  output = LogStash::Outputs::File.new(config)
186
187
  output.register
187
- output.receive(bad_event)
188
+ output.multi_receive([bad_event])
188
189
 
189
190
  error_file = File.join(path, config["filename_failure"])
190
191
 
@@ -202,10 +203,10 @@ describe LogStash::Outputs::File do
202
203
  output.register
203
204
 
204
205
  bad_event.set('error', encoded_once)
205
- output.receive(bad_event)
206
+ output.multi_receive([bad_event])
206
207
 
207
208
  bad_event.set('error', encoded_twice)
208
- output.receive(bad_event)
209
+ output.multi_receive([bad_event])
209
210
 
210
211
  expect(Dir.glob(File.join(path, "*")).size).to eq(2)
211
212
  output.close
@@ -218,7 +219,7 @@ describe LogStash::Outputs::File do
218
219
  output.register
219
220
 
220
221
  bad_event.set('error', '../..//test')
221
- output.receive(bad_event)
222
+ output.multi_receive([bad_event])
222
223
 
223
224
  expect(Dir.glob(File.join(path, "*")).size).to eq(1)
224
225
  output.close
@@ -235,7 +236,7 @@ describe LogStash::Outputs::File do
235
236
  config = { "path" => "#{path}/%{error}" }
236
237
  output = LogStash::Outputs::File.new(config)
237
238
  output.register
238
- output.receive(good_event)
239
+ output.multi_receive([good_event])
239
240
 
240
241
  good_file = File.join(path, good_event.get('error'))
241
242
  expect(File.exist?(good_file)).to eq(true)
@@ -254,7 +255,7 @@ describe LogStash::Outputs::File do
254
255
  config = { "path" => dynamic_path }
255
256
  output = LogStash::Outputs::File.new(config)
256
257
  output.register
257
- output.receive(good_event)
258
+ output.multi_receive([good_event])
258
259
 
259
260
  expect(File.exist?(expected_path)).to eq(true)
260
261
  output.close
@@ -276,7 +277,7 @@ describe LogStash::Outputs::File do
276
277
 
277
278
  output = LogStash::Outputs::File.new(config)
278
279
  output.register
279
- output.receive(good_event)
280
+ output.multi_receive([good_event])
280
281
 
281
282
  expect(File.exist?(expected_path)).to eq(true)
282
283
  output.close
@@ -291,7 +292,7 @@ describe LogStash::Outputs::File do
291
292
  config = { "path" => "#{path}/%{error}" }
292
293
  output = LogStash::Outputs::File.new(config)
293
294
  output.register
294
- output.receive(good_event)
295
+ output.multi_receive([good_event])
295
296
 
296
297
  good_file = File.join(path, good_event.get('error'))
297
298
  expect(File.exist?(good_file)).to eq(true)
@@ -310,7 +311,7 @@ describe LogStash::Outputs::File do
310
311
  config = { "path" => "#{path}/output.txt" }
311
312
  output = LogStash::Outputs::File.new(config)
312
313
  output.register
313
- output.receive(good_event)
314
+ output.multi_receive([good_event])
314
315
  good_file = File.join(path, 'output.txt')
315
316
  expect(File.exist?(good_file)).to eq(true)
316
317
  output.close #teardown first to allow reading the file
@@ -328,30 +329,9 @@ describe LogStash::Outputs::File do
328
329
 
329
330
  Stud::Temporary.directory do |path|
330
331
  config = { "path" => "#{path}/output.txt" }
331
- output = LogStash::Outputs::File.new(config)
332
- output.codec = LogStash::Codecs::Line.new({ "format" => "Custom format: %{message}"})
333
- output.register
334
- output.receive(good_event)
335
- good_file = File.join(path, 'output.txt')
336
- expect(File.exist?(good_file)).to eq(true)
337
- output.close #teardown first to allow reading the file
338
- File.open(good_file) {|f|
339
- line = f.readline
340
- expect(line).to eq("Custom format: hello world\n")
341
- }
342
- end
343
- end
344
- end
345
- context "when using deprecated message_format config" do
346
- it 'falls back to line codec' do
347
- good_event = LogStash::Event.new
348
- good_event.set('message', 'hello world')
349
-
350
- Stud::Temporary.directory do |path|
351
- config = { "path" => "#{path}/output.txt", "message_format" => "Custom format: %{message}" }
352
- output = LogStash::Outputs::File.new(config)
332
+ output = LogStash::Outputs::File.new(config.merge("codec" => LogStash::Codecs::Line.new({ "format" => "Custom format: %{message}"})))
353
333
  output.register
354
- output.receive(good_event)
334
+ output.multi_receive([good_event])
355
335
  good_file = File.join(path, 'output.txt')
356
336
  expect(File.exist?(good_file)).to eq(true)
357
337
  output.close #teardown first to allow reading the file
@@ -375,7 +355,7 @@ describe LogStash::Outputs::File do
375
355
  }
376
356
  output = LogStash::Outputs::File.new(config)
377
357
  output.register
378
- output.receive(good_event)
358
+ output.multi_receive([good_event])
379
359
  good_file = File.join(path, 'is/nested/output.txt')
380
360
  expect(File.exist?(good_file)).to eq(true)
381
361
  expect(File.stat(good_file).mode.to_s(8)[-3..-1]).to eq('610')
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-14 00:00:00.000000000 Z
11
+ date: 2016-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '1.60'
19
- - - "<="
18
+ version: 2.0.0
19
+ - - "<"
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.99'
22
22
  name: logstash-core-plugin-api
@@ -26,8 +26,8 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '1.60'
30
- - - "<="
29
+ version: 2.0.0
30
+ - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2.99'
33
33
  - !ruby/object:Gem::Dependency
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  version: '0'
124
124
  requirements: []
125
125
  rubyforge_project:
126
- rubygems_version: 2.6.3
126
+ rubygems_version: 2.4.8
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: This output will write events to files on disk