logstash-input-file 4.1.17 → 4.1.18

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
  SHA256:
3
- metadata.gz: cdb425f23de3ef4ccd1a1358ce48789001145a9a4620405bac4dc6a75d2b7f69
4
- data.tar.gz: b7c856e75936d99912a8a517b81e23be1603e4032a255e6340b2c4da7faa6639
3
+ metadata.gz: dc2b7f39bcc8e3dfb894ea72af1b07e78fff73bf97ad12614a9ec440fed0c2d1
4
+ data.tar.gz: 6715064a8a25a13538cc07216f5c479f79dd2d3ba73a267377cd357c6e27ea8d
5
5
  SHA512:
6
- metadata.gz: d0641b7f747964983a6f2e3b8c68a19efc74bb085e6a635cc110cd8d1c43efe330a899a951933f228cf59015785cc00730bd196a84a63dd36241045d36614ebf
7
- data.tar.gz: 834e9ad07ed15beaee47e0cd3d6d6f5e5494e41a6d5a2f4871f79df4d63837ef3c480f033eaac0d092794f4c0a36fe4d3466728d98cf2ad55ac564cd8dec0f4f
6
+ metadata.gz: fbc9d7cd0f7b50be21721bfe0cb7c26a1e87a1f5697f4a01f14dcdc14a8449c9a9d14ddec58f3ec1b8bd611e624855b538155af8f2924604fb9f1cf120de4e22
7
+ data.tar.gz: 44b4bdb7b356a6494cb1cde6bf48395d61222234d2ec6cfb134d551a20ed1ab08043b23266b5bc75854b85577d22a1fd36d5b40c17213eb10df68f2903086146
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 4.1.18
2
+ - Fix: release watched files on completion (in read-mode) [#271](https://github.com/logstash-plugins/logstash-input-file/pull/271)
3
+
1
4
  ## 4.1.17
2
5
  - Added configuration setting `check_archive_validity` settings to enable
3
6
  gzipped files verification, issue
@@ -22,6 +22,9 @@ module FileWatch module ReadMode module Handlers
22
22
  sincedb_collection.reading_completed(key)
23
23
  sincedb_collection.clear_watched_file(key)
24
24
  watched_file.listener.deleted
25
+ # NOTE: on top of un-watching we should also remove from the watched files collection
26
+ # if the file is getting deleted (on completion), that part currently resides in
27
+ # DeleteCompletedFileHandler - triggered above using `watched_file.listener.deleted`
25
28
  watched_file.unwatch
26
29
  end
27
30
  end
@@ -67,7 +67,7 @@ module FileWatch
67
67
  watched_files = @watched_files_collection.values
68
68
  @processor.process_all_states(watched_files)
69
69
  ensure
70
- @watched_files_collection.delete(@processor.deletable_filepaths)
70
+ @watched_files_collection.remove_paths(@processor.deletable_filepaths)
71
71
  @processor.deletable_filepaths.clear
72
72
  end
73
73
  end # def each
@@ -15,13 +15,17 @@ module FileWatch
15
15
  @sort_method.call
16
16
  end
17
17
 
18
- def delete(paths)
19
- Array(paths).each do |f|
20
- index = @pointers.delete(f)
21
- @files.delete_at(index)
22
- refresh_pointers
18
+ def remove_paths(paths)
19
+ removed_files = Array(paths).map do |path|
20
+ index = @pointers.delete(path)
21
+ if index
22
+ watched_file = @files.delete_at(index)
23
+ refresh_pointers
24
+ watched_file
25
+ end
23
26
  end
24
27
  @sort_method.call
28
+ removed_files
25
29
  end
26
30
 
27
31
  def close_all
Binary file
@@ -2,8 +2,13 @@
2
2
 
3
3
  module LogStash module Inputs
4
4
  class DeleteCompletedFileHandler
5
+ def initialize(watch)
6
+ @watch = watch
7
+ end
8
+
5
9
  def handle(path)
6
10
  Pathname.new(path).unlink rescue nil
11
+ @watch.watched_files_collection.remove_paths([path])
7
12
  end
8
13
  end
9
14
  end end
@@ -6,6 +6,7 @@ require "logstash/codecs/identity_map_codec"
6
6
  require "pathname"
7
7
  require "socket" # for Socket.gethostname
8
8
  require "fileutils"
9
+ require "concurrent/atomic/atomic_reference"
9
10
 
10
11
  require_relative "file/patch"
11
12
  require_relative "file_listener"
@@ -247,6 +248,9 @@ class File < LogStash::Inputs::Base
247
248
  end
248
249
  end
249
250
 
251
+ # @private used in specs
252
+ attr_reader :watcher
253
+
250
254
  def register
251
255
  require "addressable/uri"
252
256
  require "digest/md5"
@@ -274,8 +278,6 @@ class File < LogStash::Inputs::Base
274
278
  :check_archive_validity => @check_archive_validity,
275
279
  }
276
280
 
277
- @completed_file_handlers = []
278
-
279
281
  @path.each do |path|
280
282
  if Pathname.new(path).relative?
281
283
  raise ArgumentError.new("File paths must be absolute, relative path specified: #{path}")
@@ -319,15 +321,10 @@ class File < LogStash::Inputs::Base
319
321
  @watcher_class = FileWatch::ObservingTail
320
322
  else
321
323
  @watcher_class = FileWatch::ObservingRead
322
- if @file_completed_action.include?('log')
323
- @completed_file_handlers << LogCompletedFileHandler.new(@file_completed_log_path)
324
- end
325
- if @file_completed_action.include?('delete')
326
- @completed_file_handlers << DeleteCompletedFileHandler.new
327
- end
328
324
  end
329
325
  @codec = LogStash::Codecs::IdentityMapCodec.new(@codec)
330
326
  @completely_stopped = Concurrent::AtomicBoolean.new
327
+ @queue = Concurrent::AtomicReference.new
331
328
  end # def register
332
329
 
333
330
  def completely_stopped?
@@ -344,13 +341,25 @@ class File < LogStash::Inputs::Base
344
341
  # if the pipeline restarts this input,
345
342
  # make sure previous files are closed
346
343
  stop
344
+
347
345
  @watcher = @watcher_class.new(@filewatch_config)
346
+
347
+ @completed_file_handlers = []
348
+ if read_mode?
349
+ if @file_completed_action.include?('log')
350
+ @completed_file_handlers << LogCompletedFileHandler.new(@file_completed_log_path)
351
+ end
352
+ if @file_completed_action.include?('delete')
353
+ @completed_file_handlers << DeleteCompletedFileHandler.new(@watcher.watch)
354
+ end
355
+ end
356
+
348
357
  @path.each { |path| @watcher.watch_this(path) }
349
358
  end
350
359
 
351
360
  def run(queue)
352
361
  start_processing
353
- @queue = queue
362
+ @queue.set queue
354
363
  @watcher.subscribe(self) # halts here until quit is called
355
364
  # last action of the subscribe call is to write the sincedb
356
365
  exit_flush
@@ -361,7 +370,7 @@ class File < LogStash::Inputs::Base
361
370
  event.set("[@metadata][host]", @host)
362
371
  event.set("host", @host) unless event.include?("host")
363
372
  decorate(event)
364
- @queue << event
373
+ @queue.get << event
365
374
  end
366
375
 
367
376
  def handle_deletable_path(path)
@@ -382,6 +391,11 @@ class File < LogStash::Inputs::Base
382
391
  end
383
392
  end
384
393
 
394
+ # @private used in specs
395
+ def queue
396
+ @queue.get
397
+ end
398
+
385
399
  private
386
400
 
387
401
  def build_sincedb_base_from_settings(settings)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-file'
4
- s.version = '4.1.17'
4
+ s.version = '4.1.18'
5
5
  s.licenses = ['Apache-2.0']
6
6
  s.summary = "Streams events from files"
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"
@@ -85,9 +85,9 @@ module FileWatch
85
85
  collection.add(wf3)
86
86
  expect(collection.keys).to eq([filepath1, filepath2, filepath3])
87
87
 
88
- collection.delete([filepath2,filepath3])
88
+ collection.remove_paths([filepath2,filepath3])
89
89
  expect(collection.keys).to eq([filepath1])
90
-
90
+ expect(collection.values.size).to eq 1
91
91
  end
92
92
  end
93
93
 
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "logstash/devutils/rspec/spec_helper"
4
+ require "rspec/wait"
4
5
  require "rspec_sequencing"
5
6
 
6
7
  module FileInput
@@ -247,4 +247,79 @@ describe LogStash::Inputs::File do
247
247
  end
248
248
  end
249
249
  end
250
+
251
+ let(:temp_directory) { Stud::Temporary.directory }
252
+ let(:interval) { 0.1 }
253
+ let(:options) do
254
+ {
255
+ 'mode' => "read",
256
+ 'path' => "#{temp_directory}/*",
257
+ 'stat_interval' => interval,
258
+ 'discover_interval' => interval,
259
+ 'sincedb_path' => "#{temp_directory}/.sincedb",
260
+ 'sincedb_write_interval' => interval
261
+ }
262
+ end
263
+
264
+ let(:queue) { Queue.new }
265
+ let(:plugin) { LogStash::Inputs::File.new(options) }
266
+
267
+ describe 'delete on complete' do
268
+
269
+ let(:options) do
270
+ super.merge({ 'file_completed_action' => "delete", 'exit_after_read' => false })
271
+ end
272
+
273
+ let(:sample_file) { File.join(temp_directory, "sample.log") }
274
+
275
+ before do
276
+ plugin.register
277
+ @run_thread = Thread.new(plugin) do |plugin|
278
+ Thread.current.abort_on_exception = true
279
+ plugin.run queue
280
+ end
281
+
282
+ File.open(sample_file, 'w') { |fd| fd.write("sample-content\n") }
283
+
284
+ wait_for_start_processing(@run_thread)
285
+ end
286
+
287
+ after { plugin.stop }
288
+
289
+ it 'processes a file' do
290
+ wait_for_file_removal(sample_file) # watched discovery
291
+
292
+ expect( plugin.queue.size ).to eql 1
293
+ event = plugin.queue.pop
294
+ expect( event.get('message') ).to eql 'sample-content'
295
+ end
296
+
297
+ it 'removes watched file from collection' do
298
+ wait_for_file_removal(sample_file) # watched discovery
299
+ sleep(0.25) # give CI some space to execute the removal
300
+ # TODO shouldn't be necessary once WatchedFileCollection does proper locking
301
+ watched_files = plugin.watcher.watch.watched_files_collection
302
+ expect( watched_files ).to be_empty
303
+ end
304
+
305
+ private
306
+
307
+ def wait_for_start_processing(run_thread, timeout: 1.0)
308
+ begin
309
+ Timeout.timeout(timeout) do
310
+ sleep(0.01) while run_thread.status != 'sleep'
311
+ sleep(timeout) unless plugin.queue
312
+ end
313
+ rescue Timeout::Error
314
+ raise "plugin did not start processing (timeout: #{timeout})" unless plugin.queue
315
+ else
316
+ raise "plugin did not start processing" unless plugin.queue
317
+ end
318
+ end
319
+
320
+ def wait_for_file_removal(path, timeout: 3 * interval)
321
+ wait(timeout).for { File.exist?(path) }.to be_falsey
322
+ end
323
+
324
+ end
250
325
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.17
4
+ version: 4.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-03 00:00:00.000000000 Z
11
+ date: 2020-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement