Class: Sawmill::Rotater::ShiftingLogFile

Inherits:
Object
  • Object
show all
Defined in:
lib/sawmill/rotater/shifting_log_file.rb

Overview

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.

Instance Method Summary collapse

Constructor Details

#initialize(options_) ⇒ ShiftingLogFile

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.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 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

Instance Method Details

#before_writeObject

Implements the rotation strategy contract.



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# 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_) ⇒ Object

Implements the rotation strategy contract.



127
128
129
130
131
132
133
134
# 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_) ⇒ Object

Implements the rotation strategy contract.



112
113
114
115
116
117
118
119
120
121
122
# 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_handleObject

Implements the rotation strategy contract.



105
106
107
# File 'lib/sawmill/rotater/shifting_log_file.rb', line 105

def preferred_handle
  @preferred_handle
end