logstash-input-file 4.1.18 → 4.2.4

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/README.md +1 -1
  4. data/lib/filewatch/discoverer.rb +9 -8
  5. data/lib/filewatch/observing_base.rb +1 -12
  6. data/lib/filewatch/processor.rb +55 -0
  7. data/lib/filewatch/read_mode/handlers/base.rb +12 -11
  8. data/lib/filewatch/read_mode/handlers/read_file.rb +23 -8
  9. data/lib/filewatch/read_mode/handlers/read_zip_file.rb +8 -6
  10. data/lib/filewatch/read_mode/processor.rb +22 -36
  11. data/lib/filewatch/settings.rb +1 -2
  12. data/lib/filewatch/sincedb_collection.rb +40 -41
  13. data/lib/filewatch/sincedb_record_serializer.rb +5 -11
  14. data/lib/filewatch/stat/generic.rb +8 -13
  15. data/lib/filewatch/stat/windows_path.rb +7 -9
  16. data/lib/filewatch/tail_mode/handlers/base.rb +32 -23
  17. data/lib/filewatch/tail_mode/handlers/delete.rb +2 -4
  18. data/lib/filewatch/tail_mode/handlers/shrink.rb +2 -3
  19. data/lib/filewatch/tail_mode/handlers/unignore.rb +4 -4
  20. data/lib/filewatch/tail_mode/processor.rb +47 -54
  21. data/lib/filewatch/watch.rb +12 -14
  22. data/lib/filewatch/watched_file.rb +25 -14
  23. data/lib/filewatch/watched_files_collection.rb +11 -78
  24. data/lib/jars/filewatch-1.0.1.jar +0 -0
  25. data/lib/logstash/inputs/file.rb +4 -3
  26. data/lib/logstash/inputs/file_listener.rb +3 -14
  27. data/logstash-input-file.gemspec +2 -1
  28. data/spec/filewatch/reading_spec.rb +63 -12
  29. data/spec/filewatch/rotate_spec.rb +4 -4
  30. data/spec/filewatch/settings_spec.rb +3 -0
  31. data/spec/filewatch/sincedb_record_serializer_spec.rb +6 -2
  32. data/spec/filewatch/spec_helper.rb +12 -14
  33. data/spec/filewatch/tailing_spec.rb +24 -22
  34. data/spec/filewatch/watched_file_spec.rb +30 -0
  35. data/spec/filewatch/watched_files_collection_spec.rb +62 -8
  36. data/spec/inputs/file_read_spec.rb +58 -14
  37. metadata +17 -2
@@ -35,5 +35,35 @@ module FileWatch
35
35
  expect(watched_file.recent_states).to eq([:watched, :active, :watched, :closed, :watched, :active, :unwatched, :active])
36
36
  end
37
37
  end
38
+
39
+ context 'restat' do
40
+
41
+ let(:directory) { Stud::Temporary.directory }
42
+ let(:file_path) { ::File.join(directory, "restat.file.txt") }
43
+ let(:pathname) { Pathname.new(file_path) }
44
+
45
+ before { FileUtils.touch file_path, :mtime => Time.now - 300 }
46
+
47
+ it 'reports false value when no changes' do
48
+ file = WatchedFile.new(pathname, PathStatClass.new(pathname), Settings.new)
49
+ mtime = file.modified_at
50
+ expect( file.modified_at_changed? ).to be false
51
+ expect( file.restat! ).to be_falsy
52
+ expect( file.modified_at_changed? ).to be false
53
+ expect( file.modified_at ).to eql mtime
54
+ expect( file.modified_at(true) ).to eql mtime
55
+ end
56
+
57
+ it 'reports truthy when changes detected' do
58
+ file = WatchedFile.new(pathname, PathStatClass.new(pathname), Settings.new)
59
+ mtime = file.modified_at
60
+ expect( file.modified_at_changed? ).to be false
61
+ FileUtils.touch file_path
62
+ expect( file.restat! ).to be_truthy
63
+ expect( file.modified_at_changed? ).to be true
64
+ expect( file.modified_at ).to eql mtime # until updated
65
+ expect( file.modified_at(true) ).to be > mtime
66
+ end
67
+ end
38
68
  end
39
69
  end
@@ -4,15 +4,18 @@ require_relative 'spec_helper'
4
4
  module FileWatch
5
5
  describe WatchedFilesCollection do
6
6
  let(:time) { Time.now }
7
- let(:filepath1){"/var/log/z.log"}
8
- let(:filepath2){"/var/log/m.log"}
9
- let(:filepath3){"/var/log/a.log"}
10
- let(:stat1) { double("stat1", :size => 98, :modified_at => time - 30, :identifier => nil, :inode => 234567, :inode_struct => InodeStruct.new("234567", 3, 2)) }
11
- let(:stat2) { double("stat2", :size => 99, :modified_at => time - 20, :identifier => nil, :inode => 234568, :inode_struct => InodeStruct.new("234568", 3, 2)) }
12
- let(:stat3) { double("stat3", :size => 100, :modified_at => time, :identifier => nil, :inode => 234569, :inode_struct => InodeStruct.new("234569", 3, 2)) }
7
+ let(:filepath1) { "/var/log/z.log" }
8
+ let(:filepath2) { "/var/log/m.log" }
9
+ let(:filepath3) { "/var/log/a.log" }
10
+ let(:filepath4) { "/var/log/b.log" }
11
+ let(:stat1) { double("stat1", :size => 98, :modified_at => time - 30, :inode => 234567, :inode_struct => InodeStruct.new("234567", 3, 2)) }
12
+ let(:stat2) { double("stat2", :size => 99, :modified_at => time - 20, :inode => 234568, :inode_struct => InodeStruct.new("234568", 3, 2)) }
13
+ let(:stat3) { double("stat3", :size => 100, :modified_at => time, :inode => 234569, :inode_struct => InodeStruct.new("234569", 3, 2)) }
14
+ let(:stat4) { double("stat4", :size => 99, :modified_at => time, :inode => 234570, :inode_struct => InodeStruct.new("234570", 3, 2)) }
13
15
  let(:wf1) { WatchedFile.new(filepath1, stat1, Settings.new) }
14
16
  let(:wf2) { WatchedFile.new(filepath2, stat2, Settings.new) }
15
17
  let(:wf3) { WatchedFile.new(filepath3, stat3, Settings.new) }
18
+ let(:wf4) { WatchedFile.new(filepath4, stat4, Settings.new) }
16
19
 
17
20
  context "sort by last_modified in ascending order" do
18
21
  let(:sort_by) { "last_modified" }
@@ -20,12 +23,29 @@ module FileWatch
20
23
 
21
24
  it "sorts earliest modified first" do
22
25
  collection = described_class.new(Settings.from_options(:file_sort_by => sort_by, :file_sort_direction => sort_direction))
26
+ expect(collection.empty?).to be true
23
27
  collection.add(wf2)
28
+ expect(collection.empty?).to be false
24
29
  expect(collection.values).to eq([wf2])
25
30
  collection.add(wf3)
26
31
  expect(collection.values).to eq([wf2, wf3])
27
32
  collection.add(wf1)
28
33
  expect(collection.values).to eq([wf1, wf2, wf3])
34
+ expect(collection.keys.size).to eq 3
35
+ end
36
+
37
+ it "sorts by path when mtime is same" do
38
+ collection = described_class.new(Settings.from_options(:file_sort_by => sort_by, :file_sort_direction => sort_direction))
39
+ expect(collection.size).to eq 0
40
+ collection.add(wf2)
41
+ collection.add(wf4)
42
+ collection.add(wf1)
43
+ expect(collection.size).to eq 3
44
+ expect(collection.values).to eq([wf1, wf2, wf4])
45
+ collection.add(wf3)
46
+ expect(collection.size).to eq 4
47
+ expect(collection.values).to eq([wf1, wf2, wf3, wf4])
48
+ expect(collection.keys.size).to eq 4
29
49
  end
30
50
  end
31
51
 
@@ -74,7 +94,7 @@ module FileWatch
74
94
  end
75
95
  end
76
96
 
77
- context "when delete called" do
97
+ context "remove_paths" do
78
98
  let(:sort_by) { "path" }
79
99
  let(:sort_direction) { "desc" }
80
100
 
@@ -85,9 +105,43 @@ module FileWatch
85
105
  collection.add(wf3)
86
106
  expect(collection.keys).to eq([filepath1, filepath2, filepath3])
87
107
 
88
- collection.remove_paths([filepath2,filepath3])
108
+ ret = collection.remove_paths([filepath2, filepath3])
109
+ expect(ret).to eq 2
89
110
  expect(collection.keys).to eq([filepath1])
90
111
  expect(collection.values.size).to eq 1
112
+
113
+ ret = collection.remove_paths([filepath2])
114
+ expect(ret).to eq 0
115
+ end
116
+ end
117
+
118
+ context "update" do
119
+ let(:sort_by) { "last_modified" }
120
+ let(:sort_direction) { "asc" }
121
+
122
+ let(:re_stat1) { double("restat1", :size => 99, :modified_at => time, :inode => 234567, :inode_struct => InodeStruct.new("234567", 3, 2)) }
123
+ let(:re_stat2) { double("restat2", :size => 99, :modified_at => time, :inode => 234568, :inode_struct => InodeStruct.new("234568", 3, 2)) }
124
+
125
+ it "updates entry with changed mtime" do
126
+ collection = described_class.new(Settings.from_options(:file_sort_by => sort_by, :file_sort_direction => sort_direction))
127
+ collection.add(wf1)
128
+ collection.add(wf2)
129
+ collection.add(wf3)
130
+ expect(collection.files).to eq([wf1, wf2, wf3])
131
+
132
+ wf2.send(:set_stat, re_stat2)
133
+ expect( wf2.modified_at_changed? ).to be_truthy
134
+
135
+ collection.update wf2
136
+ expect(collection.files).to eq([wf1, wf3, wf2])
137
+
138
+ wf1.send(:set_stat, re_stat1)
139
+ expect( wf1.modified_at_changed? ).to be_truthy
140
+ collection.update wf1
141
+ expect(collection.files).to eq([wf3, wf2, wf1])
142
+
143
+ collection.add(wf4)
144
+ expect(collection.files).to eq([wf3, wf4, wf2, wf1])
91
145
  end
92
146
  end
93
147
 
@@ -267,7 +267,7 @@ describe LogStash::Inputs::File do
267
267
  describe 'delete on complete' do
268
268
 
269
269
  let(:options) do
270
- super.merge({ 'file_completed_action' => "delete", 'exit_after_read' => false })
270
+ super().merge({ 'file_completed_action' => "delete", 'exit_after_read' => false })
271
271
  end
272
272
 
273
273
  let(:sample_file) { File.join(temp_directory, "sample.log") }
@@ -301,25 +301,69 @@ describe LogStash::Inputs::File do
301
301
  watched_files = plugin.watcher.watch.watched_files_collection
302
302
  expect( watched_files ).to be_empty
303
303
  end
304
+ end
304
305
 
305
- private
306
+ describe 'sincedb cleanup' do
306
307
 
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
308
+ let(:options) do
309
+ super().merge(
310
+ 'sincedb_path' => sincedb_path,
311
+ 'sincedb_clean_after' => '1.0 seconds',
312
+ 'sincedb_write_interval' => 0.25,
313
+ 'stat_interval' => 0.1,
314
+ )
315
+ end
316
+
317
+ let(:sincedb_path) { "#{temp_directory}/.sincedb" }
318
+
319
+ let(:sample_file) { File.join(temp_directory, "sample.txt") }
320
+
321
+ before do
322
+ plugin.register
323
+ @run_thread = Thread.new(plugin) do |plugin|
324
+ Thread.current.abort_on_exception = true
325
+ plugin.run queue
317
326
  end
327
+
328
+ File.open(sample_file, 'w') { |fd| fd.write("line1\nline2\n") }
329
+
330
+ wait_for_start_processing(@run_thread)
318
331
  end
319
332
 
320
- def wait_for_file_removal(path, timeout: 3 * interval)
321
- wait(timeout).for { File.exist?(path) }.to be_falsey
333
+ after { plugin.stop }
334
+
335
+ it 'cleans up sincedb entry' do
336
+ wait_for_file_removal(sample_file) # watched discovery
337
+
338
+ sincedb_content = File.read(sincedb_path).strip
339
+ expect( sincedb_content ).to_not be_empty
340
+
341
+ Stud.try(3.times) do
342
+ sleep(1.5) # > sincedb_clean_after
343
+
344
+ sincedb_content = File.read(sincedb_path).strip
345
+ expect( sincedb_content ).to be_empty
346
+ end
322
347
  end
323
348
 
324
349
  end
350
+
351
+ private
352
+
353
+ def wait_for_start_processing(run_thread, timeout: 1.0)
354
+ begin
355
+ Timeout.timeout(timeout) do
356
+ sleep(0.01) while run_thread.status != 'sleep'
357
+ sleep(timeout) unless plugin.queue
358
+ end
359
+ rescue Timeout::Error
360
+ raise "plugin did not start processing (timeout: #{timeout})" unless plugin.queue
361
+ else
362
+ raise "plugin did not start processing" unless plugin.queue
363
+ end
364
+ end
365
+
366
+ def wait_for_file_removal(path, timeout: 3 * interval)
367
+ wait(timeout).for { File.exist?(path) }.to be_falsey
368
+ end
325
369
  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.18
4
+ version: 4.2.4
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-30 00:00:00.000000000 Z
11
+ date: 2021-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.0'
67
+ name: concurrent-ruby
68
+ prerelease: false
69
+ type: :runtime
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
61
75
  - !ruby/object:Gem::Dependency
62
76
  requirement: !ruby/object:Gem::Requirement
63
77
  requirements:
@@ -178,6 +192,7 @@ files:
178
192
  - lib/filewatch/observing_base.rb
179
193
  - lib/filewatch/observing_read.rb
180
194
  - lib/filewatch/observing_tail.rb
195
+ - lib/filewatch/processor.rb
181
196
  - lib/filewatch/read_mode/handlers/base.rb
182
197
  - lib/filewatch/read_mode/handlers/read_file.rb
183
198
  - lib/filewatch/read_mode/handlers/read_zip_file.rb