aboutsummaryrefslogtreecommitdiffstats
path: root/lib/logger.rb
diff options
context:
space:
mode:
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}")