From 79d4a02e343e9fdf92535e2689f10d4a311cc88d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 4 May 2009 02:01:32 -0700 Subject: Preserve 1.9 IO encodings in reopen_logs Ensure we preserve both internal and external encodings when reopening logs. --- Manifest | 1 + lib/unicorn/util.rb | 15 ++++++--- test/unit/test_util.rb | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 test/unit/test_util.rb diff --git a/Manifest b/Manifest index cfc2ddb..89db23c 100644 --- a/Manifest +++ b/Manifest @@ -129,3 +129,4 @@ test/unit/test_server.rb test/unit/test_signals.rb test/unit/test_socket_helper.rb test/unit/test_upload.rb +test/unit/test_util.rb diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb index 0400fd0..2d3f827 100644 --- a/lib/unicorn/util.rb +++ b/lib/unicorn/util.rb @@ -4,6 +4,8 @@ module Unicorn class Util class << self + APPEND_FLAGS = File::WRONLY | File::APPEND + # this reopens logs that have been rotated (using logrotate(8) or # similar). It is recommended that you install # A +File+ object is considered for reopening if it is: @@ -17,17 +19,20 @@ module Unicorn ObjectSpace.each_object(File) do |fp| next if fp.closed? next unless (fp.sync && fp.path[0..0] == "/") - - flags = fp.fcntl(Fcntl::F_GETFL) - open_flags = File::WRONLY | File::APPEND - next unless (flags & open_flags) == open_flags + next unless (fp.fcntl(Fcntl::F_GETFL) & APPEND_FLAGS) == APPEND_FLAGS begin a, b = fp.stat, File.stat(fp.path) next if a.ino == b.ino && a.dev == b.dev rescue Errno::ENOENT end - fp.reopen(fp.path, "a") + + open_arg = 'a' + if fp.respond_to?(:external_encoding) && enc = fp.external_encoding + open_arg << ":#{enc.to_s}" + enc = fp.internal_encoding and open_arg << ":#{enc.to_s}" + end + fp.reopen(fp.path, open_arg) fp.sync = true nr += 1 end # each_object diff --git a/test/unit/test_util.rb b/test/unit/test_util.rb new file mode 100644 index 0000000..1616eac --- /dev/null +++ b/test/unit/test_util.rb @@ -0,0 +1,87 @@ +require 'test/test_helper' +require 'tempfile' + +class TestUtil < Test::Unit::TestCase + + EXPECT_FLAGS = File::WRONLY | File::APPEND + def test_reopen_logs_noop + tmp = Tempfile.new(nil) + tmp.reopen(tmp.path, 'a') + tmp.sync = true + ext = tmp.external_encoding rescue nil + int = tmp.internal_encoding rescue nil + before = tmp.stat.inspect + Unicorn::Util.reopen_logs + assert_equal before, File.stat(tmp.path).inspect + assert_equal ext, (tmp.external_encoding rescue nil) + assert_equal int, (tmp.internal_encoding rescue nil) + end + + def test_reopen_logs_renamed + tmp = Tempfile.new(nil) + tmp_path = tmp.path.freeze + tmp.reopen(tmp_path, 'a') + tmp.sync = true + ext = tmp.external_encoding rescue nil + int = tmp.internal_encoding rescue nil + before = tmp.stat.inspect + to = Tempfile.new(nil) + File.rename(tmp_path, to.path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert before != File.stat(tmp_path).inspect + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal ext, (tmp.external_encoding rescue nil) + assert_equal int, (tmp.internal_encoding rescue nil) + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + end + + def test_reopen_logs_renamed_with_encoding + tmp = Tempfile.new(nil) + tmp_path = tmp.path.dup.freeze + Encoding.list.each { |encoding| + tmp.reopen(tmp_path, "a:#{encoding.to_s}") + tmp.sync = true + assert_equal encoding, tmp.external_encoding + assert_nil tmp.internal_encoding + File.unlink(tmp_path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal encoding, tmp.external_encoding + assert_nil tmp.internal_encoding + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + } + end if STDIN.respond_to?(:external_encoding) + + def test_reopen_logs_renamed_with_internal_encoding + tmp = Tempfile.new(nil) + tmp_path = tmp.path.dup.freeze + Encoding.list.each { |ext| + Encoding.list.each { |int| + next if ext == int + tmp.reopen(tmp_path, "a:#{ext.to_s}:#{int.to_s}") + tmp.sync = true + assert_equal ext, tmp.external_encoding + assert_equal int, tmp.internal_encoding + File.unlink(tmp_path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal ext, tmp.external_encoding + assert_equal int, tmp.internal_encoding + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + } + } + end if STDIN.respond_to?(:external_encoding) + +end -- cgit v1.2.3-24-ge0c7