summaryrefslogtreecommitdiff
path: root/lib/logger.rb
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-01 22:14:42 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-01 22:14:42 +0000
commit0749adc54ceffce15ad40947bd05be19fc9f1618 (patch)
tree368a686210860ed663fdacb0eca8d6201ec1318f /lib/logger.rb
parent052ef632a59e4aff785bcc7573c8cc83c7711f2c (diff)
* 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.rb57
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}")