From 98e2aceaaa77fa31c56c646ddea99cc644792972 Mon Sep 17 00:00:00 2001 From: Case Taintor Date: Fri, 7 Feb 2014 16:27:35 -0500 Subject: [PATCH] USR2 will now reopen *all* log files (like Unicorn). Also, the logfile will be reopened using IO#reopen rather than creating a new Logger object, reducing the possibility of having a stale logger object --- lib/sidekiq/cli.rb | 2 +- lib/sidekiq/logging.rb | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/sidekiq/cli.rb b/lib/sidekiq/cli.rb index 1a0fcc91..a5761060 100644 --- a/lib/sidekiq/cli.rb +++ b/lib/sidekiq/cli.rb @@ -108,7 +108,7 @@ module Sidekiq when 'USR2' if Sidekiq.options[:logfile] Sidekiq.logger.info "Received USR2, reopening log file" - initialize_logger + Sidekiq::Logging.reopen_logs end when 'TTIN' Thread.list.each do |thread| diff --git a/lib/sidekiq/logging.rb b/lib/sidekiq/logging.rb index 03739974..34c14cb9 100644 --- a/lib/sidekiq/logging.rb +++ b/lib/sidekiq/logging.rb @@ -42,6 +42,54 @@ module Sidekiq @logger = (log ? log : Logger.new('/dev/null')) end + # This reopens ALL logfiles in the process that have been rotated + # using logrotate(8) (without copytruncate) or similar tools. + # A +File+ object is considered for reopening if it is: + # 1) opened with the O_APPEND and O_WRONLY flags + # 2) the current open file handle does not match its original open path + # 3) unbuffered (as far as userspace buffering goes, not O_SYNC) + # Returns the number of files reopened + def self.reopen_logs + to_reopen = [] + nr = 0 + ObjectSpace.each_object(File) { |fp| is_log?(fp) and to_reopen << fp } + + to_reopen.each do |fp| + orig_st = begin + fp.stat + rescue IOError, Errno::EBADF + next + end + + begin + b = File.stat(fp.path) + next if orig_st.ino == b.ino && orig_st.dev == b.dev + rescue Errno::ENOENT + end + + begin + File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) } + fp.sync = true + + nr += 1 + rescue IOError, Errno::EBADF + # not much we can do... + end + end + nr + end + + def self.is_log?(fp) + append_flags = File::WRONLY | File::APPEND + + ! fp.closed? && + fp.stat.file? && + fp.sync && + (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags + rescue IOError, Errno::EBADF + false + end + def logger Sidekiq::Logging.logger end