logstash-input-file 4.1.17 → 4.1.18

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 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