class Sawmill::Rotater::ShiftingLogFile

A rotation strategy that “shifts” log files by appending index numbers to the filename when the file reaches a certain size or age. So when the file “foo.log” is ready to rotate, it is renamed “foo.log.0”, and a new “foo.log” is started. When that one is ready to rotate, the oldest “foo.log.0” is shifted down to “foo.log.1”, “foo.log” is renamed to “foo.log.0”, and a new “foo.log” is started. So the oldest logfile is always the one with the largest number suffix, and the file currently being written to has no suffix. This is a common rotation strategy for many unix tools.

Public Class Methods

new(options_) click to toggle source

Create a new shifting log file rotation strategy.

Recognized options include:

:basedir

The base directory used if the filepath is a relative path. If not specified, the current working directory is used.

:file_path

The path to the log file. This may be an absolute path or a path relative to basedir. If not specified, defaults to “sawmill.log”.

:max_file_size

A logfile will try to rotate once it has reached this size in bytes. If not specified, the file size is not checked.

:shift_period

A logfile will try to rotate once it has been in service for this many seconds. This parameter also recognizes the values :yearly, :monthly, :daily, and :hourly. If not specified, the file’s age is not checked.

:history_size

The maximum number of old logfiles (files with indexes) to keep. Files beyond this history size will be automatically deleted. Default is 1. This value must be at least 1.

# File lib/sawmill/rotater/shifting_log_file.rb, line 80
def initialize(options_)
  @max_logfile_size = options_[:max_file_size] || options_[:max_logfile_size]
  @shift_period = options_[:shift_period]
  case @shift_period
  when :yearly
    @shift_period = 60*60*24*365
  when :monthly
    @shift_period = 60*60*24*30
  when :daily
    @shift_period = 60*60*24
  when :hourly
    @shift_period = 60*60
  end
  @history_size = options_[:history_size].to_i
  @history_size = 1 if @history_size < 1 && (@max_logfile_size || @shift_period)
  @normal_path = ::File.expand_path(options_[:file_path] || options_[:filepath] || 'sawmill.log',
                                    options_[:basedir] || ::Dir.getwd)
  @preferred_handle = 0
  @open_handles = {}
  @last_shift = ::Time.now
end

Public Instance Methods

before_write() click to toggle source

Implements the rotation strategy contract.

# File lib/sawmill/rotater/shifting_log_file.rb, line 139
def before_write
  return unless @max_logfile_size || @shift_period
  turnover_ = false
  if @max_logfile_size && ::File.file?(@normal_path) && ::File.size(@normal_path) > @max_logfile_size
    turnover_ = true
  end
  if @shift_period && (::Time.now - @last_shift) > @shift_period
    turnover_ = true
  end
  if turnover_
    max_ = @preferred_handle - @open_handles.keys.min + 1
    max_ = @history_size if max_ < @history_size
    ::File.delete("#{@normal_path}.#{max_-1}") rescue nil
    (max_-1).downto(1) do |index_|
      ::File.rename("#{@normal_path}.#{index_-1}", "#{@normal_path}.#{index_}") rescue nil
    end
    ::File.rename("#{@normal_path}", "#{@normal_path}.0") rescue nil
    @preferred_handle += 1
    @last_shift = ::Time.now
  end
end
close_handle(handle_, io_) click to toggle source

Implements the rotation strategy contract.

# File lib/sawmill/rotater/shifting_log_file.rb, line 127
def close_handle(handle_, io_)
  io_.close
  if @preferred_handle - handle_ > @history_size
    ::File.delete("#{@normal_path}.#{@preferred_handle-handle_-1}") rescue nil
  end
  @open_handles.delete(handle_)
  nil
end
open_handle(handle_) click to toggle source

Implements the rotation strategy contract.

# File lib/sawmill/rotater/shifting_log_file.rb, line 112
def open_handle(handle_)
  if handle_ == @preferred_handle
    path_ = @normal_path
  else
    path_ = "#{@normal_path}.#{@preferred_handle-handle_-1}"
  end
  file_ = ::File.open(path_, 'a')
  file_.sync = true
  @open_handles[handle_] = true
  file_
end
preferred_handle() click to toggle source

Implements the rotation strategy contract.

# File lib/sawmill/rotater/shifting_log_file.rb, line 105
def preferred_handle
  @preferred_handle
end