diff options
author | danielsdeleo <dan@opscode.com> | 2013-02-24 20:43:55 -0800 |
---|---|---|
committer | danielsdeleo <dan@opscode.com> | 2013-02-27 11:12:15 -0800 |
commit | 634ad58ab14d6cfa05f56991bbc758cc3b22d410 (patch) | |
tree | fbcf778a5c03f7a27400352c0b3a7098c9471aef /lib/chef/monologger.rb | |
parent | b217dc3f2a80866d484a6cad33190dd321b3e2b7 (diff) | |
download | chef-634ad58ab14d6cfa05f56991bbc758cc3b22d410.tar.gz |
[CHEF-3935] Use stripped down lockless logger
Ruby's stdlib Logger wraps all IO in mutexes. Ruby 2.0 doesn't allow you
to request a lock in a trap handler because that could deadlock. This
commit fixes by replacing the Logger with a lock-free variant.
Diffstat (limited to 'lib/chef/monologger.rb')
-rw-r--r-- | lib/chef/monologger.rb | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/chef/monologger.rb b/lib/chef/monologger.rb new file mode 100644 index 0000000000..fed60514d7 --- /dev/null +++ b/lib/chef/monologger.rb @@ -0,0 +1,93 @@ +require 'logger' + +require 'pp' + +#== MonoLogger +# A subclass of Ruby's stdlib Logger with all the mutex and logrotation stuff +# ripped out. +class MonoLogger < Logger + + # + # === Synopsis + # + # Logger.new(name, shift_age = 7, shift_size = 1048576) + # Logger.new(name, shift_age = 'weekly') + # + # === Args + # + # +logdev+:: + # The log device. This is a filename (String) or IO object (typically + # +STDOUT+, +STDERR+, or an open file). + # +shift_age+:: + # Number of old log files to keep, *or* frequency of rotation (+daily+, + # +weekly+ or +monthly+). + # +shift_size+:: + # Maximum logfile size (only applies when +shift_age+ is a number). + # + # === Description + # + # Create an instance. + # + def initialize(logdev) + @progname = nil + @level = DEBUG + @default_formatter = Formatter.new + @formatter = nil + @logdev = nil + if logdev + @logdev = LocklessLogDevice.new(logdev) + end + end + + + class LocklessLogDevice < LogDevice + + def initialize(log = nil) + @dev = @filename = @shift_age = @shift_size = nil + if log.respond_to?(:write) and log.respond_to?(:close) + @dev = log + else + @dev = open_logfile(log) + @dev.sync = true + @filename = log + end + end + + def write(message) + @dev.write(message) + rescue Exception => ignored + warn("log writing failed. #{ignored}") + end + + def close + @dev.close rescue nil + end + + private + + def open_logfile(filename) + if (FileTest.exist?(filename)) + open(filename, (File::WRONLY | File::APPEND)) + else + 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) + logdev + end + + def add_log_header(file) + file.write( + "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName] + ) + end + + end + + +end + |