Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Fix a bug that the wrong log file is reopened with log rotate setting when flushing or graceful reloading #4054

Merged
merged 9 commits into from
Feb 16, 2023
10 changes: 3 additions & 7 deletions lib/fluent/supervisor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,8 @@ def init(process_type, worker_id)
if @log_rotate_age || @log_rotate_size
# We need to prepare a unique path for each worker since
# Windows locks files.
if Fluent.windows?
path = LoggerInitializer.per_process_path(@path, process_type, worker_id)
else
path = @path
end
@logdev = Fluent::LogDeviceIO.new(path, shift_age: @log_rotate_age, shift_size: @log_rotate_size)
@path = LoggerInitializer.per_process_path(@path, process_type, worker_id) if Fluent.windows?
ashie marked this conversation as resolved.
Show resolved Hide resolved
@logdev = Fluent::LogDeviceIO.new(@path, shift_age: @log_rotate_age, shift_size: @log_rotate_size)
else
@logdev = File.open(@path, "a")
end
Expand All @@ -591,7 +587,7 @@ def init(process_type, worker_id)
$log = Fluent::Log.new(logger, @opts)
$log.enable_color(false) if @path
$log.enable_debug if @level <= Fluent::Log::LEVEL_DEBUG
$log.info "init #{process_type} logger", path: path, rotate_age: @log_rotate_age, rotate_size: @log_rotate_size
$log.info "init #{process_type} logger", path: @path, rotate_age: @log_rotate_age, rotate_size: @log_rotate_size
ashie marked this conversation as resolved.
Show resolved Hide resolved
end

def stdout?
Expand Down
114 changes: 94 additions & 20 deletions test/test_logger_initializer.rb
Original file line number Diff line number Diff line change
@@ -1,46 +1,120 @@
require_relative 'helper'
require 'fluent/supervisor'
require 'fileutils'
require 'pathname'

class LoggerInitializerTest < ::Test::Unit::TestCase
TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/tmp/logger_initializer#{ENV['TEST_ENV_NUMBER']}")

teardown do
begin
FileUtils.rm_rf(TMP_DIR)
rescue => _
def setup
@stored_global_logger = $log
Dir.mktmpdir do |tmp_dir|
begin
@tmp_dir = Pathname(tmp_dir)
yield
ensure
$log = @stored_global_logger
daipom marked this conversation as resolved.
Show resolved Hide resolved
end
end
end

test 'when path is given' do
path = File.join(TMP_DIR, 'fluent_with_path.log')

assert_false File.exist?(TMP_DIR)
logger = Fluent::Supervisor::LoggerInitializer.new(path, Fluent::Log::LEVEL_DEBUG, nil, nil, {})
mock.proxy(File).chmod(0o777, TMP_DIR).never
path = @tmp_dir + 'log' + 'fluent_with_path.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {})
mock.proxy(File).chmod(0o777, path.parent.to_s).never

assert_nothing_raised do
logger.init(:supervisor, 0)
end
$log.out.close

assert_true File.exist?(TMP_DIR)
assert { path.parent.exist? }
end

test 'apply_options with log_dir_perm' do
omit "NTFS doesn't support UNIX like permissions" if Fluent.windows?

path = File.join(TMP_DIR, 'fluent_with_path.log')

assert_false File.exist?(TMP_DIR)
logger = Fluent::Supervisor::LoggerInitializer.new(path, Fluent::Log::LEVEL_DEBUG, nil, nil, {})
mock.proxy(File).chmod(0o777, TMP_DIR).once
path = @tmp_dir + 'log' + 'fluent_with_path.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {})
mock.proxy(File).chmod(0o777, path.parent.to_s).once

assert_nothing_raised do
logger.init(:supervisor, 0)
end

logger.apply_options(log_dir_perm: 0o777)
assert_true File.exist?(TMP_DIR)
assert_equal 0o777, (File.stat(TMP_DIR).mode & 0xFFF)
$log.out.close

assert { path.parent.exist? }
assert_equal 0o777, (File.stat(path.parent).mode & 0xFFF)
end

test 'rotate' do
path = @tmp_dir + 'log' + 'fluent.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5, log_rotate_size: 500)
logger.init(:supervisor, 0)
begin
10.times.each do
$log.info "This is test message. This is test message. This is test message."
end
ensure
$log.out.close
end

assert { path.parent.entries.size > 3 } # [".", "..", "logfile.log", ...]
end

test 'rotate to max age' do
path = @tmp_dir + 'log' + 'fluent.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5, log_rotate_size: 500)
logger.init(:supervisor, 0)
begin
100.times.each do
$log.info "This is test message. This is test message. This is test message."
end
ensure
$log.out.close
end

assert { path.parent.entries.size == 7 } # [".", "..", "logfile.log", ...]
end

test 'files for each process with rotate on Windows' do
omit "Only for Windows." unless Fluent.windows?

path = @tmp_dir + 'log' + 'fluent.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5)
logger.init(:supervisor, 0)
$log.out.close

logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5)
logger.init(:worker0, 0)
$log.out.close

logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5)
logger.init(:workers, 1)
$log.out.close

assert { path.parent.entries.size == 5 } # [".", "..", "logfile.log", ...]
end

test 'reopen!' do
path = @tmp_dir + 'log' + 'fluent.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {})
logger.init(:supervisor, 0)
message = "This is test message."
$log.info message
logger.reopen!
$log.info message
$log.out.close

assert { path.read.lines.select{ |line| line.include?(message) }.size == 2 }
end

test 'reopen! with rotate reopens the same file' do
path = @tmp_dir + 'log' + 'fluent.log'
logger = Fluent::Supervisor::LoggerInitializer.new(path.to_s, Fluent::Log::LEVEL_DEBUG, nil, nil, {}, log_rotate_age: 5)
logger.init(:supervisor, 0)
logger.reopen!
$log.out.close

assert { path.parent.entries.size == 3 } # [".", "..", "logfile.log", ...]
end
end