[ruby/logger] Enable log file rotation on Windows
Since ruby 2.3, a file opened with `File::SHARE_DELETE` and `File::BINARY` can be renamed or removed. https://github.com/ruby/logger/commit/7b6146fee6
This commit is contained in:
parent
ed47b6b324
commit
edd3977b40
@ -67,6 +67,12 @@ class Logger
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# :stopdoc:
|
||||||
|
|
||||||
|
MODE = File::WRONLY | File::APPEND
|
||||||
|
MODE_TO_OPEN = MODE | File::SHARE_DELETE | File::BINARY
|
||||||
|
MODE_TO_CREATE = MODE_TO_OPEN | File::CREAT | File::EXCL
|
||||||
|
|
||||||
def set_dev(log)
|
def set_dev(log)
|
||||||
if log.respond_to?(:write) and log.respond_to?(:close)
|
if log.respond_to?(:write) and log.respond_to?(:close)
|
||||||
@dev = log
|
@dev = log
|
||||||
@ -77,34 +83,54 @@ class Logger
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
@dev = open_logfile(log)
|
@dev = open_logfile(log)
|
||||||
@dev.sync = true
|
|
||||||
@dev.binmode if @binmode
|
|
||||||
@filename = log
|
@filename = log
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if MODE_TO_OPEN == MODE
|
||||||
|
def fixup_mode(dev, filename)
|
||||||
|
dev
|
||||||
|
end
|
||||||
|
else
|
||||||
|
def fixup_mode(dev, filename)
|
||||||
|
return dev if @binmode
|
||||||
|
dev.autoclose = false
|
||||||
|
old_dev = dev
|
||||||
|
dev = File.new(dev.fileno, mode: MODE, path: filename)
|
||||||
|
old_dev.close
|
||||||
|
PathAttr.set_path(dev, filename) if defined?(PathAttr)
|
||||||
|
dev
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def open_logfile(filename)
|
def open_logfile(filename)
|
||||||
begin
|
begin
|
||||||
File.open(filename, (File::WRONLY | File::APPEND))
|
dev = File.open(filename, MODE_TO_OPEN)
|
||||||
rescue Errno::ENOENT
|
rescue Errno::ENOENT
|
||||||
create_logfile(filename)
|
create_logfile(filename)
|
||||||
|
else
|
||||||
|
dev = fixup_mode(dev, filename)
|
||||||
|
dev.sync = true
|
||||||
|
dev.binmode if @binmode
|
||||||
|
dev
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_logfile(filename)
|
def create_logfile(filename)
|
||||||
begin
|
begin
|
||||||
logdev = File.open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
|
logdev = File.open(filename, MODE_TO_CREATE)
|
||||||
logdev.flock(File::LOCK_EX)
|
logdev.flock(File::LOCK_EX)
|
||||||
|
logdev = fixup_mode(logdev, filename)
|
||||||
logdev.sync = true
|
logdev.sync = true
|
||||||
logdev.binmode if @binmode
|
logdev.binmode if @binmode
|
||||||
add_log_header(logdev)
|
add_log_header(logdev)
|
||||||
logdev.flock(File::LOCK_UN)
|
logdev.flock(File::LOCK_UN)
|
||||||
|
logdev
|
||||||
rescue Errno::EEXIST
|
rescue Errno::EEXIST
|
||||||
# file is created by another process
|
# file is created by another process
|
||||||
logdev = open_logfile(filename)
|
open_logfile(filename)
|
||||||
logdev.sync = true
|
|
||||||
end
|
end
|
||||||
logdev
|
end
|
||||||
|
|
||||||
def handle_write_errors(mesg)
|
def handle_write_errors(mesg)
|
||||||
yield
|
yield
|
||||||
@ -135,40 +161,33 @@ class Logger
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
|
def lock_shift_log
|
||||||
def lock_shift_log
|
retry_limit = 8
|
||||||
yield
|
retry_sleep = 0.1
|
||||||
end
|
begin
|
||||||
else
|
File.open(@filename, MODE_TO_OPEN) do |lock|
|
||||||
def lock_shift_log
|
lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file
|
||||||
retry_limit = 8
|
if File.identical?(@filename, lock) and File.identical?(lock, @dev)
|
||||||
retry_sleep = 0.1
|
yield # log shifting
|
||||||
begin
|
|
||||||
File.open(@filename, File::WRONLY | File::APPEND) do |lock|
|
|
||||||
lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file
|
|
||||||
if File.identical?(@filename, lock) and File.identical?(lock, @dev)
|
|
||||||
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
|
else
|
||||||
sleep retry_sleep
|
# log shifted by another process (i-node before locking and i-node after locking are different)
|
||||||
retry_limit -= 1
|
@dev.close rescue nil
|
||||||
retry_sleep *= 2
|
@dev = open_logfile(@filename)
|
||||||
retry
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue
|
rescue Errno::ENOENT
|
||||||
warn("log rotation inter-process lock failed. #{$!}")
|
# @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
|
end
|
||||||
|
rescue
|
||||||
|
warn("log rotation inter-process lock failed. #{$!}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def shift_log_age
|
def shift_log_age
|
||||||
@ -203,3 +222,15 @@ class Logger
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
File.open(IO::NULL) do |f|
|
||||||
|
File.new(f.fileno, autoclose: false, path: "").path
|
||||||
|
rescue IOError
|
||||||
|
module PathAttr # :nodoc:
|
||||||
|
attr_reader :path
|
||||||
|
|
||||||
|
def self.set_path(file, path)
|
||||||
|
file.extend(self).instance_variable_set(:@path, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -452,7 +452,7 @@ class TestLogDevice < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
logdev0.close
|
logdev0.close
|
||||||
end unless /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
|
end
|
||||||
|
|
||||||
def test_shifting_midnight
|
def test_shifting_midnight
|
||||||
Dir.mktmpdir do |tmpdir|
|
Dir.mktmpdir do |tmpdir|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user