fluentd 1.14.6-x64-mingw32 → 1.15.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linux-test.yaml +1 -1
  3. data/.github/workflows/windows-test.yaml +4 -1
  4. data/CHANGELOG.md +85 -1
  5. data/fluentd.gemspec +1 -3
  6. data/lib/fluent/command/ctl.rb +4 -1
  7. data/lib/fluent/command/fluentd.rb +11 -6
  8. data/lib/fluent/config/literal_parser.rb +2 -2
  9. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  10. data/lib/fluent/config/yaml_parser/loader.rb +91 -0
  11. data/lib/fluent/config/yaml_parser/parser.rb +166 -0
  12. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  13. data/lib/fluent/config/yaml_parser.rb +56 -0
  14. data/lib/fluent/config.rb +14 -1
  15. data/lib/fluent/error.rb +3 -0
  16. data/lib/fluent/plugin/base.rb +19 -0
  17. data/lib/fluent/plugin/file_wrapper.rb +57 -113
  18. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  19. data/lib/fluent/plugin/in_tail/position_file.rb +1 -15
  20. data/lib/fluent/plugin/in_tail.rb +68 -48
  21. data/lib/fluent/plugin/out_file.rb +11 -1
  22. data/lib/fluent/plugin/out_forward/socket_cache.rb +2 -0
  23. data/lib/fluent/plugin/output.rb +2 -1
  24. data/lib/fluent/plugin/parser_syslog.rb +1 -1
  25. data/lib/fluent/plugin_helper/child_process.rb +3 -0
  26. data/lib/fluent/plugin_helper/server.rb +3 -1
  27. data/lib/fluent/plugin_helper/service_discovery.rb +2 -2
  28. data/lib/fluent/supervisor.rb +125 -31
  29. data/lib/fluent/system_config.rb +4 -2
  30. data/lib/fluent/version.rb +1 -1
  31. data/lib/fluent/win32api.rb +38 -0
  32. data/lib/fluent/winsvc.rb +5 -8
  33. data/test/command/test_ctl.rb +0 -1
  34. data/test/command/test_fluentd.rb +33 -0
  35. data/test/config/test_system_config.rb +5 -1
  36. data/test/config/test_types.rb +1 -1
  37. data/test/plugin/in_tail/test_io_handler.rb +14 -4
  38. data/test/plugin/in_tail/test_position_file.rb +0 -63
  39. data/test/plugin/out_forward/test_socket_cache.rb +26 -1
  40. data/test/plugin/test_base.rb +34 -0
  41. data/test/plugin/test_file_wrapper.rb +0 -73
  42. data/test/plugin/test_in_object_space.rb +9 -3
  43. data/test/plugin/test_in_syslog.rb +1 -1
  44. data/test/plugin/test_in_tail.rb +629 -353
  45. data/test/plugin/test_out_forward.rb +30 -20
  46. data/test/plugin/test_parser_syslog.rb +1 -1
  47. data/test/plugin_helper/test_cert_option.rb +1 -1
  48. data/test/plugin_helper/test_child_process.rb +16 -4
  49. data/test/test_config.rb +135 -4
  50. data/test/test_supervisor.rb +155 -0
  51. metadata +12 -39
@@ -0,0 +1,56 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'fluent/config/yaml_parser/loader'
18
+ require 'fluent/config/yaml_parser/parser'
19
+ require 'pathname'
20
+
21
+ module Fluent
22
+ module Config
23
+ module YamlParser
24
+ def self.parse(path)
25
+ context = Kernel.binding
26
+
27
+ unless context.respond_to?(:use_nil)
28
+ context.define_singleton_method(:use_nil) do
29
+ raise Fluent::SetNil
30
+ end
31
+ end
32
+
33
+ unless context.respond_to?(:use_default)
34
+ context.define_singleton_method(:use_default) do
35
+ raise Fluent::SetDefault
36
+ end
37
+ end
38
+
39
+ unless context.respond_to?(:hostname)
40
+ context.define_singleton_method(:hostname) do
41
+ Socket.gethostname
42
+ end
43
+ end
44
+
45
+ unless context.respond_to?(:worker_id)
46
+ context.define_singleton_method(:worker_id) do
47
+ ENV['SERVERENGINE_WORKER_ID'] || ''
48
+ end
49
+ end
50
+
51
+ s = Fluent::Config::YamlParser::Loader.new(context).load(Pathname.new(path))
52
+ Fluent::Config::YamlParser::Parser.new(s).build.to_element
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/fluent/config.rb CHANGED
@@ -17,6 +17,7 @@
17
17
  require 'fluent/config/error'
18
18
  require 'fluent/config/element'
19
19
  require 'fluent/configurable'
20
+ require 'fluent/config/yaml_parser'
20
21
 
21
22
  module Fluent
22
23
  module Config
@@ -25,7 +26,18 @@ module Fluent
25
26
  # @param additional_config [String] config which is added to last of config body
26
27
  # @param use_v1_config [Bool] config is formatted with v1 or not
27
28
  # @return [Fluent::Config]
28
- def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true)
29
+ def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil)
30
+ if type == :guess
31
+ config_file_ext = File.extname(config_path)
32
+ if config_file_ext == '.yaml' || config_file_ext == '.yml'
33
+ type = :yaml
34
+ end
35
+ end
36
+
37
+ if type == :yaml || type == :yml
38
+ return Fluent::Config::YamlParser.parse(config_path)
39
+ end
40
+
29
41
  config_fname = File.basename(config_path)
30
42
  config_basedir = File.dirname(config_path)
31
43
  config_data = File.open(config_path, "r:#{encoding}:utf-8") do |f|
@@ -36,6 +48,7 @@ module Fluent
36
48
  end
37
49
  s
38
50
  end
51
+
39
52
  Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config)
40
53
  end
41
54
 
data/lib/fluent/error.rb CHANGED
@@ -28,6 +28,9 @@ module Fluent
28
28
  class InvalidRootDirectory < UnrecoverableError
29
29
  end
30
30
 
31
+ class InvalidLockDirectory < UnrecoverableError
32
+ end
33
+
31
34
  # For internal use
32
35
  class UncatchableError < Exception
33
36
  end
@@ -31,6 +31,7 @@ module Fluent
31
31
  def initialize
32
32
  @log = nil
33
33
  super
34
+ @fluentd_lock_dir = ENV['FLUENTD_LOCK_DIR']
34
35
  @_state = State.new(false, false, false, false, false, false, false, false, false)
35
36
  @_context_router = nil
36
37
  @_fluentd_worker_id = nil
@@ -70,6 +71,24 @@ module Fluent
70
71
  true
71
72
  end
72
73
 
74
+ def get_lock_path(name)
75
+ name = name.gsub(/[^a-zA-Z0-9]/, "_")
76
+ File.join(@fluentd_lock_dir, "fluentd-#{name}.lock")
77
+ end
78
+
79
+ def acquire_worker_lock(name)
80
+ if @fluentd_lock_dir.nil?
81
+ raise InvalidLockDirectory, "can't acquire lock because FLUENTD_LOCK_DIR isn't set"
82
+ end
83
+ lock_path = get_lock_path(name)
84
+ File.open(lock_path, "w") do |f|
85
+ f.flock(File::LOCK_EX)
86
+ yield
87
+ end
88
+ # Update access time to prevent tmpwatch from deleting a lock file.
89
+ FileUtils.touch(lock_path);
90
+ end
91
+
73
92
  def string_safe_encoding(str)
74
93
  unless str.valid_encoding?
75
94
  str = str.scrub('?')
@@ -14,10 +14,12 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/win32api'
18
+
17
19
  module Fluent
18
20
  module FileWrapper
19
- def self.open(*args)
20
- io = WindowsFile.new(*args).io
21
+ def self.open(path, mode='r')
22
+ io = WindowsFile.new(path, mode).io
21
23
  if block_given?
22
24
  v = yield io
23
25
  io.close
@@ -35,126 +37,78 @@ module Fluent
35
37
  end
36
38
  end
37
39
 
38
- module WindowsFileExtension
39
- attr_reader :path
40
-
41
- def stat
42
- s = super
43
- s.instance_variable_set :@ino, @ino
44
- def s.ino; @ino; end
45
- s
46
- end
47
- end
48
-
49
- class Win32Error < StandardError
50
- require 'windows/error'
51
- include Windows::Error
52
-
53
- attr_reader :errcode, :msg
54
-
55
- WSABASEERR = 10000
56
-
57
- def initialize(errcode, msg = nil)
58
- @errcode = errcode
59
- @msg = msg
60
- end
61
-
62
- def format_english_message(errcode)
63
- buf = 0.chr * 260
64
- flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
65
- english_lang_id = 1033 # The result of MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
66
- FormatMessageA.call(flags, 0, errcode, english_lang_id, buf, buf.size, 0)
67
- buf.force_encoding(Encoding.default_external).strip
68
- end
69
-
70
- def to_s
71
- msg = super
72
- msg << ": code: #{@errcode}, #{format_english_message(@errcode)}"
73
- msg << " - #{@msg}" if @msg
74
- msg
75
- end
76
-
77
- def inspect
78
- "#<#{to_s}>"
79
- end
80
-
81
- def ==(other)
82
- return false if other.class != Win32Error
83
- @errcode == other.errcode && @msg == other.msg
84
- end
85
-
86
- def wsaerr?
87
- @errcode >= WSABASEERR
88
- end
89
- end
90
-
91
- # To open and get stat with setting FILE_SHARE_DELETE
92
40
  class WindowsFile
93
- require 'windows/file'
94
- require 'windows/error'
95
- require 'windows/handle'
96
- require 'windows/nio'
41
+ include File::Constants
97
42
 
98
- include Windows::Error
99
- include Windows::File
100
- include Windows::Handle
101
- include Windows::NIO
102
-
103
- def initialize(path, mode='r', sharemode=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
104
- @path = path
105
- @file_handle = INVALID_HANDLE_VALUE
106
- @mode = mode
43
+ attr_reader :io
107
44
 
45
+ INVALID_HANDLE_VALUE = -1
108
46
 
109
- access, creationdisposition, seektoend = case mode.delete('b')
110
- when "r" ; [FILE_GENERIC_READ , OPEN_EXISTING, false]
111
- when "r+"; [FILE_GENERIC_READ | FILE_GENERIC_WRITE, OPEN_ALWAYS , false]
112
- when "w" ; [FILE_GENERIC_WRITE , CREATE_ALWAYS, false]
113
- when "w+"; [FILE_GENERIC_READ | FILE_GENERIC_WRITE, CREATE_ALWAYS, false]
114
- when "a" ; [FILE_GENERIC_WRITE , OPEN_ALWAYS , true]
115
- when "a+"; [FILE_GENERIC_READ | FILE_GENERIC_WRITE, OPEN_ALWAYS , true]
116
- else raise "unknown mode '#{mode}'"
117
- end
118
-
119
- @file_handle = CreateFile.call(@path, access, sharemode,
120
- 0, creationdisposition, FILE_ATTRIBUTE_NORMAL, 0)
121
- if @file_handle == INVALID_HANDLE_VALUE
122
- win32err = Win32Error.new(Win32::API.last_error, path)
123
- errno = ServerEngine::RbWinSock.rb_w32_map_errno(win32err.errcode)
124
- if errno == Errno::EINVAL::Errno || win32err.wsaerr?
125
- # maybe failed to map
126
- raise win32err
127
- else
128
- raise SystemCallError.new(win32err.message, errno)
129
- end
47
+ def initialize(path, mode='r')
48
+ @path = path
49
+ @io = File.open(path, mode2flags(mode))
50
+ @file_handle = Win32API._get_osfhandle(@io.to_i)
51
+ @io.instance_variable_set(:@file_index, self.ino)
52
+ def @io.ino
53
+ @file_index
130
54
  end
131
55
  end
132
56
 
133
57
  def close
134
- CloseHandle.call(@file_handle)
58
+ @io.close
135
59
  @file_handle = INVALID_HANDLE_VALUE
136
60
  end
137
61
 
138
- def io
139
- fd = _open_osfhandle(@file_handle, 0)
140
- raise Errno::ENOENT if fd == -1
141
- io = File.for_fd(fd, @mode)
142
- io.instance_variable_set :@ino, self.ino
143
- io.instance_variable_set :@path, @path
144
- io.extend WindowsFileExtension
145
- io
146
- end
147
-
62
+ # To keep backward compatibility, we continue to use GetFileInformationByHandle()
63
+ # to get file id.
64
+ # Note that Ruby's File.stat uses GetFileInformationByHandleEx() with FileIdInfo
65
+ # and returned value is different with above one, former one is 64 bit while
66
+ # later one is 128bit.
148
67
  def ino
149
68
  by_handle_file_information = '\0'*(4+8+8+8+4+4+4+4+4+4) #72bytes
150
69
 
151
- unless GetFileInformationByHandle.call(@file_handle, by_handle_file_information)
70
+ unless Win32API.GetFileInformationByHandle(@file_handle, by_handle_file_information)
152
71
  return 0
153
72
  end
154
73
 
155
74
  by_handle_file_information.unpack("I11Q1")[11] # fileindex
156
75
  end
157
76
 
77
+ def stat
78
+ raise Errno::ENOENT if delete_pending
79
+ s = File.stat(@path)
80
+ s.instance_variable_set :@ino, self.ino
81
+ def s.ino; @ino; end
82
+ s
83
+ end
84
+
85
+ private
86
+
87
+ def mode2flags(mode)
88
+ # Always inject File::Constants::SHARE_DELETE
89
+ # https://github.com/fluent/fluentd/pull/3585#issuecomment-1101502617
90
+ # To enable SHARE_DELETE, BINARY is also required.
91
+ # https://bugs.ruby-lang.org/issues/11218
92
+ # https://github.com/ruby/ruby/blob/d6684f063bc53e3cab025bd39526eca3b480b5e7/win32/win32.c#L6332-L6345
93
+ flags = BINARY | SHARE_DELETE
94
+ case mode.delete("b")
95
+ when "r"
96
+ flags |= RDONLY
97
+ when "r+"
98
+ flags |= RDWR
99
+ when "w"
100
+ flags |= WRONLY | CREAT | TRUNC
101
+ when "w+"
102
+ flags |= RDWR | CREAT | TRUNC
103
+ when "a"
104
+ flags |= WRONLY | CREAT | APPEND
105
+ when "a+"
106
+ flags |= RDWR | CREAT | APPEND
107
+ else
108
+ raise Errno::EINVAL.new("Unsupported mode by Fluent::FileWrapper: #{mode}")
109
+ end
110
+ end
111
+
158
112
  # DeletePending is a Windows-specific file state that roughly means
159
113
  # "this file is queued for deletion, so close any open handlers"
160
114
  #
@@ -167,21 +121,11 @@ module Fluent
167
121
  bufsize = 1024
168
122
  buf = '\0' * bufsize
169
123
 
170
- unless GetFileInformationByHandleEx.call(@file_handle, file_standard_info, buf, bufsize)
124
+ unless Win32API.GetFileInformationByHandleEx(@file_handle, file_standard_info, buf, bufsize)
171
125
  return false
172
126
  end
173
127
 
174
128
  return buf.unpack("QQICC")[3] != 0
175
129
  end
176
-
177
- private :delete_pending
178
-
179
- def stat
180
- raise Errno::ENOENT if delete_pending
181
- s = File.stat(@path)
182
- s.instance_variable_set :@ino, self.ino
183
- def s.ino; @ino; end
184
- s
185
- end
186
130
  end
187
131
  end if Fluent.windows?
@@ -0,0 +1,204 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'fluent/plugin/input'
18
+
19
+ module Fluent::Plugin
20
+ class TailInput < Fluent::Plugin::Input
21
+ module GroupWatchParams
22
+ include Fluent::Configurable
23
+
24
+ DEFAULT_KEY = /.*/
25
+ DEFAULT_LIMIT = -1
26
+ REGEXP_JOIN = "_"
27
+
28
+ config_section :group, param_name: :group, required: false, multi: false do
29
+ desc 'Regex for extracting group\'s metadata'
30
+ config_param :pattern,
31
+ :regexp,
32
+ default: /^\/var\/log\/containers\/(?<podname>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\/[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace>[^_]+)_(?<container>.+)-(?<docker_id>[a-z0-9]{64})\.log$/
33
+
34
+ desc 'Period of time in which the group_line_limit is applied'
35
+ config_param :rate_period, :time, default: 5
36
+
37
+ config_section :rule, param_name: :rule, required: true, multi: true do
38
+ desc 'Key-value pairs for grouping'
39
+ config_param :match, :hash, value_type: :regexp, default: { namespace: [DEFAULT_KEY], podname: [DEFAULT_KEY] }
40
+ desc 'Maximum number of log lines allowed per group over a period of rate_period'
41
+ config_param :limit, :integer, default: DEFAULT_LIMIT
42
+ end
43
+ end
44
+ end
45
+
46
+ module GroupWatch
47
+ def self.included(mod)
48
+ mod.include GroupWatchParams
49
+ end
50
+
51
+ attr_reader :group_watchers, :default_group_key
52
+
53
+ def initialize
54
+ super
55
+ @group_watchers = {}
56
+ @group_keys = nil
57
+ @default_group_key = nil
58
+ end
59
+
60
+ def configure(conf)
61
+ super
62
+
63
+ unless @group.nil?
64
+ ## Ensuring correct time period syntax
65
+ @group.rule.each { |rule|
66
+ raise "Metadata Group Limit >= DEFAULT_LIMIT" unless rule.limit >= GroupWatchParams::DEFAULT_LIMIT
67
+ }
68
+
69
+ @group_keys = Regexp.compile(@group.pattern).named_captures.keys
70
+ @default_group_key = ([GroupWatchParams::DEFAULT_KEY] * @group_keys.length).join(GroupWatchParams::REGEXP_JOIN)
71
+
72
+ ## Ensures that "specific" rules (with larger number of `rule.match` keys)
73
+ ## have a higher priority against "generic" rules (with less number of `rule.match` keys).
74
+ ## This will be helpful when a file satisfies more than one rule.
75
+ @group.rule.sort_by! { |rule| -rule.match.length() }
76
+ construct_groupwatchers
77
+ @group_watchers[@default_group_key] ||= GroupWatcher.new(@group.rate_period, GroupWatchParams::DEFAULT_LIMIT)
78
+ end
79
+ end
80
+
81
+ def add_path_to_group_watcher(path)
82
+ return nil if @group.nil?
83
+ group_watcher = find_group_from_metadata(path)
84
+ group_watcher.add(path) unless group_watcher.include?(path)
85
+ group_watcher
86
+ end
87
+
88
+ def remove_path_from_group_watcher(path)
89
+ return if @group.nil?
90
+ group_watcher = find_group_from_metadata(path)
91
+ group_watcher.delete(path)
92
+ end
93
+
94
+ def construct_group_key(named_captures)
95
+ match_rule = []
96
+ @group_keys.each { |key|
97
+ match_rule.append(named_captures.fetch(key, GroupWatchParams::DEFAULT_KEY))
98
+ }
99
+ match_rule = match_rule.join(GroupWatchParams::REGEXP_JOIN)
100
+
101
+ match_rule
102
+ end
103
+
104
+ def construct_groupwatchers
105
+ @group.rule.each { |rule|
106
+ match_rule = construct_group_key(rule.match)
107
+ @group_watchers[match_rule] ||= GroupWatcher.new(@group.rate_period, rule.limit)
108
+ }
109
+ end
110
+
111
+ def find_group(metadata)
112
+ metadata_key = construct_group_key(metadata)
113
+ gw_key = @group_watchers.keys.find { |regexp| metadata_key.match?(regexp) && regexp != @default_group_key }
114
+ gw_key ||= @default_group_key
115
+
116
+ @group_watchers[gw_key]
117
+ end
118
+
119
+ def find_group_from_metadata(path)
120
+ begin
121
+ metadata = @group.pattern.match(path).named_captures
122
+ group_watcher = find_group(metadata)
123
+ rescue
124
+ log.warn "Cannot find group from metadata, Adding file in the default group"
125
+ group_watcher = @group_watchers[@default_group_key]
126
+ end
127
+
128
+ group_watcher
129
+ end
130
+ end
131
+
132
+ class GroupWatcher
133
+ attr_accessor :current_paths, :limit, :number_lines_read, :start_reading_time, :rate_period
134
+
135
+ FileCounter = Struct.new(
136
+ :number_lines_read,
137
+ :start_reading_time,
138
+ )
139
+
140
+ def initialize(rate_period = 60, limit = -1)
141
+ @current_paths = {}
142
+ @rate_period = rate_period
143
+ @limit = limit
144
+ end
145
+
146
+ def add(path)
147
+ @current_paths[path] = FileCounter.new(0, nil)
148
+ end
149
+
150
+ def include?(path)
151
+ @current_paths.key?(path)
152
+ end
153
+
154
+ def size
155
+ @current_paths.size
156
+ end
157
+
158
+ def delete(path)
159
+ @current_paths.delete(path)
160
+ end
161
+
162
+ def update_reading_time(path)
163
+ @current_paths[path].start_reading_time ||= Fluent::Clock.now
164
+ end
165
+
166
+ def update_lines_read(path, value)
167
+ @current_paths[path].number_lines_read += value
168
+ end
169
+
170
+ def reset_counter(path)
171
+ @current_paths[path].start_reading_time = nil
172
+ @current_paths[path].number_lines_read = 0
173
+ end
174
+
175
+ def time_spent_reading(path)
176
+ Fluent::Clock.now - @current_paths[path].start_reading_time
177
+ end
178
+
179
+ def limit_time_period_reached?(path)
180
+ time_spent_reading(path) < @rate_period
181
+ end
182
+
183
+ def limit_lines_reached?(path)
184
+ return true unless include?(path)
185
+ return true if @limit == 0
186
+
187
+ return false if @limit < 0
188
+ return false if @current_paths[path].number_lines_read < @limit / size
189
+
190
+ # update_reading_time(path)
191
+ if limit_time_period_reached?(path) # Exceeds limit
192
+ true
193
+ else # Does not exceed limit
194
+ reset_counter(path)
195
+ false
196
+ end
197
+ end
198
+
199
+ def to_s
200
+ super + " current_paths: #{@current_paths} rate_period: #{@rate_period} limit: #{@limit}"
201
+ end
202
+ end
203
+ end
204
+ end
@@ -250,20 +250,6 @@ module Fluent::Plugin
250
250
  end
251
251
  end
252
252
 
253
- TargetInfo = Struct.new(:path, :ino) do
254
- def ==(other)
255
- return false unless other.is_a?(TargetInfo)
256
- self.path == other.path
257
- end
258
-
259
- def hash
260
- self.path.hash
261
- end
262
-
263
- def eql?(other)
264
- return false unless other.is_a?(TargetInfo)
265
- self.path == other.path
266
- end
267
- end
253
+ TargetInfo = Struct.new(:path, :ino)
268
254
  end
269
255
  end