Skip to content

Commit

Permalink
Merge pull request sidekiq#1467 from ctaintor/improve_log_reopening
Browse files Browse the repository at this point in the history
USR2 will now reopen *all* log files (like Unicorn)
  • Loading branch information
mperham committed Feb 7, 2014
2 parents 547f07a + c720dad commit df85a0f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
2.17.5
-----------

- A `USR2` signal will now reopen _all_ logs, using IO#reopen. Thus, instead of creating a new Logger object,
Sidekiq will now just update the existing Logger's file descriptor [#1163].
Like Unicorn, a File object is considered a log file if:
- opened with the `O_APPEND` and `O_WRONLY` flags
- the current open file handle does not match its original open path
- unbuffered (as far as userspace buffering goes, not `O_SYNC`)

2.17.4
-----------

Expand Down
2 changes: 1 addition & 1 deletion lib/sidekiq/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def handle_signal(sig)
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|
Expand Down
48 changes: 48 additions & 0 deletions lib/sidekiq/logging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,54 @@ def self.logger=(log)
@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
Expand Down

0 comments on commit df85a0f

Please sign in to comment.