# :nodoc: # Version:: $Id: rollingfileoutputter.rb,v 1.4 2003/09/12 23:55:43 fando Exp $ require "log4r/outputter/fileoutputter" require "log4r/staticlogger" module Log4r # RollingFileOutputter - subclass of FileOutputter that rolls files on size # or time. Additional hash arguments are: # # [:maxsize] Maximum size of the file in bytes. # [:trunc] Maximum age of the file in seconds. class RollingFileOutputter < FileOutputter attr_reader :count, :maxsize, :maxtime, :startTime, :maxBackupIndex #,i:baseFilename def initialize(_name, hash={}) @count = 0 @max_backup_index = 10 super(_name, hash) set_maxsize(hash) if hash.has_key?(:maxtime) || hash.has_key?('maxtime') _maxtime = (hash[:maxtime] or hash['maxtime']).to_i if _maxtime.class != Fixnum raise TypeError, "Argument 'maxtime' must be an Fixnum", caller end if _maxtime == 0 raise TypeError, "Argument 'maxtime' must be > 0", caller end @maxtime = _maxtime @startTime = Time.now end if hash.has_key?(:maxBackupIndex) || hash.has_key?('maxBackupIndex') _max_backup_index = (hash[:maxBackupIndex] or hash['maxBackupIndex']).to_i if _max_backup_index.class != Fixnum raise TypeError, "Argument 'maxsize' must be an Fixnum", caller end if _max_backup_index == 0 raise TypeError, "Argument 'maxsize' must be > 0", caller end @max_backup_index = _max_backup_index end @baseFilename = File.basename(@filename) # roll immediately so all files are of the form "000001-@baseFilename" roll if file_size_requires_roll? # initialize the file size counter @datasize = 0 end ####### private ####### def set_maxsize(options) if options.has_key?(:maxsize) || options.has_key?('maxsize') maxsize = (options[:maxsize] or options['maxsize']) multiplier = 1 if (maxsize =~ /\d+KB/) multiplier = 1024 elsif (maxsize =~ /\d+MB/) multiplier = 1024 * 1024 elsif (maxsize =~ /\d+GB/) multiplier = 1024 * 1024 * 1024 end _maxsize = maxsize.to_i * multiplier if _maxsize.class != Fixnum and _maxsize.class != Bignum raise TypeError, "Argument 'maxsize' must be an Fixnum", caller end if _maxsize == 0 raise TypeError, "Argument 'maxsize' must be > 0", caller end @maxsize = _maxsize end end # perform the write def write(data) # we have to keep track of the file size ourselves - File.size doesn't # seem to report the correct size when the size changes rapidly @datasize += data.size + 1 # the 1 is for newline super roll if requiresRoll end # construct a new filename from the count and baseFilname def makeNewFilename # note use of hard coded 6 digit counter width - is this enough files? pad = "0" * (6 - @count.to_s.length) + count.to_s newbase = @baseFilename.sub(/(\.\w*)$/, pad + '\1') @filename = File.join(File.dirname(@filename), newbase) Logger.log_internal {"File #{@filename} created"} end # does the file require a roll? def requiresRoll if !@maxsize.nil? && @datasize > @maxsize @datasize = 0 return true end if !@maxtime.nil? && (Time.now - @startTime) > @maxtime @startTime = Time.now return true end false end def indexed_filename(index) @filename + ".#{index}" end # more expensive, only for startup def file_size_requires_roll? (@maxsize.to_i > 0 and (File.size?(@filename).to_i >= @maxsize.to_i)) end # roll the file def roll begin @out.close rescue Logger.log_internal { "RollingFileOutputter '#{@name}' could not close #{@filename}" } end @count += 1 @max_backup_index.times do |x| index = @max_backup_index - x - 1 if File.exists?(indexed_filename(index)) and index != 0 FileUtils.mv(indexed_filename(index), indexed_filename(index + 1)) elsif index == 0 and File.exists?(@filename) FileUtils.mv(@filename, indexed_filename(index + 1)) end end @out = File.new(@filename, (@trunc ? "w" : "a")) end end end # this can be found in examples/fileroll.rb as well if __FILE__ == $0 require 'log4r' include Log4r timeLog = Logger.new 'WbExplorer' timeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestTime.log", "maxtime" => 10, "trunc" => true }) timeLog.level = DEBUG 100.times { |t| timeLog.info "blah #{t}" sleep(1.0) } sizeLog = Logger.new 'WbExplorer' sizeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestSize.log", "maxsize" => 16000, "trunc" => true }) sizeLog.level = DEBUG 10000.times { |t| sizeLog.info "blah #{t}" } end