From: Tim Pease Date: 2010-05-02T00:29:06+09:00 Subject: Re: subclassing Logging On Apr 30, 2010, at 11:23 PM, dhf@dhfrench.com wrote: > Tim, > > I am trying to subclass the logging module to have a consistent setup for my classes. They all log to the same rolling file. I seem to get two different errors. > > Error one: > require 'fileutils' > require 'logging' > > module MyLogger > class Log < Logging::Logger > def initialize(config) # config not used in test but will be. > super("reader") > Logging.appenders.stdout(:level => :debug) > file_path = "./reader.log" > Logging.appenders.rolling_file( > "readerlog", > :filename => file_path, > :age => :daily, > :layout => Logging.layouts.json) > add_appenders('stdout','readerlog') > end > end > end > Take a look at this example logging configuration. It walks though the concept of logger hierarchies in the logging framework. http://github.com/TwP/logging/blob/master/examples/hierarchies.rb This, I believe, is what you are trying to accomplish. You should not have to subclass the Logging:Logger. Take a look at the other example files in that "examples" folder; they walk through in code some of the concepts behind the logging framework. Logging.appenders.stdout( 'stdout', :layout => Logging.layouts.pattern ) Logging.appenders.rolling_file( 'readerlog', :filename => './reader.log', :age => :daily, :layout => Logging.layouts.json ) logger = Logging.logger['YourModule'] logger.appenders = ['stdout', 'readerlog'] logger.level = :info In the above snippet of code, I created two appenders. The first is named "stdout" and will use a pattern based layout to write log messages to STDOUT. The second is named "readerlog" and will use a JSON layout to write log messages to a file called "reader.log". I then created a new logger instance, added the two appenders by name, and then set the log level to 'info'. Now you can create nested loggers that will use the same appenders and have the same default log level. another_logger = Logging.logger['YourModule::Another'] yet_another_logger = Logging.logger['YourModule::Another::Yet'] > with this in a larger program or by it self I get: > > NoMethodError: undefined method `synchronize' for nil:NilClass > from /usr/local/ruby/lib/ruby/gems/1.8/gems/logging-1.4.1/lib/logging/logger.rb:51:in `new' > from (irb):2 > irb command is l = MyLogger::Log.new('test') > > If I remove the parameter from the initialize, I can make it work standalone. > > I tried using rspec in the larger app and just the test for log fails the same with the parameter. I take it off and the init passes but the actual log does not return. > The Logging framework has built in support for rspec. It can be configured to log all messages to a StringIO instance during tests. You can then read out your log messages from the StringIO and make sure the right messages are making it into the log. In your spec_helper file .... require 'spec/logging_helper' Spec::Runner.configure do |config| include Spec::LoggingHelper config.capture_log_messages end And in your actual specs ... it 'logs a message on error' do @foo.error_method @log_output.readline.should == 'This is your error message' end I hope all this helps. Blessings, TwP PS I cc'd the ruby-talk mailing list so this information can be found by others. > describe MyLogger::Log do > it "should initialize" do > l = MyLogger::Log.new() > l.class.should == MyLogger::Log > end > end > > describe MyLogger::Log do > before :each do > @log = MyLogger::Log.new > end > > it "should log a debug" do > @log.info "Rspec debug".should == true > end > > end > > the @log.info fails with: > 'MyLogger::Log should log a debug' FAILED > expected: true, > got: "Rspec debug" (using ==) > > > I can use any help you can give. > > Don French