class Logger::LogDevice

Device used for logging messages.

Attributes

dev[R]
filename[R]

Public Class Methods

new(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil) click to toggle source
# File lib/logger.rb, line 668
def initialize(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil)
  @dev = @filename = @shift_age = @shift_size = @shift_period_suffix = nil
  mon_initialize
  set_dev(log)
  if @filename
    @shift_age = shift_age || 7
    @shift_size = shift_size || 1048576
    @shift_period_suffix = shift_period_suffix || '%Y%m%d'

    unless @shift_age.is_a?(Integer)
      base_time = @dev.respond_to?(:stat) ? @dev.stat.mtime : Time.now
      @next_rotate_time = next_rotate_time(base_time, @shift_age)
    end
  end
end

Public Instance Methods

close() click to toggle source
# File lib/logger.rb, line 705
def close
  begin
    synchronize do
      @dev.close rescue nil
    end
  rescue Exception
    @dev.close rescue nil
  end
end
reopen(log = nil) click to toggle source
# File lib/logger.rb, line 715
def reopen(log = nil)
  # reopen the same filename if no argument, do nothing for IO
  log ||= @filename if @filename
  if log
    synchronize do
      if @filename and @dev
        @dev.close rescue nil # close only file opened by Logger
        @filename = nil
      end
      set_dev(log)
    end
  end
  self
end
write(message) click to toggle source
# File lib/logger.rb, line 684
def write(message)
  begin
    synchronize do
      if @shift_age and @dev.respond_to?(:stat)
        begin
          check_shift_log
        rescue
          warn("log shifting failed. #{$!}")
        end
      end
      begin
        @dev.write(message)
      rescue
        warn("log writing failed. #{$!}")
      end
    end
  rescue Exception => ignored
    warn("log writing failed. #{ignored}")
  end
end

Private Instance Methods

add_log_header(file) click to toggle source
# File lib/logger.rb, line 765
def add_log_header(file)
  file.write(
    "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
  ) if file.size == 0
end
check_shift_log() click to toggle source
# File lib/logger.rb, line 771
def check_shift_log
  if @shift_age.is_a?(Integer)
    # Note: always returns false if '0'.
    if @filename && (@shift_age > 0) && (@dev.stat.size > @shift_size)
      lock_shift_log { shift_log_age }
    end
  else
    now = Time.now
    if now >= @next_rotate_time
      @next_rotate_time = next_rotate_time(now, @shift_age)
      lock_shift_log { shift_log_period(previous_period_end(now, @shift_age)) }
    end
  end
end
create_logfile(filename) click to toggle source
# File lib/logger.rb, line 750
def create_logfile(filename)
  begin
    logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
    logdev.flock(File::LOCK_EX)
    logdev.sync = true
    add_log_header(logdev)
    logdev.flock(File::LOCK_UN)
  rescue Errno::EEXIST
    # file is created by another process
    logdev = open_logfile(filename)
    logdev.sync = true
  end
  logdev
end
lock_shift_log() { || ... } click to toggle source
# File lib/logger.rb, line 787
def lock_shift_log
  yield
end
open_logfile(filename) click to toggle source
# File lib/logger.rb, line 742
def open_logfile(filename)
  begin
    open(filename, (File::WRONLY | File::APPEND))
  rescue Errno::ENOENT
    create_logfile(filename)
  end
end
set_dev(log) click to toggle source
# File lib/logger.rb, line 732
def set_dev(log)
  if log.respond_to?(:write) and log.respond_to?(:close)
    @dev = log
  else
    @dev = open_logfile(log)
    @dev.sync = true
    @filename = log
  end
end
shift_log_age() click to toggle source
# File lib/logger.rb, line 822
def shift_log_age
  (@shift_age-3).downto(0) do |i|
    if FileTest.exist?("#{@filename}.#{i}")
      File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}")
    end
  end
  @dev.close rescue nil
  File.rename("#{@filename}", "#{@filename}.0")
  @dev = create_logfile(@filename)
  return true
end
shift_log_period(period_end) click to toggle source
# File lib/logger.rb, line 834
  def shift_log_period(period_end)
    suffix = period_end.strftime(@shift_period_suffix)
    age_file = "#{@filename}.#{suffix}"
    if FileTest.exist?(age_file)
      # try to avoid filename crash caused by Timestamp change.
      idx = 0
      # .99 can be overridden; avoid too much file search with 'loop do'
      while idx < 100
        idx += 1
        age_file = "#{@filename}.#{suffix}.#{idx}"
        break unless FileTest.exist?(age_file)
      end
    end
    @dev.close rescue nil
    File.rename("#{@filename}", age_file)
    @dev = create_logfile(@filename)
    return true
  end
end