logstash-input-file 4.1.17 → 4.2.3
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/filewatch/discoverer.rb +9 -8
- data/lib/filewatch/observing_base.rb +1 -12
- data/lib/filewatch/processor.rb +55 -0
- data/lib/filewatch/read_mode/handlers/base.rb +12 -11
- data/lib/filewatch/read_mode/handlers/read_file.rb +26 -8
- data/lib/filewatch/read_mode/handlers/read_zip_file.rb +8 -6
- data/lib/filewatch/read_mode/processor.rb +22 -36
- data/lib/filewatch/settings.rb +1 -2
- data/lib/filewatch/sincedb_collection.rb +39 -40
- data/lib/filewatch/sincedb_record_serializer.rb +5 -11
- data/lib/filewatch/stat/generic.rb +8 -13
- data/lib/filewatch/stat/windows_path.rb +7 -9
- data/lib/filewatch/tail_mode/handlers/base.rb +32 -23
- data/lib/filewatch/tail_mode/handlers/delete.rb +2 -4
- data/lib/filewatch/tail_mode/handlers/shrink.rb +2 -3
- data/lib/filewatch/tail_mode/handlers/unignore.rb +4 -4
- data/lib/filewatch/tail_mode/processor.rb +47 -54
- data/lib/filewatch/watch.rb +12 -14
- data/lib/filewatch/watched_file.rb +25 -14
- data/lib/filewatch/watched_files_collection.rb +11 -74
- data/lib/jars/filewatch-1.0.1.jar +0 -0
- data/lib/logstash/inputs/delete_completed_file_handler.rb +5 -0
- data/lib/logstash/inputs/file.rb +28 -13
- data/lib/logstash/inputs/file_listener.rb +3 -14
- data/logstash-input-file.gemspec +2 -1
- data/spec/filewatch/reading_spec.rb +60 -9
- data/spec/filewatch/settings_spec.rb +3 -0
- data/spec/filewatch/sincedb_record_serializer_spec.rb +6 -2
- data/spec/filewatch/spec_helper.rb +12 -14
- data/spec/filewatch/tailing_spec.rb +14 -12
- data/spec/filewatch/watched_file_spec.rb +30 -0
- data/spec/filewatch/watched_files_collection_spec.rb +62 -8
- data/spec/helpers/spec_helper.rb +1 -0
- data/spec/inputs/file_read_spec.rb +119 -0
- metadata +17 -2
@@ -14,11 +14,10 @@ module FileWatch module TailMode module Handlers
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def update_existing_specifically(watched_file, sincedb_value)
|
17
|
-
# we have a match but size is smaller
|
18
|
-
# set all to zero
|
17
|
+
# we have a match but size is smaller - set all to zero
|
19
18
|
watched_file.reset_bytes_unread
|
20
19
|
sincedb_value.update_position(0)
|
21
|
-
logger.trace("update_existing_specifically: was truncated seeking to beginning",
|
20
|
+
logger.trace? && logger.trace("update_existing_specifically: was truncated seeking to beginning", :watched_file => watched_file.details, :sincedb_value => sincedb_value)
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end end end
|
@@ -13,9 +13,9 @@ module FileWatch module TailMode module Handlers
|
|
13
13
|
# for file initially ignored their bytes_read was set to stat.size
|
14
14
|
# use this value not the `start_new_files_at` for the position
|
15
15
|
# logger.trace("get_new_value_specifically", "watched_file" => watched_file.inspect)
|
16
|
-
SincedbValue.new(watched_file.bytes_read).tap do |
|
17
|
-
|
18
|
-
logger.trace("
|
16
|
+
SincedbValue.new(watched_file.bytes_read).tap do |sincedb_value|
|
17
|
+
sincedb_value.set_watched_file(watched_file)
|
18
|
+
logger.trace? && logger.trace("get_new_value_specifically: unignore", :watched_file => watched_file.details, :sincedb_value => sincedb_value)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -26,7 +26,7 @@ module FileWatch module TailMode module Handlers
|
|
26
26
|
# we will handle grow or shrink
|
27
27
|
# for now we seek to where we were before the file got ignored (grow)
|
28
28
|
# or to the start (shrink)
|
29
|
-
logger.trace("
|
29
|
+
logger.trace? && logger.trace("update_existing_specifically: unignore", :watched_file => watched_file.details, :sincedb_value => sincedb_value)
|
30
30
|
position = 0
|
31
31
|
if watched_file.shrunk?
|
32
32
|
watched_file.update_bytes_read(0)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
2
|
+
require 'filewatch/processor'
|
3
3
|
require_relative "handlers/base"
|
4
4
|
require_relative "handlers/create_initial"
|
5
5
|
require_relative "handlers/create"
|
@@ -18,20 +18,7 @@ module FileWatch module TailMode
|
|
18
18
|
# :delete - file can't be read
|
19
19
|
# :timeout - file is closable
|
20
20
|
# :unignore - file was ignored, but have now received new content
|
21
|
-
class Processor
|
22
|
-
include LogStash::Util::Loggable
|
23
|
-
|
24
|
-
attr_reader :watch, :deletable_filepaths
|
25
|
-
|
26
|
-
def initialize(settings)
|
27
|
-
@settings = settings
|
28
|
-
@deletable_filepaths = []
|
29
|
-
end
|
30
|
-
|
31
|
-
def add_watch(watch)
|
32
|
-
@watch = watch
|
33
|
-
self
|
34
|
-
end
|
21
|
+
class Processor < FileWatch::Processor
|
35
22
|
|
36
23
|
def initialize_handlers(sincedb_collection, observer)
|
37
24
|
@sincedb_collection = sincedb_collection
|
@@ -91,11 +78,12 @@ module FileWatch module TailMode
|
|
91
78
|
private
|
92
79
|
|
93
80
|
def process_closed(watched_files)
|
94
|
-
|
81
|
+
logger.trace(__method__.to_s)
|
95
82
|
# Handles watched_files in the closed state.
|
96
83
|
# if its size changed it is put into the watched state
|
97
|
-
watched_files.
|
98
|
-
|
84
|
+
watched_files.each do |watched_file|
|
85
|
+
next unless watched_file.closed?
|
86
|
+
common_restat_with_delay(watched_file, __method__) do
|
99
87
|
# it won't do this if rotation is detected
|
100
88
|
if watched_file.size_changed?
|
101
89
|
# if the closed file changed, move it to the watched state
|
@@ -108,13 +96,14 @@ module FileWatch module TailMode
|
|
108
96
|
end
|
109
97
|
|
110
98
|
def process_ignored(watched_files)
|
111
|
-
|
99
|
+
logger.trace(__method__.to_s)
|
112
100
|
# Handles watched_files in the ignored state.
|
113
101
|
# if its size changed:
|
114
102
|
# put it in the watched state
|
115
103
|
# invoke unignore
|
116
|
-
watched_files.
|
117
|
-
|
104
|
+
watched_files.each do |watched_file|
|
105
|
+
next unless watched_file.ignored?
|
106
|
+
common_restat_with_delay(watched_file, __method__) do
|
118
107
|
# it won't do this if rotation is detected
|
119
108
|
if watched_file.size_changed?
|
120
109
|
watched_file.watch
|
@@ -128,11 +117,12 @@ module FileWatch module TailMode
|
|
128
117
|
def process_delayed_delete(watched_files)
|
129
118
|
# defer the delete to one loop later to ensure that the stat really really can't find a renamed file
|
130
119
|
# because a `stat` can be called right in the middle of the rotation rename cascade
|
131
|
-
logger.trace(
|
132
|
-
watched_files.
|
133
|
-
|
134
|
-
|
135
|
-
|
120
|
+
logger.trace(__method__.to_s)
|
121
|
+
watched_files.each do |watched_file|
|
122
|
+
next unless watched_file.delayed_delete?
|
123
|
+
logger.trace(">>> Delayed Delete", :path => watched_file.path)
|
124
|
+
common_restat_without_delay(watched_file, __method__) do
|
125
|
+
logger.trace(">>> Delayed Delete: file at path found again", :watched_file => watched_file.details)
|
136
126
|
watched_file.file_at_path_found_again
|
137
127
|
end
|
138
128
|
end
|
@@ -140,33 +130,35 @@ module FileWatch module TailMode
|
|
140
130
|
|
141
131
|
def process_restat_for_watched_and_active(watched_files)
|
142
132
|
# do restat on all watched and active states once now. closed and ignored have been handled already
|
143
|
-
logger.trace(
|
144
|
-
watched_files.
|
145
|
-
|
133
|
+
logger.trace(__method__.to_s)
|
134
|
+
watched_files.each do |watched_file|
|
135
|
+
next if !watched_file.watched? && !watched_file.active?
|
136
|
+
common_restat_with_delay(watched_file, __method__)
|
146
137
|
end
|
147
138
|
end
|
148
139
|
|
149
140
|
def process_rotation_in_progress(watched_files)
|
150
|
-
logger.trace(
|
151
|
-
watched_files.
|
141
|
+
logger.trace(__method__.to_s)
|
142
|
+
watched_files.each do |watched_file|
|
143
|
+
next unless watched_file.rotation_in_progress?
|
152
144
|
if !watched_file.all_read?
|
153
145
|
if watched_file.file_open?
|
154
146
|
# rotated file but original opened file is not fully read
|
155
147
|
# we need to keep reading the open file, if we close it we lose it because the path is now pointing at a different file.
|
156
|
-
logger.trace(">>> Rotation In Progress - inode change detected and original content is not fully read, reading all",
|
148
|
+
logger.trace(">>> Rotation In Progress - inode change detected and original content is not fully read, reading all", :watched_file => watched_file.details)
|
157
149
|
# need to fully read open file while we can
|
158
150
|
watched_file.set_maximum_read_loop
|
159
151
|
grow(watched_file)
|
160
152
|
watched_file.set_standard_read_loop
|
161
153
|
else
|
162
|
-
logger.warn(">>> Rotation In Progress - inode change detected and original content is not fully read, file is closed and path points to new content",
|
154
|
+
logger.warn(">>> Rotation In Progress - inode change detected and original content is not fully read, file is closed and path points to new content", :watched_file => watched_file.details)
|
163
155
|
end
|
164
156
|
end
|
165
157
|
current_key = watched_file.sincedb_key
|
166
158
|
sdb_value = @sincedb_collection.get(current_key)
|
167
159
|
potential_key = watched_file.stat_sincedb_key
|
168
160
|
potential_sdb_value = @sincedb_collection.get(potential_key)
|
169
|
-
logger.trace(">>> Rotation In Progress",
|
161
|
+
logger.trace(">>> Rotation In Progress", :watched_file => watched_file.details, :found_sdb_value => sdb_value, :potential_key => potential_key, :potential_sdb_value => potential_sdb_value)
|
170
162
|
if potential_sdb_value.nil?
|
171
163
|
logger.trace("---------- >>>> Rotation In Progress: rotating as existing file")
|
172
164
|
watched_file.rotate_as_file
|
@@ -189,13 +181,13 @@ module FileWatch module TailMode
|
|
189
181
|
sdb_value.clear_watched_file unless sdb_value.nil?
|
190
182
|
potential_sdb_value.set_watched_file(watched_file)
|
191
183
|
else
|
192
|
-
logger.trace("---------- >>>> Rotation In Progress: rotating from...",
|
184
|
+
logger.trace("---------- >>>> Rotation In Progress: rotating from...", :this_watched_file => watched_file.details, :other_watched_file => other_watched_file.details)
|
193
185
|
watched_file.rotate_from(other_watched_file)
|
194
186
|
sdb_value.clear_watched_file unless sdb_value.nil?
|
195
187
|
potential_sdb_value.set_watched_file(watched_file)
|
196
188
|
end
|
197
189
|
end
|
198
|
-
logger.trace("---------- >>>> Rotation In Progress: after handling rotation",
|
190
|
+
logger.trace("---------- >>>> Rotation In Progress: after handling rotation", :this_watched_file => watched_file.details, :sincedb_value => (potential_sdb_value || sdb_value))
|
199
191
|
end
|
200
192
|
end
|
201
193
|
|
@@ -206,11 +198,11 @@ module FileWatch module TailMode
|
|
206
198
|
# and we allow the block to open the file and create a sincedb collection record if needed
|
207
199
|
# some have never been active and some have
|
208
200
|
# those that were active before but are watched now were closed under constraint
|
209
|
-
logger.trace(
|
201
|
+
logger.trace(__method__.to_s)
|
210
202
|
# how much of the max active window is available
|
211
|
-
to_take = @settings.max_active - watched_files.count
|
203
|
+
to_take = @settings.max_active - watched_files.count(&:active?)
|
212
204
|
if to_take > 0
|
213
|
-
watched_files.select
|
205
|
+
watched_files.select(&:watched?).take(to_take).each do |watched_file|
|
214
206
|
watched_file.activate
|
215
207
|
if watched_file.initial?
|
216
208
|
create_initial(watched_file)
|
@@ -223,36 +215,37 @@ module FileWatch module TailMode
|
|
223
215
|
now = Time.now.to_i
|
224
216
|
if (now - watch.lastwarn_max_files) > MAX_FILES_WARN_INTERVAL
|
225
217
|
waiting = watched_files.size - @settings.max_active
|
226
|
-
logger.warn(@settings.max_warn_msg
|
218
|
+
logger.warn("#{@settings.max_warn_msg}, files yet to open: #{waiting}")
|
227
219
|
watch.lastwarn_max_files = now
|
228
220
|
end
|
229
221
|
end
|
230
222
|
end
|
231
223
|
|
232
224
|
def process_active(watched_files)
|
233
|
-
|
225
|
+
logger.trace(__method__.to_s)
|
234
226
|
# Handles watched_files in the active state.
|
235
227
|
# files have been opened at this point
|
236
|
-
watched_files.
|
228
|
+
watched_files.each do |watched_file|
|
229
|
+
next unless watched_file.active?
|
237
230
|
break if watch.quit?
|
238
231
|
path = watched_file.filename
|
239
232
|
if watched_file.grown?
|
240
|
-
logger.trace("
|
233
|
+
logger.trace("#{__method__} file grew: new size is #{watched_file.last_stat_size}, bytes read #{watched_file.bytes_read}", :path => path)
|
241
234
|
grow(watched_file)
|
242
235
|
elsif watched_file.shrunk?
|
243
236
|
if watched_file.bytes_unread > 0
|
244
|
-
logger.warn("
|
237
|
+
logger.warn("potential data loss, file truncate detected with #{watched_file.bytes_unread} unread bytes", :path => path)
|
245
238
|
end
|
246
239
|
# we don't update the size here, its updated when we actually read
|
247
|
-
logger.trace("
|
240
|
+
logger.trace("#{__method__} file shrunk: new size is #{watched_file.last_stat_size}, old size #{watched_file.bytes_read}", :path => path)
|
248
241
|
shrink(watched_file)
|
249
242
|
else
|
250
243
|
# same size, do nothing
|
251
|
-
logger.trace("
|
244
|
+
logger.trace("#{__method__} no change", :path => path)
|
252
245
|
end
|
253
246
|
# can any active files be closed to make way for waiting files?
|
254
247
|
if watched_file.file_closable?
|
255
|
-
logger.trace("
|
248
|
+
logger.trace("#{__method__} file expired", :path => path)
|
256
249
|
timeout(watched_file)
|
257
250
|
watched_file.close
|
258
251
|
end
|
@@ -270,28 +263,28 @@ module FileWatch module TailMode
|
|
270
263
|
def common_restat(watched_file, action, delay, &block)
|
271
264
|
all_ok = true
|
272
265
|
begin
|
273
|
-
watched_file
|
266
|
+
restat(watched_file)
|
274
267
|
if watched_file.rotation_in_progress?
|
275
|
-
logger.trace("-------------------- >>>>> restat - rotation_detected",
|
268
|
+
logger.trace("-------------------- >>>>> restat - rotation_detected", :watched_file => watched_file.details, :new_sincedb_key => watched_file.stat_sincedb_key)
|
276
269
|
# don't yield to closed and ignore processing
|
277
270
|
else
|
278
271
|
yield if block_given?
|
279
272
|
end
|
280
273
|
rescue Errno::ENOENT
|
281
274
|
if delay
|
282
|
-
logger.trace("#{action} - delaying the stat fail on:
|
275
|
+
logger.trace("#{action} - delaying the stat fail on", :filename => watched_file.filename)
|
283
276
|
watched_file.delay_delete
|
284
277
|
else
|
285
278
|
# file has gone away or we can't read it anymore.
|
286
|
-
logger.trace("#{action} - after a delay, really can't find this file:
|
279
|
+
logger.trace("#{action} - after a delay, really can't find this file", :path => watched_file.path)
|
287
280
|
watched_file.unwatch
|
288
|
-
logger.trace("#{action} - removing from collection:
|
281
|
+
logger.trace("#{action} - removing from collection", :filename => watched_file.filename)
|
289
282
|
delete(watched_file)
|
290
|
-
|
283
|
+
add_deletable_path watched_file.path
|
291
284
|
all_ok = false
|
292
285
|
end
|
293
286
|
rescue => e
|
294
|
-
logger.error("#{action} - other error
|
287
|
+
logger.error("#{action} - other error", error_details(e, watched_file))
|
295
288
|
all_ok = false
|
296
289
|
end
|
297
290
|
all_ok
|
data/lib/filewatch/watch.rb
CHANGED
@@ -1,26 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "logstash/util/loggable"
|
3
|
+
require "concurrent/atomic/atomic_boolean"
|
3
4
|
|
4
5
|
module FileWatch
|
5
6
|
class Watch
|
6
7
|
include LogStash::Util::Loggable
|
7
8
|
|
8
9
|
attr_accessor :lastwarn_max_files
|
9
|
-
attr_reader :discoverer, :watched_files_collection
|
10
|
+
attr_reader :discoverer, :processor, :watched_files_collection
|
10
11
|
|
11
|
-
def initialize(discoverer,
|
12
|
+
def initialize(discoverer, processor, settings)
|
13
|
+
@discoverer = discoverer
|
14
|
+
@watched_files_collection = discoverer.watched_files_collection
|
12
15
|
@settings = settings
|
16
|
+
|
13
17
|
# we need to be threadsafe about the quit mutation
|
14
18
|
@quit = Concurrent::AtomicBoolean.new(false)
|
15
19
|
@lastwarn_max_files = 0
|
16
|
-
@discoverer = discoverer
|
17
|
-
@watched_files_collection = watched_files_collection
|
18
|
-
end
|
19
20
|
|
20
|
-
def add_processor(processor)
|
21
21
|
@processor = processor
|
22
22
|
@processor.add_watch(self)
|
23
|
-
self
|
24
23
|
end
|
25
24
|
|
26
25
|
def watch(path)
|
@@ -52,7 +51,10 @@ module FileWatch
|
|
52
51
|
glob = 0
|
53
52
|
end
|
54
53
|
break if quit?
|
54
|
+
# NOTE: maybe the plugin should validate stat_interval <= sincedb_write_interval <= sincedb_clean_after
|
55
55
|
sleep(@settings.stat_interval)
|
56
|
+
# we need to check potential expired keys (sincedb_clean_after) periodically
|
57
|
+
sincedb_collection.flush_at_interval
|
56
58
|
end
|
57
59
|
sincedb_collection.write_if_requested # does nothing if no requests to write were lodged.
|
58
60
|
@watched_files_collection.close_all
|
@@ -67,20 +69,16 @@ module FileWatch
|
|
67
69
|
watched_files = @watched_files_collection.values
|
68
70
|
@processor.process_all_states(watched_files)
|
69
71
|
ensure
|
70
|
-
@watched_files_collection.
|
71
|
-
@processor.deletable_filepaths.clear
|
72
|
+
@watched_files_collection.remove_paths(@processor.clear_deletable_paths)
|
72
73
|
end
|
73
|
-
end
|
74
|
+
end
|
74
75
|
|
75
76
|
def quit
|
76
77
|
@quit.make_true
|
77
78
|
end
|
78
79
|
|
79
80
|
def quit?
|
80
|
-
|
81
|
-
@exit = @watched_files_collection.empty?
|
82
|
-
end
|
83
|
-
@quit.true? || @exit
|
81
|
+
@quit.true? || (@settings.exit_after_read && @watched_files_collection.empty?)
|
84
82
|
end
|
85
83
|
|
86
84
|
private
|
@@ -6,7 +6,7 @@ module FileWatch
|
|
6
6
|
IO_BASED_STAT = 1
|
7
7
|
|
8
8
|
attr_reader :bytes_read, :state, :file, :buffer, :recent_states, :bytes_unread
|
9
|
-
attr_reader :path, :accessed_at, :
|
9
|
+
attr_reader :path, :accessed_at, :pathname, :filename
|
10
10
|
attr_reader :listener, :read_loop_count, :read_chunk_size, :stat
|
11
11
|
attr_reader :loop_count_type, :loop_count_mode
|
12
12
|
attr_accessor :last_open_warning_at
|
@@ -16,7 +16,7 @@ module FileWatch
|
|
16
16
|
def initialize(pathname, stat, settings)
|
17
17
|
@settings = settings
|
18
18
|
@pathname = Pathname.new(pathname) # given arg pathname might be a string or a Pathname object
|
19
|
-
@path = @pathname.to_path
|
19
|
+
@path = @pathname.to_path.freeze
|
20
20
|
@filename = @pathname.basename.to_s
|
21
21
|
full_state_reset(stat)
|
22
22
|
watch
|
@@ -24,10 +24,6 @@ module FileWatch
|
|
24
24
|
set_accessed_at
|
25
25
|
end
|
26
26
|
|
27
|
-
def no_restat_reset
|
28
|
-
full_state_reset(@stat)
|
29
|
-
end
|
30
|
-
|
31
27
|
def full_state_reset(this_stat = nil)
|
32
28
|
if this_stat.nil?
|
33
29
|
begin
|
@@ -75,6 +71,7 @@ module FileWatch
|
|
75
71
|
@size = @stat.size
|
76
72
|
@sdb_key_v1 = @stat.inode_struct
|
77
73
|
end
|
74
|
+
private :set_stat
|
78
75
|
|
79
76
|
def rotate_as_file(bytes_read = 0)
|
80
77
|
# rotation, when a sincedb record exists for new inode, but no watched file to rotate from
|
@@ -100,19 +97,33 @@ module FileWatch
|
|
100
97
|
stat_sincedb_key != sincedb_key
|
101
98
|
end
|
102
99
|
|
103
|
-
|
100
|
+
# @return true if the file was modified since last stat
|
101
|
+
def restat!
|
102
|
+
modified_at # to always be able to detect changes
|
104
103
|
@stat.restat
|
105
104
|
if rotation_detected?
|
106
105
|
# switch to new state now
|
107
106
|
rotation_in_progress
|
107
|
+
return true
|
108
108
|
else
|
109
109
|
@size = @stat.size
|
110
110
|
update_bytes_unread
|
111
|
+
modified_at_changed?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def modified_at(update = false)
|
116
|
+
if update || @modified_at.nil?
|
117
|
+
@modified_at = @stat.modified_at
|
118
|
+
else
|
119
|
+
@modified_at
|
111
120
|
end
|
112
121
|
end
|
113
122
|
|
114
|
-
|
115
|
-
|
123
|
+
# @return whether modified_at changed since it was last read
|
124
|
+
# @see #restat!
|
125
|
+
def modified_at_changed?
|
126
|
+
modified_at != @stat.modified_at
|
116
127
|
end
|
117
128
|
|
118
129
|
def position_for_new_sincedb_value
|
@@ -405,14 +416,14 @@ module FileWatch
|
|
405
416
|
end
|
406
417
|
|
407
418
|
def details
|
408
|
-
detail = "@filename='#{filename}', @state
|
409
|
-
detail.concat("@bytes_read
|
410
|
-
detail.concat("last_stat_size
|
411
|
-
"<FileWatch::WatchedFile: #{detail},
|
419
|
+
detail = "@filename='#{@filename}', @state=#{@state.inspect}, @recent_states=#{@recent_states.inspect}, "
|
420
|
+
detail.concat("@bytes_read=#{@bytes_read}, @bytes_unread=#{@bytes_unread}, current_size=#{current_size}, ")
|
421
|
+
detail.concat("last_stat_size=#{last_stat_size}, file_open?=#{file_open?}, @initial=#{@initial}")
|
422
|
+
"<FileWatch::WatchedFile: #{detail}, sincedb_key='#{sincedb_key}'>"
|
412
423
|
end
|
413
424
|
|
414
425
|
def inspect
|
415
|
-
"
|
426
|
+
"<FileWatch::WatchedFile: @filename='#{@filename}', @state=#{@state.inspect}, current_size=#{current_size}, sincedb_key='#{sincedb_key}'>"
|
416
427
|
end
|
417
428
|
|
418
429
|
def to_s
|
@@ -1,85 +1,22 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
module FileWatch
|
3
|
-
class WatchedFilesCollection
|
4
|
-
|
5
|
-
def initialize(settings)
|
6
|
-
@sort_by = settings.file_sort_by # "last_modified" | "path"
|
7
|
-
@sort_direction = settings.file_sort_direction # "asc" | "desc"
|
8
|
-
@sort_method = method("#{@sort_by}_#{@sort_direction}".to_sym)
|
9
|
-
@files = Concurrent::Array.new
|
10
|
-
@pointers = Concurrent::Hash.new
|
11
|
-
end
|
12
2
|
|
13
|
-
|
14
|
-
@files << watched_file
|
15
|
-
@sort_method.call
|
16
|
-
end
|
3
|
+
require 'java'
|
17
4
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@files.delete_at(index)
|
22
|
-
refresh_pointers
|
23
|
-
end
|
24
|
-
@sort_method.call
|
25
|
-
end
|
5
|
+
module FileWatch
|
6
|
+
# @see `org.logstash.filewatch.WatchedFilesCollection`
|
7
|
+
class WatchedFilesCollection
|
26
8
|
|
9
|
+
# Closes all managed watched files.
|
10
|
+
# @see FileWatch::WatchedFile#file_close
|
27
11
|
def close_all
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def empty?
|
32
|
-
@files.empty?
|
33
|
-
end
|
34
|
-
|
35
|
-
def keys
|
36
|
-
@pointers.keys
|
12
|
+
each_file(&:file_close) # synchronized
|
37
13
|
end
|
38
14
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def watched_file_by_path(path)
|
44
|
-
index = @pointers[path]
|
45
|
-
return nil unless index
|
46
|
-
@files[index]
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def last_modified_asc
|
52
|
-
@files.sort! do |left, right|
|
53
|
-
left.modified_at <=> right.modified_at
|
54
|
-
end
|
55
|
-
refresh_pointers
|
56
|
-
end
|
15
|
+
# @return [Enumerable<String>] managed path keys (snapshot)
|
16
|
+
alias keys paths
|
57
17
|
|
58
|
-
|
59
|
-
|
60
|
-
right.modified_at <=> left.modified_at
|
61
|
-
end
|
62
|
-
refresh_pointers
|
63
|
-
end
|
64
|
-
|
65
|
-
def path_asc
|
66
|
-
@files.sort! do |left, right|
|
67
|
-
left.path <=> right.path
|
68
|
-
end
|
69
|
-
refresh_pointers
|
70
|
-
end
|
18
|
+
# @return [Enumerable<WatchedFile>] managed files (snapshot)
|
19
|
+
alias values files
|
71
20
|
|
72
|
-
def path_desc
|
73
|
-
@files.sort! do |left, right|
|
74
|
-
right.path <=> left.path
|
75
|
-
end
|
76
|
-
refresh_pointers
|
77
|
-
end
|
78
|
-
|
79
|
-
def refresh_pointers
|
80
|
-
@files.each_with_index do |watched_file, index|
|
81
|
-
@pointers[watched_file.path] = index
|
82
|
-
end
|
83
|
-
end
|
84
21
|
end
|
85
22
|
end
|