Project

General

Profile

Feature #5096 » syslog.logger.patch

rails-free patch - drbrain (Eric Hodel), 05/16/2012 09:59 AM

View differences:

ext/syslog/lib/syslog/logger.rb (revision 0)
require 'syslog'
require 'logger'
##
# Syslog::Logger is a Logger work-alike that logs via syslog instead of to a
# file. You can use Syslog::Logger to aggregate logs between multiple
# machines.
#
# By default, Syslog::Logger uses the program name 'ruby', but this can be
# changed via the first argument to Syslog::Logger.new.
#
# NOTE! You can only set the Syslog::Logger program name when you initialize
# Syslog::Logger for the first time. This is a limitation of the way
# Syslog::Logger uses syslog (and in some ways, a limitation of the way
# syslog(3) works). Attempts to change Syslog::Logger's program name after
# the first initialization will be ignored.
#
# === Example
#
# The following will log to syslogd on your local machine:
#
# require 'syslog/logger'
#
# log = Syslog::Logger.new 'my_program'
# log.info 'this line will be logged via syslog(3)'
#
# You may need to perform some syslog.conf setup first. For a BSD machine add
# the following lines to /etc/syslog.conf:
#
# !my_program
# *.* /var/log/my_program.log
#
# Then touch /var/log/my_program.log and signal syslogd with a HUP
# (killall -HUP syslogd, on FreeBSD).
#
# If you wish to have logs automatically roll over and archive, see the
# newsyslog.conf(5) and newsyslog(8) man pages.
class Syslog::Logger
##
# The version of Syslog::Logger you are using.
VERSION = '2.0'
##
# Maps Logger warning types to syslog(3) warning types.
#
# Messages from ruby applications are not considered as critical as messages
# from other system daemons using syslog(3), so most messages are reduced by
# one level. For example, a fatal message for ruby's Logger is considered
# an error for syslog(3).
LOGGER_MAP = {
:unknown => :alert,
:fatal => :err,
:error => :warning,
:warn => :notice,
:info => :info,
:debug => :debug,
}
##
# Maps Logger log levels to their values so we can silence.
LOGGER_LEVEL_MAP = {}
LOGGER_MAP.each_key do |key|
LOGGER_LEVEL_MAP[key] = ::Logger.const_get key.to_s.upcase
end
##
# Maps Logger log level values to syslog log levels.
LEVEL_LOGGER_MAP = {}
LOGGER_LEVEL_MAP.invert.each do |level, severity|
LEVEL_LOGGER_MAP[level] = LOGGER_MAP[severity]
end
##
# Builds a methods for level +meth+.
def self.make_methods meth
eval <<-EOM, nil, __FILE__, __LINE__ + 1
def #{meth}(message = nil)
return true if #{LOGGER_LEVEL_MAP[meth]} < @level
SYSLOG.#{LOGGER_MAP[meth]} clean(message || yield)
return true
end
def #{meth}?
@level <= ::Logger::#{meth.to_s.upcase}
end
EOM
end
##
# :method: unknown
#
# Logs a +message+ at the unknown (syslog alert) log level, or logs the
# message returned from the block.
##
# :method: fatal
#
# Logs a +message+ at the fatal (syslog err) log level, or logs the message
# returned from the block.
##
# :method: error
#
# Logs a +message+ at the error (syslog warning) log level, or logs the
# message returned from the block.
##
# :method: warn
#
# Logs a +message+ at the warn (syslog notice) log level, or logs the
# message returned from the block.
##
# :method: info
#
# Logs a +message+ at the info (syslog info) log level, or logs the message
# returned from the block.
##
# :method: debug
#
# Logs a +message+ at the debug (syslog debug) log level, or logs the
# message returned from the block.
LOGGER_MAP.each_key do |level|
make_methods level
end
##
# Log level for Logger compatibility.
attr_accessor :level
##
# Fills in variables for Logger compatibility. If this is the first
# instance of Syslog::Logger, +program_name+ may be set to change the logged
# program name.
#
# Due to the way syslog works, only one program name may be chosen.
def initialize program_name = 'ruby'
@level = ::Logger::DEBUG
return if defined? SYSLOG
self.class.const_set :SYSLOG, Syslog.open(program_name)
end
##
# Almost duplicates Logger#add. +progname+ is ignored.
def add severity, message = nil, progname = nil, &block
severity ||= ::Logger::UNKNOWN
return true if severity < @level
SYSLOG.send LEVEL_LOGGER_MAP[severity], clean(message || block.call)
return true
end
private
##
# Clean up messages so they're nice and pretty.
def clean message
message = message.to_s.dup
message.strip!
message.gsub!(/%/, '%%') # syslog(3) fails on % (printf)
message.gsub!(/\e\[[^m]*m/, '') # remove useless ansi color codes
return message
end
end
NEWS (working copy)
* Shellwords#shelljoin() accepts non-string objects in the given
array, each of which is stringified using to_s.
* syslog
* Added Syslog::Logger which provides a Logger API atop Syslog.
* lib/tmpdir.rb
* incompatible changes:
* Dir.mktmpdir uses FileUtils.remove_entry instead of
test/syslog/test_syslog_logger.rb (revision 0)
require 'test/unit'
require 'tempfile'
require 'syslog/logger'
class TestSyslogRootLogger < Test::Unit::TestCase
module MockSyslog; end
class << MockSyslog
@line = nil
Syslog::Logger::LOGGER_MAP.values.uniq.each do |level|
eval <<-EOM
def #{level}(message)
@line = "#{level.to_s.upcase} - \#{message}"
end
EOM
end
attr_reader :line
attr_reader :program_name
def open(program_name)
@program_name = program_name
end
def reset
@line = ''
end
end
Syslog::Logger.const_set :SYSLOG, MockSyslog
LEVEL_LABEL_MAP = {
Logger::DEBUG => 'DEBUG',
Logger::INFO => 'INFO',
Logger::WARN => 'WARN',
Logger::ERROR => 'ERROR',
Logger::FATAL => 'FATAL',
Logger::UNKNOWN => 'ANY',
}
def setup
@logger = Logger.new(nil)
end
class Log
attr_reader :line, :label, :datetime, :pid, :severity, :progname, :msg
def initialize(line)
@line = line
/\A(\w+), \[([^#]*)#(\d+)\]\s+(\w+) -- (\w*): ([\x0-\xff]*)/ =~ @line
@label, @datetime, @pid, @severity, @progname, @msg = $1, $2, $3, $4, $5, $6
end
end
def log_add(severity, msg, progname = nil, &block)
log(:add, severity, msg, progname, &block)
end
def log(msg_id, *arg, &block)
Log.new(log_raw(msg_id, *arg, &block))
end
def log_raw(msg_id, *arg, &block)
logdev = Tempfile.new(File.basename(__FILE__) + '.log')
@logger.instance_eval { @logdev = Logger::LogDevice.new(logdev) }
assert_equal true, @logger.__send__(msg_id, *arg, &block)
logdev.open
msg = logdev.read
logdev.close
msg
end
def test_initialize
assert_equal Logger::DEBUG, @logger.level
end
def test_add
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
msg = log_add Logger::WARN, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
msg = log_add Logger::INFO, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal LEVEL_LABEL_MAP[Logger::DEBUG], msg.severity
end
def test_add_level_unknown
@logger.level = Logger::UNKNOWN
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal '', msg.line
msg = log_add Logger::ERROR, 'error level message'
assert_equal '', msg.line
msg = log_add Logger::WARN, 'warn level message'
assert_equal '', msg.line
msg = log_add Logger::INFO, 'info level message'
assert_equal '', msg.line
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal '', msg.line
end
def test_add_level_fatal
@logger.level = Logger::FATAL
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal '', msg.line
msg = log_add Logger::WARN, 'warn level message'
assert_equal '', msg.line
msg = log_add Logger::INFO, 'info level message'
assert_equal '', msg.line
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal '', msg.line
end
def test_add_level_error
@logger.level = Logger::ERROR
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
msg = log_add Logger::WARN, 'warn level message'
assert_equal '', msg.line
msg = log_add Logger::INFO, 'info level message'
assert_equal '', msg.line
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal '', msg.line
end
def test_add_level_warn
@logger.level = Logger::WARN
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
msg = log_add Logger::WARN, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
msg = log_add Logger::INFO, 'info level message'
assert_equal '', msg.line
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal '', msg.line
end
def test_add_level_info
@logger.level = Logger::INFO
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
msg = log_add Logger::WARN, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
msg = log_add Logger::INFO, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal '', msg.line
end
def test_add_level_debug
@logger.level = Logger::DEBUG
msg = log_add nil, 'unknown level message' # nil == unknown
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
msg = log_add Logger::FATAL, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
msg = log_add Logger::ERROR, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
msg = log_add Logger::WARN, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
msg = log_add Logger::INFO, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
msg = log_add Logger::DEBUG, 'debug level message'
assert_equal LEVEL_LABEL_MAP[Logger::DEBUG], msg.severity
end
def test_unknown
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::FATAL
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::ERROR
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::WARN
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::INFO
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
@logger.level = Logger::DEBUG
msg = log :unknown, 'unknown level message'
assert_equal LEVEL_LABEL_MAP[Logger::UNKNOWN], msg.severity
end
def test_fatal
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :fatal, 'fatal level message'
assert_equal '', msg.line
@logger.level = Logger::FATAL
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
@logger.level = Logger::ERROR
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
@logger.level = Logger::WARN
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
@logger.level = Logger::INFO
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
@logger.level = Logger::DEBUG
msg = log :fatal, 'fatal level message'
assert_equal LEVEL_LABEL_MAP[Logger::FATAL], msg.severity
end
def test_fatal_eh
@logger.level = Logger::FATAL
assert_equal true, @logger.fatal?
@logger.level = Logger::UNKNOWN
assert_equal false, @logger.fatal?
end
def test_error
msg = log :error, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :error, 'error level message'
assert_equal '', msg.line
@logger.level = Logger::FATAL
msg = log :error, 'error level message'
assert_equal '', msg.line
@logger.level = Logger::ERROR
msg = log :error, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
@logger.level = Logger::WARN
msg = log :error, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
@logger.level = Logger::INFO
msg = log :error, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
@logger.level = Logger::DEBUG
msg = log :error, 'error level message'
assert_equal LEVEL_LABEL_MAP[Logger::ERROR], msg.severity
end
def test_error_eh
@logger.level = Logger::ERROR
assert_equal true, @logger.error?
@logger.level = Logger::FATAL
assert_equal false, @logger.error?
end
def test_warn
msg = log :warn, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :warn, 'warn level message'
assert_equal '', msg.line
@logger.level = Logger::FATAL
msg = log :warn, 'warn level message'
assert_equal '', msg.line
@logger.level = Logger::ERROR
msg = log :warn, 'warn level message'
assert_equal '', msg.line
@logger.level = Logger::WARN
msg = log :warn, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
@logger.level = Logger::INFO
msg = log :warn, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
@logger.level = Logger::DEBUG
msg = log :warn, 'warn level message'
assert_equal LEVEL_LABEL_MAP[Logger::WARN], msg.severity
end
def test_warn_eh
@logger.level = Logger::WARN
assert_equal true, @logger.warn?
@logger.level = Logger::ERROR
assert_equal false, @logger.warn?
end
def test_info
msg = log :info, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :info, 'info level message'
assert_equal '', msg.line
@logger.level = Logger::FATAL
msg = log :info, 'info level message'
assert_equal '', msg.line
@logger.level = Logger::ERROR
msg = log :info, 'info level message'
assert_equal '', msg.line
@logger.level = Logger::WARN
msg = log :info, 'info level message'
assert_equal '', msg.line
@logger.level = Logger::INFO
msg = log :info, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
@logger.level = Logger::DEBUG
msg = log :info, 'info level message'
assert_equal LEVEL_LABEL_MAP[Logger::INFO], msg.severity
end
def test_info_eh
@logger.level = Logger::INFO
assert_equal true, @logger.info?
@logger.level = Logger::WARN
assert_equal false, @logger.info?
end
def test_debug
msg = log :debug, 'debug level message'
assert_equal LEVEL_LABEL_MAP[Logger::DEBUG], msg.severity
@logger.level = Logger::UNKNOWN
msg = log :debug, 'debug level message'
assert_equal '', msg.line
@logger.level = Logger::FATAL
msg = log :debug, 'debug level message'
assert_equal '', msg.line
@logger.level = Logger::ERROR
msg = log :debug, 'debug level message'
assert_equal '', msg.line
@logger.level = Logger::WARN
msg = log :debug, 'debug level message'
assert_equal '', msg.line
@logger.level = Logger::INFO
msg = log :debug, 'debug level message'
assert_equal '', msg.line
@logger.level = Logger::DEBUG
msg = log :debug, 'debug level message'
assert_equal LEVEL_LABEL_MAP[Logger::DEBUG], msg.severity
end
def test_debug_eh
@logger.level = Logger::DEBUG
assert_equal true, @logger.debug?
@logger.level = Logger::INFO
assert_equal false, @logger.debug?
end
end
class TestSyslogLogger < TestSyslogRootLogger
def setup
super
@logger = Syslog::Logger.new
end
class Log
attr_reader :line, :label, :datetime, :pid, :severity, :progname, :msg
def initialize(line)
@line = line
return unless /\A(\w+) - (.*)\Z/ =~ @line
severity, @msg = $1, $2
severity = Syslog::Logger::LOGGER_MAP.invert[severity.downcase.intern]
@severity = severity.to_s.upcase
@severity = 'ANY' if @severity == 'UNKNOWN'
end
end
def log_add(severity, msg, progname = nil, &block)
log(:add, severity, msg, progname, &block)
end
def log(msg_id, *arg, &block)
Log.new(log_raw(msg_id, *arg, &block))
end
def log_raw(msg_id, *arg, &block)
assert_equal true, @logger.__send__(msg_id, *arg, &block)
msg = MockSyslog.line
MockSyslog.reset
return msg
end
def test_unknown_eh
@logger.level = Logger::UNKNOWN
assert_equal true, @logger.unknown?
@logger.level = Logger::UNKNOWN + 1
assert_equal false, @logger.unknown?
end
end
(2-2/3)