Working on a little Ruby script that goes out to the web and crawls various services. I've got a module with several classes inside:
module Crawler
class Runner
class Options
class Engine
end
I want to share one logger among all those of those classes. Normally I'd just put this in a constant in the module and reference it like so:
Crawler::LOGGER.info("Hello, world")
The problem is that I can't create my logger instance until I know where the output is going. You start the crawler via command line and at that point you can tell it you want to run in development (log output goes to STDOUT) or production (log output goes to a file, crawler.log):
crawler --environment=production
I have a class Options
that parses the options passed in through the command line. Only at that point do I know how to instantiate the logger with the correct output location.
So, my question is: how/where to I put my logger object so that all my classes have access to it?
I could pass my logger instance to each new()
call for every class instance I create, but I know there has to be a better, Rubyish way to do it. I'm imagining some weird class variable on the module that shared with class << self
or some other magic. :)
A little more detail: Runner
starts everything by passing the command line options to the Options
class and gets back an object with a couple of instance variables:
module Crawler
class Runner
def initialize(argv)
@options = Options.new(argv)
# feels like logger initialization should go here
# @options.log_output => STDOUT or string (log file name)
# @options.log_level => Logger::DEBUG or Logger::INFO
@engine = Engine.new()
end
def run
@engine.go
end
end
end
runner = Runner.new(ARGV)
runner.run
I need the code in Engine
to be able to access the logger object (along with a couple more classes that are initialized inside Engine
). Help!
All of this could be avoided if you could just dynamically change the output location of an already-instantiated Logger (similar to how you change the log level). I'd instantiate it to STDOUT and then change over to a file if I'm in production. I did see a suggestion somewhere about changing Ruby's $stdout global variable, which would redirect output somewhere other than STDOUT, but this seems pretty hacky.
Thanks!
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…