logstash-input-file 4.1.18 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
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