diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-11-01 22:14:42 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-11-01 22:14:42 +0000 |
commit | 0749adc54ceffce15ad40947bd05be19fc9f1618 (patch) | |
tree | 368a686210860ed663fdacb0eca8d6201ec1318f /lib/logger.rb | |
parent | 052ef632a59e4aff785bcc7573c8cc83c7711f2c (diff) | |
download | ruby-0749adc54ceffce15ad40947bd05be19fc9f1618.tar.gz |
* lib/logger.rb: Inter-process locking for log rotation
Current implementation fails log rotation on multi process env.
by sonots <sonots@gmail.com>
https://github.com/ruby/ruby/pull/428 fix GH-428 [Bug #9046]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43511 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/logger.rb')
-rw-r--r-- | lib/logger.rb | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/lib/logger.rb b/lib/logger.rb index f24b20b1a6..2eb4e642d2 100644 --- a/lib/logger.rb +++ b/lib/logger.rb @@ -588,24 +588,32 @@ private private def open_logfile(filename) - if (FileTest.exist?(filename)) + begin open(filename, (File::WRONLY | File::APPEND)) - else + rescue Errno::ENOENT create_logfile(filename) end end def create_logfile(filename) - logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT)) - logdev.sync = true - add_log_header(logdev) + 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 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 SiD = 24 * 60 * 60 @@ -614,17 +622,50 @@ private if @shift_age.is_a?(Integer) # Note: always returns false if '0'. if @filename && (@shift_age > 0) && (@dev.stat.size > @shift_size) - shift_log_age + lock_shift_log { shift_log_age } end else now = Time.now period_end = previous_period_end(now) if @dev.stat.mtime <= period_end - shift_log_period(period_end) + lock_shift_log { shift_log_period(period_end) } end end end + def lock_shift_log + begin + retry_limit = 8 + retry_sleep = 0.1 + begin + File.open(@filename, File::WRONLY | File::APPEND) do |lock| + lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file + ino = lock.stat.ino + if ino == File.stat(@filename).ino + yield # log shifting + else + # log shifted by another process (i-node before locking and i-node after locking are different) + @dev.close rescue nil + @dev = open_logfile(@filename) + @dev.sync = true + end + end + rescue Errno::ENOENT + # @filename file would not exist right after #rename and before #create_logfile + if retry_limit <= 0 + warn("log rotation inter-process lock failed. #{$!}") + else + sleep retry_sleep + retry_limit -= 1 + retry_sleep *= 2 + retry + end + end + rescue + warn("log rotation inter-process lock failed. #{$!}") + end + end + def shift_log_age (@shift_age-3).downto(0) do |i| if FileTest.exist?("#{@filename}.#{i}") |