diff options
author | Daniel DeLeo <dan@opscode.com> | 2011-03-15 19:10:16 -0700 |
---|---|---|
committer | Daniel DeLeo <dan@opscode.com> | 2011-03-15 19:10:16 -0700 |
commit | 9939a40e1cbbf509244a62c05b9089f69af1b2bb (patch) | |
tree | 68c635039edabff0b2627fb07dd2b878e89178d1 | |
parent | 0dee0929cf660f02e474ee488e54a37b15b8c79d (diff) | |
download | mixlib-log-9939a40e1cbbf509244a62c05b9089f69af1b2bb.tar.gz |
add multiple logger support
-rw-r--r-- | VERSION.yml | 2 | ||||
-rw-r--r-- | lib/mixlib/log.rb | 91 | ||||
-rw-r--r-- | spec/mixlib/log_spec.rb | 20 |
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 |