logstash-input-file 4.1.18 → 4.2.0

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: dc2b7f39bcc8e3dfb894ea72af1b07e78fff73bf97ad12614a9ec440fed0c2d1
4
- data.tar.gz: 6715064a8a25a13538cc07216f5c479f79dd2d3ba73a267377cd357c6e27ea8d
3
+ metadata.gz: 6cdc2495fe9eb7a2c84aaaac6ea922a6034a9ad1bd8223f021ed9bd77fedae74
4
+ data.tar.gz: 4e6ba1c9fc044ff6cd93cbc92c16d114415357877ea75ad2fce375514517f0d7
5
5
  SHA512:
6
- metadata.gz: fbc9d7cd0f7b50be21721bfe0cb7c26a1e87a1f5697f4a01f14dcdc14a8449c9a9d14ddec58f3ec1b8bd611e624855b538155af8f2924604fb9f1cf120de4e22
7
- data.tar.gz: 44b4bdb7b356a6494cb1cde6bf48395d61222234d2ec6cfb134d551a20ed1ab08043b23266b5bc75854b85577d22a1fd36d5b40c17213eb10df68f2903086146
6
+ metadata.gz: a790d7f2a79551d8e8a96ca8cee597c1baba4dd9eabff1f9cc806432072a58826c6066922431f020105d7d86a53b22a2a0136e3c132d1b4d532f844a4a815f2e
7
+ data.tar.gz: 0d4528eab5b7c56b9b6b62b7f0e7124c8bd47745ac46fb915210a7647021fd3fd0f97f4ef031d14fdd6ec03b28b697dd255c9ec9676d888cbf1107d987609c92
@@ -1,3 +1,7 @@
1
+ ## 4.2.0
2
+ - Fix: watched files performance with huge filesets [#268](https://github.com/logstash-plugins/logstash-input-file/pull/268)
3
+ - Updated logging to include full traces in debug (and trace) levels
4
+
1
5
  ## 4.1.18
2
6
  - Fix: release watched files on completion (in read-mode) [#271](https://github.com/logstash-plugins/logstash-input-file/pull/271)
3
7
 
@@ -9,6 +9,8 @@ module FileWatch
9
9
  # associated with a sincedb entry if one can be found
10
10
  include LogStash::Util::Loggable
11
11
 
12
+ attr_reader :watched_files_collection
13
+
12
14
  def initialize(watched_files_collection, sincedb_collection, settings)
13
15
  @watching = Concurrent::Array.new
14
16
  @exclude = Concurrent::Array.new
@@ -37,8 +39,7 @@ module FileWatch
37
39
  @exclude.each do |pattern|
38
40
  if watched_file.pathname.basename.fnmatch?(pattern)
39
41
  if new_discovery
40
- logger.trace("Discoverer can_exclude?: #{watched_file.path}: skipping " +
41
- "because it matches exclude #{pattern}")
42
+ logger.trace("skipping file because it matches exclude", :path => watched_file.path, :pattern => pattern)
42
43
  end
43
44
  watched_file.unwatch
44
45
  return true
@@ -56,13 +57,13 @@ module FileWatch
56
57
  end
57
58
 
58
59
  def discover_any_files(path, ongoing)
59
- fileset = Dir.glob(path).select{|f| File.file?(f)}
60
- logger.trace("discover_files", "count" => fileset.size)
60
+ fileset = Dir.glob(path).select { |f| File.file?(f) }
61
+ logger.trace("discover_files", :count => fileset.size)
61
62
  fileset.each do |file|
62
- pathname = Pathname.new(file)
63
63
  new_discovery = false
64
- watched_file = @watched_files_collection.watched_file_by_path(file)
64
+ watched_file = @watched_files_collection.get(file)
65
65
  if watched_file.nil?
66
+ pathname = Pathname.new(file)
66
67
  begin
67
68
  path_stat = PathStatClass.new(pathname)
68
69
  rescue Errno::ENOENT
@@ -74,7 +75,7 @@ module FileWatch
74
75
  # if it already unwatched or its excluded then we can skip
75
76
  next if watched_file.unwatched? || can_exclude?(watched_file, new_discovery)
76
77
 
77
- logger.trace("discover_files handling:", "new discovery"=> new_discovery, "watched_file details" => watched_file.details)
78
+ logger.trace? && logger.trace("handling:", :new_discovery => new_discovery, :watched_file => watched_file.details)
78
79
 
79
80
  if new_discovery
80
81
  watched_file.initial_completed if ongoing
@@ -86,7 +87,7 @@ module FileWatch
86
87
  # associated with a different watched_file
87
88
  if @sincedb_collection.associate(watched_file)
88
89
  if watched_file.file_ignorable?
89
- logger.trace("Discoverer discover_files: #{file}: skipping because it was last modified more than #{@settings.ignore_older} seconds ago")
90
+ logger.trace("skipping file because it was last modified more than #{@settings.ignore_older} seconds ago", :path => file)
90
91
  # on discovery ignorable watched_files are put into the ignored state and that
91
92
  # updates the size from the internal stat
92
93
  # so the existing contents are not read.
@@ -62,8 +62,7 @@ module FileWatch
62
62
  @sincedb_collection = SincedbCollection.new(@settings)
63
63
  @sincedb_collection.open
64
64
  discoverer = Discoverer.new(watched_files_collection, @sincedb_collection, @settings)
65
- @watch = Watch.new(discoverer, watched_files_collection, @settings)
66
- @watch.add_processor build_specific_processor(@settings)
65
+ @watch = Watch.new(discoverer, build_specific_processor(@settings), @settings)
67
66
  end
68
67
 
69
68
  def watch_this(path)
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ require "logstash/util/loggable"
3
+ require 'concurrent/atomic/atomic_reference'
4
+
5
+ module FileWatch
6
+ class Processor
7
+ include LogStash::Util::Loggable
8
+
9
+ attr_reader :watch
10
+
11
+ def initialize(settings)
12
+ @settings = settings
13
+ @deletable_paths = Concurrent::AtomicReference.new []
14
+ end
15
+
16
+ def add_watch(watch)
17
+ @watch = watch
18
+ self
19
+ end
20
+
21
+ def clear_deletable_paths
22
+ @deletable_paths.get_and_set []
23
+ end
24
+
25
+ def add_deletable_path(path)
26
+ @deletable_paths.get << path
27
+ end
28
+
29
+ def restat(watched_file)
30
+ changed = watched_file.restat!
31
+ if changed
32
+ # the collection (when sorted by modified_at) needs to re-sort every time watched-file is modified,
33
+ # we can perform these update operation while processing files (stat interval) instead of having to
34
+ # re-sort the whole collection every time an entry is accessed
35
+ @watch.watched_files_collection.update(watched_file)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def error_details(error, watched_file)
42
+ details = { :path => watched_file.path,
43
+ :exception => error.class,
44
+ :message => error.message,
45
+ :backtrace => error.backtrace }
46
+ if logger.debug?
47
+ details[:file] = watched_file
48
+ else
49
+ details[:backtrace] = details[:backtrace].take(8) if details[:backtrace]
50
+ end
51
+ details
52
+ end
53
+
54
+ end
55
+ end
@@ -34,19 +34,21 @@ module FileWatch module ReadMode module Handlers
34
34
 
35
35
  def open_file(watched_file)
36
36
  return true if watched_file.file_open?
37
- logger.trace("opening #{watched_file.path}")
37
+ logger.trace? && logger.trace("opening", :path => watched_file.path)
38
38
  begin
39
39
  watched_file.open
40
- rescue
40
+ rescue => e
41
41
  # don't emit this message too often. if a file that we can't
42
42
  # read is changing a lot, we'll try to open it more often, and spam the logs.
43
43
  now = Time.now.to_i
44
44
  logger.trace("opening OPEN_WARN_INTERVAL is '#{OPEN_WARN_INTERVAL}'")
45
45
  if watched_file.last_open_warning_at.nil? || now - watched_file.last_open_warning_at > OPEN_WARN_INTERVAL
46
- logger.warn("failed to open #{watched_file.path}: #{$!.inspect}, #{$!.backtrace.take(3)}")
46
+ backtrace = e.backtrace
47
+ backtrace = backtrace.take(3) if backtrace && !logger.debug?
48
+ logger.warn("failed to open", :path => watched_file.path, :exception => e.class, :message => e.message, :backtrace => backtrace)
47
49
  watched_file.last_open_warning_at = now
48
50
  else
49
- logger.trace("suppressed warning for `failed to open` #{watched_file.path}: #{$!.inspect}")
51
+ logger.trace("suppressed warning (failed to open)", :path => watched_file.path, :exception => e.class, :message => e.message)
50
52
  end
51
53
  watched_file.watch # set it back to watch so we can try it again
52
54
  end
@@ -75,7 +77,7 @@ module FileWatch module ReadMode module Handlers
75
77
  watched_file.update_bytes_read(sincedb_value.position)
76
78
  else
77
79
  sincedb_value.set_watched_file(watched_file)
78
- logger.trace("add_or_update_sincedb_collection: switching from...", "watched_file details" => watched_file.details)
80
+ logger.trace("add_or_update_sincedb_collection: switching from", :watched_file => watched_file.details)
79
81
  watched_file.rotate_from(existing_watched_file)
80
82
  end
81
83
 
@@ -92,7 +94,7 @@ module FileWatch module ReadMode module Handlers
92
94
  def add_new_value_sincedb_collection(watched_file)
93
95
  sincedb_value = SincedbValue.new(0)
94
96
  sincedb_value.set_watched_file(watched_file)
95
- logger.trace("add_new_value_sincedb_collection: #{watched_file.path}", "position" => sincedb_value.position)
97
+ logger.trace("add_new_value_sincedb_collection:", :path => watched_file.path, :position => sincedb_value.position)
96
98
  sincedb_collection.set(watched_file.sincedb_key, sincedb_value)
97
99
  end
98
100
  end
@@ -31,7 +31,7 @@ module FileWatch module ReadMode module Handlers
31
31
  end
32
32
 
33
33
  def controlled_read(watched_file, loop_control)
34
- logger.trace("reading...", "iterations" => loop_control.count, "amount" => loop_control.size, "filename" => watched_file.filename)
34
+ logger.trace? && logger.trace("reading...", :filename => watched_file.filename, :iterations => loop_control.count, :amount => loop_control.size)
35
35
  loop_control.count.times do
36
36
  break if quit?
37
37
  begin
@@ -43,22 +43,35 @@ module FileWatch module ReadMode module Handlers
43
43
  delta = line.bytesize + @settings.delimiter_byte_size
44
44
  sincedb_collection.increment(watched_file.sincedb_key, delta)
45
45
  end
46
- rescue EOFError
47
- logger.error("controlled_read: eof error reading file", "path" => watched_file.path, "error" => e.inspect, "backtrace" => e.backtrace.take(8))
46
+ rescue EOFError => e
47
+ log_error("controlled_read: eof error reading file", watched_file, e)
48
48
  loop_control.flag_read_error
49
49
  break
50
- rescue Errno::EWOULDBLOCK, Errno::EINTR
51
- logger.error("controlled_read: block or interrupt error reading file", "path" => watched_file.path, "error" => e.inspect, "backtrace" => e.backtrace.take(8))
50
+ rescue Errno::EWOULDBLOCK, Errno::EINTR => e
51
+ log_error("controlled_read: block or interrupt error reading file", watched_file, e)
52
52
  watched_file.listener.error
53
53
  loop_control.flag_read_error
54
54
  break
55
55
  rescue => e
56
- logger.error("controlled_read: general error reading file", "path" => watched_file.path, "error" => e.inspect, "backtrace" => e.backtrace.take(8))
56
+ log_error("controlled_read: general error reading file", watched_file, e)
57
57
  watched_file.listener.error
58
58
  loop_control.flag_read_error
59
59
  break
60
60
  end
61
61
  end
62
62
  end
63
+
64
+ def log_error(msg, watched_file, error)
65
+ details = { :path => watched_file.path,
66
+ :exception => error.class,
67
+ :message => error.message,
68
+ :backtrace => error.backtrace }
69
+ if logger.debug?
70
+ details[:file] = watched_file
71
+ else
72
+ details[:backtrace] = details[:backtrace].take(8) if details[:backtrace]
73
+ end
74
+ logger.error(msg, details)
75
+ end
63
76
  end
64
77
  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)
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
- require "logstash/util/loggable"
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("Watched processing")
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 {|wf| wf.watched?}.take(to_take).each do |watched_file|
60
- path = watched_file.path
45
+ watched_files.select(&:watched?).take(to_take).each do |watched_file|
61
46
  begin
62
- watched_file.restat
47
+ restat(watched_file)
63
48
  watched_file.activate
64
49
  rescue Errno::ENOENT
65
- common_deleted_reaction(watched_file, "Watched")
50
+ common_deleted_reaction(watched_file, __method__)
66
51
  next
67
52
  rescue => e
68
- common_error_reaction(path, e, "Watched")
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 + ", files yet to open: #{waiting}")
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("Active processing")
71
+ logger.trace(__method__.to_s)
87
72
  # Handles watched_files in the active state.
88
- watched_files.select {|wf| wf.active? }.each do |watched_file|
89
- path = watched_file.path
73
+ watched_files.each do |watched_file|
74
+ next unless watched_file.active?
75
+
90
76
  begin
91
- watched_file.restat
77
+ restat(watched_file)
92
78
  rescue Errno::ENOENT
93
- common_deleted_reaction(watched_file, "Active")
79
+ common_deleted_reaction(watched_file, __method__)
94
80
  next
95
81
  rescue => e
96
- common_error_reaction(path, e, "Active")
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
- deletable_filepaths << watched_file.path
118
- logger.trace("Whole file read: #{watched_file.path}, removing from collection")
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
- deletable_filepaths << watched_file.path
125
- logger.trace("#{action} - stat failed: #{watched_file.path}, removing from collection")
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(path, error, action)
129
- logger.error("#{action} - other error #{path}: (#{error.message}, #{error.backtrace.take(8).inspect})")
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
@@ -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: #{path}: #{e.inspect}")
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", "inode" => watched_file.sincedb_key.inode, "path" => watched_file.path)
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", "filename" => watched_file.filename, "sincedb key" => watched_file.sincedb_key,"sincedb_value" => sincedb_value)
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", "this watched_file details" => watched_file.details, "other watched_file details" => existing_watched_file.details)
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
- return unless member?(watched_file.sincedb_key)
153
- get(watched_file.sincedb_key).unset_watched_file
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)
@@ -195,7 +197,7 @@ module FileWatch
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.....", "watched file" => watched_file.details, "sincedb value" => sincedb_value)
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
 
@@ -214,8 +216,8 @@ module FileWatch
214
216
  @write_method.call
215
217
  @serializer.expired_keys.each do |key|
216
218
  @sincedb[key].unset_watched_file
217
- delete(key)
218
- logger.trace("sincedb_write: cleaned", "key" => "'#{key}'")
219
+ delete(key) # delete
220
+ logger.trace? && logger.trace("sincedb_write: cleaned", :key => key)
219
221
  end
220
222
  @sincedb_last_write = time
221
223
  @write_requested = false
@@ -3,24 +3,19 @@
3
3
  module FileWatch module Stat
4
4
  class Generic
5
5
 
6
- attr_reader :identifier, :inode, :modified_at, :size, :inode_struct
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
- @inner_stat = @source.stat
18
- @inode = @inner_stat.ino.to_s
19
- @modified_at = @inner_stat.mtime.to_f
20
- @size = @inner_stat.size
21
- @dev_major = @inner_stat.dev_major
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
- "<Generic size='#{@size}', modified_at='#{@modified_at}', inode='#{@inode}', inode_struct='#{@inode_struct}'>"
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