@@ -39,13 +39,7 @@ class LogStash::Outputs::File < LogStash::Outputs::Base
3939 # E.g: `/%{myfield}/`, `/test-%{myfield}/` are not valid paths
4040 config :path , :validate => :string , :required => true
4141
42- # The format to use when writing events to the file. This value
43- # supports any string and can include `%{name}` and other dynamic
44- # strings.
45- #
46- # If this setting is omitted, the full json representation of the
47- # event will be written as a single line.
48- config :message_format , :validate => :string , :deprecated => "You can achieve the same behavior with the 'line' codec"
42+ config :message_format , :validate => :string , :obsolete => "You can achieve the same behavior with the 'line' codec"
4943
5044 # Flush interval (in seconds) for flushing writes to log files.
5145 # 0 will flush on every message.
@@ -81,10 +75,8 @@ def register
8175 require "fileutils" # For mkdir_p
8276
8377 @files = { }
84- @files_lock = java . util . concurrent . locks . ReentrantReadWriteLock . new
85- @files_read_lock = @files_lock . readLock
86- @files_write_lock = @files_lock . writeLock
87-
78+ @io_mutex = Mutex . new
79+
8880 @path = File . expand_path ( path )
8981
9082 validate_path
@@ -131,33 +123,28 @@ def root_directory
131123 public
132124 def multi_receive_encoded ( events_and_encoded )
133125 encoded_by_path = Hash . new { |h , k | h [ k ] = [ ] }
134-
126+
135127 events_and_encoded . each do |event , encoded |
136- file_output_path = write_event ( event )
128+ file_output_path = event_path ( event )
137129 encoded_by_path [ file_output_path ] << encoded
138130 end
139131
140- encoded_by_path . each do |path , chunks |
141- fd = open ( path )
142- chunks . each ( &fd . method ( :write ) )
143- flush ( fd )
144- end
145-
146- close_stale_files
132+ @io_mutex . synchronize do
133+ encoded_by_path . each do |path , chunks |
134+ fd = open ( path )
135+ chunks . each { |chunk | fd . write ( chunk ) }
136+ fd . flush
137+ end
138+
139+ close_stale_files
140+ end
147141 end # def receive
148142
149- def with_lock ( lock )
150- lock . lock
151- yield
152- ensure
153- lock . unlock
154- end
155-
156143 public
157144 def close
158- @logger . debug ( "Close: closing files" )
159-
160- with_lock ( @files_read_lock ) do
145+ @io_mutex . synchronize do
146+ @logger . debug ( "Close: closing files" )
147+
161148 @files . each do |path , fd |
162149 begin
163150 fd . close
@@ -176,7 +163,7 @@ def inside_file_root?(log_path)
176163 end
177164
178165 private
179- def write_event ( event )
166+ def event_path ( event )
180167 file_output_path = generate_filepath ( event )
181168 if path_with_field_ref? && !inside_file_root? ( file_output_path )
182169 @logger . warn ( "File: the event tried to write outside the files root, writing the event to the failure file" , :event => event , :filename => @failure_path )
@@ -185,7 +172,6 @@ def write_event(event)
185172 file_output_path = @failure_path
186173 end
187174 @logger . debug ( "File, writing event to file." , :filename => file_output_path )
188-
189175
190176 file_output_path
191177 end
@@ -221,11 +207,9 @@ def flush_pending_files
221207 return unless Time . now - @last_flush_cycle >= flush_interval
222208 @logger . debug ( "Starting flush cycle" )
223209
224- with_lock ( @files_read_lock ) do
225- @files . each do |path , fd |
226- @logger . debug ( "Flushing file" , :path => path , :fd => fd )
227- fd . flush
228- end
210+ @files . each do |path , fd |
211+ @logger . debug ( "Flushing file" , :path => path , :fd => fd )
212+ fd . flush
229213 end
230214
231215 @last_flush_cycle = Time . now
@@ -237,24 +221,22 @@ def close_stale_files
237221 now = Time . now
238222 return unless now - @last_stale_cleanup_cycle >= @stale_cleanup_interval
239223
240- with_lock ( @files_write_lock ) do
241- @logger . info ( "Starting stale files cleanup cycle" , :files => @files )
242- inactive_files = @files . select { |path , fd | not fd . active }
243- @logger . debug ( "%d stale files found" % inactive_files . count , :inactive_files => inactive_files )
244- inactive_files . each do |path , fd |
245- @logger . info ( "Closing file %s" % path )
246- fd . close
247- @files . delete ( path )
248- end
249- # mark all files as inactive, a call to write will mark them as active again
250- @files . each { |path , fd | fd . active = false }
251- @last_stale_cleanup_cycle = now
224+ @logger . info ( "Starting stale files cleanup cycle" , :files => @files )
225+ inactive_files = @files . select { |path , fd | not fd . active }
226+ @logger . debug ( "%d stale files found" % inactive_files . count , :inactive_files => inactive_files )
227+ inactive_files . each do |path , fd |
228+ @logger . info ( "Closing file %s" % path )
229+ fd . close
230+ @files . delete ( path )
252231 end
232+ # mark all files as inactive, a call to write will mark them as active again
233+ @files . each { |path , fd | fd . active = false }
234+ @last_stale_cleanup_cycle = now
253235 end
254236
255237 private
256238 def cached? ( path )
257- with_lock ( @files_read_lock ) { @ files. include? ( path ) && !@files [ path ] . nil? }
239+ @ files. include? ( path ) && !@files [ path ] . nil?
258240 end
259241
260242 private
@@ -265,19 +247,20 @@ def deleted?(path)
265247 private
266248 def open ( path )
267249 if !deleted? ( path ) && cached? ( path )
268- with_lock ( @files_read_lock ) { return @files [ path ] }
269- elsif deleted? ( path )
270- with_lock ( @files_write_lock ) do
271- if @create_if_deleted
272- @logger . debug ( "Required path was deleted, creating the file again" , :path => path )
273- @files . delete ( path )
274- else
275- return @files [ path ] if cached? ( path )
276- end
250+ return @files [ path ]
251+ end
252+
253+ if deleted? ( path )
254+ if @create_if_deleted
255+ @logger . debug ( "Required path was deleted, creating the file again" , :path => path )
256+ @files . delete ( path )
257+ else
258+ return @files [ path ] if cached? ( path )
277259 end
278260 end
279- @logger . info ( "Opening file" , :path => path )
280261
262+ @logger . info ( "Opening file" , :path => path )
263+
281264 dir = File . dirname ( path )
282265 if !Dir . exist? ( dir )
283266 @logger . info ( "Creating directory" , :directory => dir )
@@ -287,6 +270,7 @@ def open(path)
287270 FileUtils . mkdir_p ( dir )
288271 end
289272 end
273+
290274 # work around a bug opening fifos (bug JRUBY-6280)
291275 stat = File . stat ( path ) rescue nil
292276 if stat && stat . ftype == "fifo" && LogStash ::Environment . jruby?
@@ -301,21 +285,18 @@ def open(path)
301285 if gzip
302286 fd = Zlib ::GzipWriter . new ( fd )
303287 end
304- with_lock ( @files_write_lock ) { @ files[ path ] = IOWriter . new ( fd ) }
288+ @ files[ path ] = IOWriter . new ( fd )
305289 end
306290end # class LogStash::Outputs::File
307291
308292# wrapper class
309293class IOWriter
310294 def initialize ( io )
311295 @io = io
312- @write_mutex = Mutex . new
313296 end
314297 def write ( string )
315- @write_mutex . synchronize do
316- @io . write ( string )
317- @active = true
318- end
298+ @io . write ( string )
299+ @active = true
319300 end
320301 def flush
321302 @io . flush
@@ -325,6 +306,7 @@ def flush
325306 end
326307 def method_missing ( method_name , *args , &block )
327308 if @io . respond_to? ( method_name )
309+
328310 @io . send ( method_name , *args , &block )
329311 else
330312 super
0 commit comments