summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel DeLeo <dan@opscode.com>2011-03-15 19:10:16 -0700
committerDaniel DeLeo <dan@opscode.com>2011-03-15 19:10:16 -0700
commit9939a40e1cbbf509244a62c05b9089f69af1b2bb (patch)
tree68c635039edabff0b2627fb07dd2b878e89178d1
parent0dee0929cf660f02e474ee488e54a37b15b8c79d (diff)
downloadmixlib-log-9939a40e1cbbf509244a62c05b9089f69af1b2bb.tar.gz
add multiple logger support
-rw-r--r--VERSION.yml2
-rw-r--r--lib/mixlib/log.rb91
-rw-r--r--spec/mixlib/log_spec.rb20
3 files changed, 83 insertions, 30 deletions
diff --git a/VERSION.yml b/VERSION.yml
index 623d3e9..082b8f7 100644
--- a/VERSION.yml
+++ b/VERSION.yml
@@ -1,5 +1,5 @@
---
:major: 1
-:minor: 2
+:minor: 3
:patch: 0
:build:
diff --git a/lib/mixlib/log.rb b/lib/mixlib/log.rb
index 025018d..1ada401 100644
--- a/lib/mixlib/log.rb
+++ b/lib/mixlib/log.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,10 +21,23 @@ require 'mixlib/log/formatter'
module Mixlib
module Log
-
+
@logger = nil
- @@levels = { :debug=>Logger::DEBUG, :info=>Logger::INFO, :warn=>Logger::WARN, :error=>Logger::ERROR, :fatal=>Logger::FATAL}
-
+
+ LEVELS = { :debug=>Logger::DEBUG, :info=>Logger::INFO, :warn=>Logger::WARN, :error=>Logger::ERROR, :fatal=>Logger::FATAL}.freeze
+ LEVEL_NAMES = LEVELS.invert.freeze
+
+
+ def reset!
+ @logger, @loggers = nil, nil
+ end
+
+ # An Array of log devices that will be logged to. Defaults to just the default
+ # @logger log device, but you can push to this array to add more devices.
+ def loggers
+ @loggers ||= [logger]
+ end
+
##
# init always returns a configured logger
# and creates a new one if it doesn't yet exist
@@ -36,7 +49,15 @@ module Mixlib
def logger=(value)
@logger=value
end
-
+
+ def use_log_devices(other)
+ if other.respond_to?(:loggers)
+ @loggers = other.loggers
+ else
+ @loggers = other
+ end
+ end
+
# Use Mixlib::Log.init when you want to set up the logger manually. Arguments to this method
# get passed directly to Logger.new, so check out the documentation for the standard Logger class
# to understand what to do here.
@@ -45,12 +66,13 @@ module Mixlib
#
# It also configures the Logger instance it creates to use the custom Mixlib::Log::Formatter class.
def init(*opts)
+ @loggers = nil
@logger = (opts.empty? ? Logger.new(STDOUT) : Logger.new(*opts))
@logger.formatter = Mixlib::Log::Formatter.new()
@logger.level = Logger::WARN
@logger
end
-
+
# Sets the level for the Logger object by symbol. Valid arguments are:
#
# :debug
@@ -60,26 +82,57 @@ module Mixlib
# :fatal
#
# Throws an ArgumentError if you feed it a bogus log level.
- def level=(l)
- lv = @@levels[l]
- raise ArgumentError, "Log level must be one of :debug, :info, :warn, :error, or :fatal" if lv.nil?
- logger.level = lv
+ def level=(new_level)
+ level_int = LEVEL_NAMES.key?(new_level) ? new_level : LEVELS[new_level]
+ raise ArgumentError, "Log level must be one of :debug, :info, :warn, :error, or :fatal" if level_int.nil?
+ loggers.each {|l| l.level = level_int }
end
- def level(lv=nil)
- if lv.nil?
- @@levels.find() {|l| logger.level==l[1]}[0]
+ def level(new_level=nil)
+ if new_level.nil?
+ LEVEL_NAMES[logger.level]
else
- self.level=(lv)
+ self.level=(new_level)
end
end
-
+
+ # Define the standard logger methods on this class programmatically.
+ # No need to incur method_missing overhead on every log call.
+ [:debug, :info, :warn, :error, :fatal].each do |method_name|
+ class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
+ def #{method_name}(msg=nil, &block)
+ loggers.each {|l| l.#{method_name}(msg, &block) }
+ end
+ METHOD_DEFN
+ end
+
+ # Define the methods to interrogate the logger for the current log level.
+ # Note that we *only* query the default logger (@logger) and not any other
+ # loggers that may have been added, even though it is possible to configure
+ # two (or more) loggers at different log levels.
+ [:debug?, :info?, :warn?, :error?, :fatal?].each do |method_name|
+ class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
+ def #{method_name}
+ logger.#{method_name}
+ end
+ METHOD_DEFN
+ end
+
+ def <<(msg)
+ loggers.each {|l| l << msg }
+ end
+
+ def add(severity, message = nil, progname = nil, &block)
+ loggers.each {|l| l.add(severity, message = nil, progname = nil, &block) }
+ end
+
+
# Passes any other method calls on directly to the underlying Logger object created with init. If
- # this method gets hit before a call to Mixlib::Logger.init has been made, it will call
+ # this method gets hit before a call to Mixlib::Logger.init has been made, it will call
# Mixlib::Logger.init() with no arguments.
def method_missing(method_symbol, *args, &block)
- logger.send(method_symbol, *args, &block)
+ loggers.each {|l| l.send(method_symbol, *args, &block) }
end
-
+
end
end
diff --git a/spec/mixlib/log_spec.rb b/spec/mixlib/log_spec.rb
index 57c8a5b..1d1c4f7 100644
--- a/spec/mixlib/log_spec.rb
+++ b/spec/mixlib/log_spec.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -26,9 +26,9 @@ describe Mixlib::Log do
# Since we are testing class behaviour for an instance variable
# that gets set once, we need to reset it prior to each example [cb]
before(:each) do
- Logit.instance_variable_set("@logger",nil)
+ Logit.reset!
end
-
+
it "should accept regular options to Logger.new via init" do
Tempfile.open("chef-test-log") do |tf|
lambda { Logit.init(STDOUT) }.should_not raise_error
@@ -46,7 +46,7 @@ describe Mixlib::Log do
first_logdev.string.should_not match(/SECOND/)
second_logdev.string.should match(/SECOND/)
end
-
+
it "should set the log level using the binding form, with :debug, :info, :warn, :error, or :fatal" do
levels = {
:debug => Logger::DEBUG,
@@ -83,26 +83,26 @@ describe Mixlib::Log do
Logit.logger.level.should == constant
end
end
-
+
it "should raise an ArgumentError if you try and set the level to something strange using the binding form" do
lambda { Logit.level = :the_roots }.should raise_error(ArgumentError)
end
-
+
it "should raise an ArgumentError if you try and set the level to something strange using the method form" do
lambda { Logit.level(:the_roots) }.should raise_error(ArgumentError)
end
-
+
it "should pass other method calls directly to logger" do
Logit.level = :debug
Logit.should be_debug
lambda { Logit.debug("Gimme some sugar!") }.should_not raise_error
end
-
+
it "should default to STDOUT if init is called with no arguments" do
logger_mock = Struct.new(:formatter, :level).new
Logger.stub!(:new).and_return(logger_mock)
Logger.should_receive(:new).with(STDOUT).and_return(logger_mock)
Logit.init
end
-
+
end