logstash-input-file 4.1.16 → 4.2.2
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 +20 -0
- data/LICENSE +199 -10
- data/docs/index.asciidoc +23 -7
- 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 +8 -6
- data/lib/filewatch/read_mode/handlers/read_file.rb +26 -8
- data/lib/filewatch/read_mode/handlers/read_zip_file.rb +63 -34
- data/lib/filewatch/read_mode/processor.rb +22 -36
- data/lib/filewatch/settings.rb +3 -2
- data/lib/filewatch/sincedb_collection.rb +23 -21
- data/lib/filewatch/stat/generic.rb +8 -13
- data/lib/filewatch/stat/windows_path.rb +7 -9
- data/lib/filewatch/tail_mode/handlers/delete.rb +2 -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 +32 -11
- data/logstash-input-file.gemspec +3 -2
- data/spec/filewatch/reading_spec.rb +60 -9
- data/spec/filewatch/rotate_spec.rb +2 -1
- data/spec/filewatch/settings_spec.rb +3 -0
- data/spec/filewatch/spec_helper.rb +13 -15
- 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 +8 -0
- data/spec/inputs/file_read_spec.rb +154 -4
- data/spec/inputs/file_tail_spec.rb +3 -2
- metadata +21 -6
@@ -19,16 +19,21 @@ module FileWatch module ReadMode module Handlers
|
|
19
19
|
watched_file.listener.eof
|
20
20
|
watched_file.file_close
|
21
21
|
key = watched_file.sincedb_key
|
22
|
-
sincedb_collection.
|
23
|
-
|
22
|
+
if sincedb_collection.get(key)
|
23
|
+
sincedb_collection.reading_completed(key)
|
24
|
+
sincedb_collection.clear_watched_file(key)
|
25
|
+
end
|
24
26
|
watched_file.listener.deleted
|
27
|
+
# NOTE: on top of un-watching we should also remove from the watched files collection
|
28
|
+
# if the file is getting deleted (on completion), that part currently resides in
|
29
|
+
# DeleteCompletedFileHandler - triggered above using `watched_file.listener.deleted`
|
25
30
|
watched_file.unwatch
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
30
35
|
def controlled_read(watched_file, loop_control)
|
31
|
-
logger.trace("reading...",
|
36
|
+
logger.trace? && logger.trace("reading...", :filename => watched_file.filename, :iterations => loop_control.count, :amount => loop_control.size)
|
32
37
|
loop_control.count.times do
|
33
38
|
break if quit?
|
34
39
|
begin
|
@@ -40,22 +45,35 @@ module FileWatch module ReadMode module Handlers
|
|
40
45
|
delta = line.bytesize + @settings.delimiter_byte_size
|
41
46
|
sincedb_collection.increment(watched_file.sincedb_key, delta)
|
42
47
|
end
|
43
|
-
rescue EOFError
|
44
|
-
|
48
|
+
rescue EOFError => e
|
49
|
+
log_error("controlled_read: eof error reading file", watched_file, e)
|
45
50
|
loop_control.flag_read_error
|
46
51
|
break
|
47
|
-
rescue Errno::EWOULDBLOCK, Errno::EINTR
|
48
|
-
|
52
|
+
rescue Errno::EWOULDBLOCK, Errno::EINTR => e
|
53
|
+
log_error("controlled_read: block or interrupt error reading file", watched_file, e)
|
49
54
|
watched_file.listener.error
|
50
55
|
loop_control.flag_read_error
|
51
56
|
break
|
52
57
|
rescue => e
|
53
|
-
|
58
|
+
log_error("controlled_read: general error reading file", watched_file, e)
|
54
59
|
watched_file.listener.error
|
55
60
|
loop_control.flag_read_error
|
56
61
|
break
|
57
62
|
end
|
58
63
|
end
|
59
64
|
end
|
65
|
+
|
66
|
+
def log_error(msg, watched_file, error)
|
67
|
+
details = { :path => watched_file.path,
|
68
|
+
:exception => error.class,
|
69
|
+
:message => error.message,
|
70
|
+
:backtrace => error.backtrace }
|
71
|
+
if logger.debug?
|
72
|
+
details[:file] = watched_file
|
73
|
+
else
|
74
|
+
details[:backtrace] = details[:backtrace].take(8) if details[:backtrace]
|
75
|
+
end
|
76
|
+
logger.error(msg, details)
|
77
|
+
end
|
60
78
|
end
|
61
79
|
end end end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'java'
|
3
|
-
java_import java.io.InputStream
|
4
|
-
java_import java.io.InputStreamReader
|
5
|
-
java_import java.io.FileInputStream
|
6
|
-
java_import java.io.BufferedReader
|
7
|
-
java_import java.util.zip.GZIPInputStream
|
8
|
-
java_import java.util.zip.ZipException
|
9
3
|
|
10
4
|
module FileWatch module ReadMode module Handlers
|
5
|
+
|
6
|
+
java_import java.io.InputStream
|
7
|
+
java_import java.io.InputStreamReader
|
8
|
+
java_import java.io.FileInputStream
|
9
|
+
java_import java.io.BufferedReader
|
10
|
+
java_import java.util.zip.GZIPInputStream
|
11
|
+
java_import java.util.zip.ZipException
|
12
|
+
|
11
13
|
class ReadZipFile < Base
|
12
14
|
def handle_specifically(watched_file)
|
13
15
|
add_or_update_sincedb_collection(watched_file) unless sincedb_collection.member?(watched_file.sincedb_key)
|
@@ -18,34 +20,40 @@ module FileWatch module ReadMode module Handlers
|
|
18
20
|
# fast forward through the lines until we reach unseen content?
|
19
21
|
# meaning that we can quit in the middle of a zip file
|
20
22
|
key = watched_file.sincedb_key
|
21
|
-
|
22
|
-
|
23
|
-
gzip_stream = GZIPInputStream.new(file_stream)
|
24
|
-
decoder = InputStreamReader.new(gzip_stream, "UTF-8")
|
25
|
-
buffered = BufferedReader.new(decoder)
|
26
|
-
while (line = buffered.readLine(false))
|
27
|
-
watched_file.listener.accept(line)
|
28
|
-
# can't quit, if we did then we would incorrectly write a 'completed' sincedb entry
|
29
|
-
# what do we do about quit when we have just begun reading the zipped file (e.g. pipeline reloading)
|
30
|
-
# should we track lines read in the sincedb and
|
31
|
-
# fast forward through the lines until we reach unseen content?
|
32
|
-
# meaning that we can quit in the middle of a zip file
|
33
|
-
end
|
34
|
-
watched_file.listener.eof
|
35
|
-
rescue ZipException => e
|
36
|
-
logger.error("Cannot decompress the gzip file at path: #{watched_file.path}")
|
37
|
-
watched_file.listener.error
|
38
|
-
else
|
39
|
-
sincedb_collection.store_last_read(key, watched_file.last_stat_size)
|
40
|
-
sincedb_collection.request_disk_flush
|
41
|
-
watched_file.listener.deleted
|
23
|
+
|
24
|
+
if @settings.check_archive_validity && corrupted?(watched_file)
|
42
25
|
watched_file.unwatch
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
26
|
+
else
|
27
|
+
begin
|
28
|
+
file_stream = FileInputStream.new(watched_file.path)
|
29
|
+
gzip_stream = GZIPInputStream.new(file_stream)
|
30
|
+
decoder = InputStreamReader.new(gzip_stream, "UTF-8")
|
31
|
+
buffered = BufferedReader.new(decoder)
|
32
|
+
while (line = buffered.readLine(false))
|
33
|
+
watched_file.listener.accept(line)
|
34
|
+
# can't quit, if we did then we would incorrectly write a 'completed' sincedb entry
|
35
|
+
# what do we do about quit when we have just begun reading the zipped file (e.g. pipeline reloading)
|
36
|
+
# should we track lines read in the sincedb and
|
37
|
+
# fast forward through the lines until we reach unseen content?
|
38
|
+
# meaning that we can quit in the middle of a zip file
|
39
|
+
end
|
40
|
+
watched_file.listener.eof
|
41
|
+
rescue ZipException => e
|
42
|
+
logger.error("Cannot decompress the gzip file at path: #{watched_file.path}", :exception => e.class,
|
43
|
+
:message => e.message, :backtrace => e.backtrace)
|
44
|
+
watched_file.listener.error
|
45
|
+
else
|
46
|
+
sincedb_collection.store_last_read(key, watched_file.last_stat_size)
|
47
|
+
sincedb_collection.request_disk_flush
|
48
|
+
watched_file.listener.deleted
|
49
|
+
watched_file.unwatch
|
50
|
+
ensure
|
51
|
+
# rescue each close individually so all close attempts are tried
|
52
|
+
close_and_ignore_ioexception(buffered) unless buffered.nil?
|
53
|
+
close_and_ignore_ioexception(decoder) unless decoder.nil?
|
54
|
+
close_and_ignore_ioexception(gzip_stream) unless gzip_stream.nil?
|
55
|
+
close_and_ignore_ioexception(file_stream) unless file_stream.nil?
|
56
|
+
end
|
49
57
|
end
|
50
58
|
sincedb_collection.clear_watched_file(key)
|
51
59
|
end
|
@@ -56,7 +64,28 @@ module FileWatch module ReadMode module Handlers
|
|
56
64
|
begin
|
57
65
|
closeable.close
|
58
66
|
rescue Exception => e # IOException can be thrown by any of the Java classes that implement the Closable interface.
|
59
|
-
logger.warn("Ignoring an IOException when closing an instance of #{closeable.class.name}",
|
67
|
+
logger.warn("Ignoring an IOException when closing an instance of #{closeable.class.name}",
|
68
|
+
:exception => e.class, :message => e.message, :backtrace => e.backtrace)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def corrupted?(watched_file)
|
73
|
+
begin
|
74
|
+
file_stream = FileInputStream.new(watched_file.path)
|
75
|
+
gzip_stream = GZIPInputStream.new(file_stream)
|
76
|
+
buffer = Java::byte[8192].new
|
77
|
+
start = Time.new
|
78
|
+
until gzip_stream.read(buffer) == -1
|
79
|
+
end
|
80
|
+
return false
|
81
|
+
rescue ZipException => e
|
82
|
+
duration = Time.now - start
|
83
|
+
logger.warn("Detected corrupted archive #{watched_file.path} file won't be processed", :message => e.message,
|
84
|
+
:duration => duration.round(3))
|
85
|
+
return true
|
86
|
+
ensure
|
87
|
+
close_and_ignore_ioexception(gzip_stream) unless gzip_stream.nil?
|
88
|
+
close_and_ignore_ioexception(file_stream) unless file_stream.nil?
|
60
89
|
end
|
61
90
|
end
|
62
91
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
|
2
|
+
require 'filewatch/processor'
|
4
3
|
require_relative "handlers/base"
|
5
4
|
require_relative "handlers/read_file"
|
6
5
|
require_relative "handlers/read_zip_file"
|
@@ -9,20 +8,7 @@ module FileWatch module ReadMode
|
|
9
8
|
# Must handle
|
10
9
|
# :read_file
|
11
10
|
# :read_zip_file
|
12
|
-
class Processor
|
13
|
-
include LogStash::Util::Loggable
|
14
|
-
|
15
|
-
attr_reader :watch, :deletable_filepaths
|
16
|
-
|
17
|
-
def initialize(settings)
|
18
|
-
@settings = settings
|
19
|
-
@deletable_filepaths = []
|
20
|
-
end
|
21
|
-
|
22
|
-
def add_watch(watch)
|
23
|
-
@watch = watch
|
24
|
-
self
|
25
|
-
end
|
11
|
+
class Processor < FileWatch::Processor
|
26
12
|
|
27
13
|
def initialize_handlers(sincedb_collection, observer)
|
28
14
|
# we deviate from the tail mode handler initialization here
|
@@ -48,24 +34,23 @@ module FileWatch module ReadMode
|
|
48
34
|
private
|
49
35
|
|
50
36
|
def process_watched(watched_files)
|
51
|
-
logger.trace(
|
37
|
+
logger.trace(__method__.to_s)
|
52
38
|
# Handles watched_files in the watched state.
|
53
39
|
# for a slice of them:
|
54
40
|
# move to the active state
|
55
41
|
# should never have been active before
|
56
42
|
# how much of the max active window is available
|
57
|
-
to_take = @settings.max_active - watched_files.count{|wf| wf.active?}
|
43
|
+
to_take = @settings.max_active - watched_files.count { |wf| wf.active? }
|
58
44
|
if to_take > 0
|
59
|
-
watched_files.select
|
60
|
-
path = watched_file.path
|
45
|
+
watched_files.select(&:watched?).take(to_take).each do |watched_file|
|
61
46
|
begin
|
62
|
-
watched_file
|
47
|
+
restat(watched_file)
|
63
48
|
watched_file.activate
|
64
49
|
rescue Errno::ENOENT
|
65
|
-
common_deleted_reaction(watched_file,
|
50
|
+
common_deleted_reaction(watched_file, __method__)
|
66
51
|
next
|
67
52
|
rescue => e
|
68
|
-
common_error_reaction(
|
53
|
+
common_error_reaction(watched_file, e, __method__)
|
69
54
|
next
|
70
55
|
end
|
71
56
|
break if watch.quit?
|
@@ -74,7 +59,7 @@ module FileWatch module ReadMode
|
|
74
59
|
now = Time.now.to_i
|
75
60
|
if (now - watch.lastwarn_max_files) > MAX_FILES_WARN_INTERVAL
|
76
61
|
waiting = watched_files.size - @settings.max_active
|
77
|
-
logger.warn(@settings.max_warn_msg
|
62
|
+
logger.warn("#{@settings.max_warn_msg}, files yet to open: #{waiting}")
|
78
63
|
watch.lastwarn_max_files = now
|
79
64
|
end
|
80
65
|
end
|
@@ -83,17 +68,18 @@ module FileWatch module ReadMode
|
|
83
68
|
## TODO add process_rotation_in_progress
|
84
69
|
|
85
70
|
def process_active(watched_files)
|
86
|
-
logger.trace(
|
71
|
+
logger.trace(__method__.to_s)
|
87
72
|
# Handles watched_files in the active state.
|
88
|
-
watched_files.
|
89
|
-
|
73
|
+
watched_files.each do |watched_file|
|
74
|
+
next unless watched_file.active?
|
75
|
+
|
90
76
|
begin
|
91
|
-
watched_file
|
77
|
+
restat(watched_file)
|
92
78
|
rescue Errno::ENOENT
|
93
|
-
common_deleted_reaction(watched_file,
|
79
|
+
common_deleted_reaction(watched_file, __method__)
|
94
80
|
next
|
95
81
|
rescue => e
|
96
|
-
common_error_reaction(
|
82
|
+
common_error_reaction(watched_file, e, __method__)
|
97
83
|
next
|
98
84
|
end
|
99
85
|
break if watch.quit?
|
@@ -114,19 +100,19 @@ module FileWatch module ReadMode
|
|
114
100
|
def common_detach_when_allread(watched_file)
|
115
101
|
watched_file.unwatch
|
116
102
|
watched_file.listener.reading_completed
|
117
|
-
|
118
|
-
logger.trace("
|
103
|
+
add_deletable_path watched_file.path
|
104
|
+
logger.trace? && logger.trace("whole file read, removing from collection", :path => watched_file.path)
|
119
105
|
end
|
120
106
|
|
121
107
|
def common_deleted_reaction(watched_file, action)
|
122
108
|
# file has gone away or we can't read it anymore.
|
123
109
|
watched_file.unwatch
|
124
|
-
|
125
|
-
logger.trace("#{action} - stat failed
|
110
|
+
add_deletable_path watched_file.path
|
111
|
+
logger.trace? && logger.trace("#{action} - stat failed, removing from collection", :path => watched_file.path)
|
126
112
|
end
|
127
113
|
|
128
|
-
def common_error_reaction(
|
129
|
-
logger.error("#{action} - other error
|
114
|
+
def common_error_reaction(watched_file, error, action)
|
115
|
+
logger.error("#{action} - other error", error_details(error, watched_file))
|
130
116
|
end
|
131
117
|
end
|
132
118
|
end end
|
data/lib/filewatch/settings.rb
CHANGED
@@ -6,9 +6,10 @@ module FileWatch
|
|
6
6
|
attr_reader :max_active, :max_warn_msg, :lastwarn_max_files
|
7
7
|
attr_reader :sincedb_write_interval, :stat_interval, :discover_interval
|
8
8
|
attr_reader :exclude, :start_new_files_at, :file_chunk_count, :file_chunk_size
|
9
|
-
attr_reader :sincedb_path, :
|
9
|
+
attr_reader :sincedb_path, :sincedb_expiry_duration
|
10
10
|
attr_reader :file_sort_by, :file_sort_direction
|
11
11
|
attr_reader :exit_after_read
|
12
|
+
attr_reader :check_archive_validity
|
12
13
|
|
13
14
|
def self.from_options(opts)
|
14
15
|
new.add_options(opts)
|
@@ -40,7 +41,6 @@ module FileWatch
|
|
40
41
|
@file_chunk_size = @opts[:file_chunk_size]
|
41
42
|
@close_older = @opts[:close_older]
|
42
43
|
@ignore_older = @opts[:ignore_older]
|
43
|
-
@sincedb_write_interval = @opts[:sincedb_write_interval]
|
44
44
|
@stat_interval = @opts[:stat_interval]
|
45
45
|
@discover_interval = @opts[:discover_interval]
|
46
46
|
@exclude = Array(@opts[:exclude])
|
@@ -52,6 +52,7 @@ module FileWatch
|
|
52
52
|
@file_sort_by = @opts[:file_sort_by]
|
53
53
|
@file_sort_direction = @opts[:file_sort_direction]
|
54
54
|
@exit_after_read = @opts[:exit_after_read]
|
55
|
+
@check_archive_validity = @opts[:check_archive_validity]
|
55
56
|
self
|
56
57
|
end
|
57
58
|
|
@@ -56,12 +56,12 @@ module FileWatch
|
|
56
56
|
logger.trace("open: count of keys read: #{@sincedb.keys.size}")
|
57
57
|
rescue => e
|
58
58
|
#No existing sincedb to load
|
59
|
-
logger.trace("open: error:
|
59
|
+
logger.trace("open: error:", :path => path, :exception => e.class, :message => e.message)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
def associate(watched_file)
|
64
|
-
logger.trace("associate: finding",
|
64
|
+
logger.trace? && logger.trace("associate: finding", :path => watched_file.path, :inode => watched_file.sincedb_key.inode)
|
65
65
|
sincedb_value = find(watched_file)
|
66
66
|
if sincedb_value.nil?
|
67
67
|
# sincedb has no record of this inode
|
@@ -71,7 +71,8 @@ module FileWatch
|
|
71
71
|
logger.trace("associate: unmatched")
|
72
72
|
return true
|
73
73
|
end
|
74
|
-
logger.trace("associate: found sincedb record",
|
74
|
+
logger.trace? && logger.trace("associate: found sincedb record", :filename => watched_file.filename,
|
75
|
+
:sincedb_key => watched_file.sincedb_key, :sincedb_value => sincedb_value)
|
75
76
|
if sincedb_value.watched_file.nil?
|
76
77
|
# not associated
|
77
78
|
if sincedb_value.path_in_sincedb.nil?
|
@@ -106,7 +107,8 @@ module FileWatch
|
|
106
107
|
# after the original is deleted
|
107
108
|
# are not yet in the delete phase, let this play out
|
108
109
|
existing_watched_file = sincedb_value.watched_file
|
109
|
-
logger.trace("----------------- >> associate: the found sincedb_value has a watched_file - this is a rename",
|
110
|
+
logger.trace? && logger.trace("----------------- >> associate: the found sincedb_value has a watched_file - this is a rename",
|
111
|
+
:this_watched_file => watched_file.details, :existing_watched_file => existing_watched_file.details)
|
110
112
|
watched_file.rotation_in_progress
|
111
113
|
true
|
112
114
|
end
|
@@ -149,8 +151,8 @@ module FileWatch
|
|
149
151
|
end
|
150
152
|
|
151
153
|
def watched_file_deleted(watched_file)
|
152
|
-
|
153
|
-
|
154
|
+
value = @sincedb[watched_file.sincedb_key]
|
155
|
+
value.unset_watched_file if value
|
154
156
|
end
|
155
157
|
|
156
158
|
def store_last_read(key, pos)
|
@@ -178,24 +180,24 @@ module FileWatch
|
|
178
180
|
get(key).watched_file.nil?
|
179
181
|
end
|
180
182
|
|
181
|
-
private
|
182
|
-
|
183
183
|
def flush_at_interval
|
184
|
-
now = Time.now
|
185
|
-
delta = now - @sincedb_last_write
|
184
|
+
now = Time.now
|
185
|
+
delta = now.to_i - @sincedb_last_write
|
186
186
|
if delta >= @settings.sincedb_write_interval
|
187
187
|
logger.debug("writing sincedb (delta since last write = #{delta})")
|
188
188
|
sincedb_write(now)
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
+
private
|
193
|
+
|
192
194
|
def handle_association(sincedb_value, watched_file)
|
193
195
|
watched_file.update_bytes_read(sincedb_value.position)
|
194
196
|
sincedb_value.set_watched_file(watched_file)
|
195
197
|
watched_file.initial_completed
|
196
198
|
if watched_file.all_read?
|
197
199
|
watched_file.ignore
|
198
|
-
logger.trace("handle_association fully read, ignoring.....",
|
200
|
+
logger.trace? && logger.trace("handle_association fully read, ignoring.....", :watched_file => watched_file.details, :sincedb_value => sincedb_value)
|
199
201
|
end
|
200
202
|
end
|
201
203
|
|
@@ -208,33 +210,33 @@ module FileWatch
|
|
208
210
|
end
|
209
211
|
end
|
210
212
|
|
211
|
-
def sincedb_write(time = Time.now
|
212
|
-
logger.trace("sincedb_write:
|
213
|
+
def sincedb_write(time = Time.now)
|
214
|
+
logger.trace("sincedb_write: #{path} (time = #{time})")
|
213
215
|
begin
|
214
|
-
@write_method.call
|
216
|
+
@write_method.call(time)
|
215
217
|
@serializer.expired_keys.each do |key|
|
216
218
|
@sincedb[key].unset_watched_file
|
217
219
|
delete(key)
|
218
|
-
logger.trace("sincedb_write: cleaned",
|
220
|
+
logger.trace? && logger.trace("sincedb_write: cleaned", :key => key)
|
219
221
|
end
|
220
|
-
@sincedb_last_write = time
|
222
|
+
@sincedb_last_write = time.to_i
|
221
223
|
@write_requested = false
|
222
224
|
rescue Errno::EACCES
|
223
225
|
# no file handles free perhaps
|
224
226
|
# maybe it will work next time
|
225
|
-
logger.trace("sincedb_write:
|
227
|
+
logger.trace("sincedb_write: #{path} error: #{$!}")
|
226
228
|
end
|
227
229
|
end
|
228
230
|
|
229
|
-
def atomic_write
|
231
|
+
def atomic_write(time)
|
230
232
|
FileHelper.write_atomically(@full_path) do |io|
|
231
|
-
@serializer.serialize(@sincedb, io)
|
233
|
+
@serializer.serialize(@sincedb, io, time.to_f)
|
232
234
|
end
|
233
235
|
end
|
234
236
|
|
235
|
-
def non_atomic_write
|
237
|
+
def non_atomic_write(time)
|
236
238
|
IO.open(IO.sysopen(@full_path, "w+")) do |io|
|
237
|
-
@serializer.serialize(@sincedb, io)
|
239
|
+
@serializer.serialize(@sincedb, io, time.to_f)
|
238
240
|
end
|
239
241
|
end
|
240
242
|
end
|
@@ -3,24 +3,19 @@
|
|
3
3
|
module FileWatch module Stat
|
4
4
|
class Generic
|
5
5
|
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :inode, :modified_at, :size, :inode_struct
|
7
7
|
|
8
8
|
def initialize(source)
|
9
|
-
@source = source
|
10
|
-
@identifier = nil
|
9
|
+
@source = source # Pathname
|
11
10
|
restat
|
12
11
|
end
|
13
12
|
|
14
|
-
def add_identifier(identifier) self; end
|
15
|
-
|
16
13
|
def restat
|
17
|
-
|
18
|
-
@inode =
|
19
|
-
@modified_at =
|
20
|
-
@size =
|
21
|
-
@
|
22
|
-
@dev_minor = @inner_stat.dev_minor
|
23
|
-
@inode_struct = InodeStruct.new(@inode, @dev_major, @dev_minor)
|
14
|
+
stat = @source.stat
|
15
|
+
@inode = stat.ino.to_s
|
16
|
+
@modified_at = stat.mtime.to_f
|
17
|
+
@size = stat.size
|
18
|
+
@inode_struct = InodeStruct.new(@inode, stat.dev_major, stat.dev_minor)
|
24
19
|
end
|
25
20
|
|
26
21
|
def windows?
|
@@ -28,7 +23,7 @@ module FileWatch module Stat
|
|
28
23
|
end
|
29
24
|
|
30
25
|
def inspect
|
31
|
-
"
|
26
|
+
"<#{self.class.name} size=#{@size}, modified_at=#{@modified_at}, inode='#{@inode}', inode_struct=#{@inode_struct}>"
|
32
27
|
end
|
33
28
|
end
|
34
29
|
end end
|