module Methadone # Provides easier access to a shared Methadone::CLILogger instance. # # Include this module into your class, and #logger provides access to a shared logger. # This is handy if you want all of your clases to have access to the same logger, but # don't want to (or aren't able to) pass it around to each class. # # This also provides methods for direct logging without going through the #logger # # === Example # # class MyClass # include Methadone::CLILogging # # def doit # debug("About to doit!") # if results # info("We did it!" # else # error("Something went wrong") # end # debug("Done doing it") # end # end # # Note that every class that mixes this in shares the *same logger instance*, so if you call #change_logger, this # will change the logger for all classes that mix this in. This is likely what you want. module CLILogging def self.included(k) k.extend(self) end # Access the shared logger. All classes that include this module # will get the same logger via this method. def logger @@logger ||= CLILogger.new end # Change the global logger that includers will use. Useful if you # don't want the default configured logger. Note that the +change_logger+ # version is preferred because Ruby will often parse logger = Logger.new as # the declaration of, and assignment to, of a local variable. You'd need to # do self.logger=Logger.new to be sure. This method # is a bit easier. # # +new_logger+:: the new logger. May not be nil and should be a logger of some kind def change_logger(new_logger) raise ArgumentError,"Logger may not be nil" if new_logger.nil? @@logger = new_logger @@logger.level = @log_level if @log_level end alias logger= change_logger # pass-through to logger.debug(progname,&block) def debug(progname = nil, &block); logger.debug(progname,&block); end # pass-through to logger.info(progname,&block) def info(progname = nil, &block); logger.info(progname,&block); end # pass-through to logger.warn(progname,&block) def warn(progname = nil, &block); logger.warn(progname,&block); end # pass-through to logger.error(progname,&block) def error(progname = nil, &block); logger.error(progname,&block); end # pass-through to logger.fatal(progname,&block) def fatal(progname = nil, &block); logger.fatal(progname,&block); end LOG_LEVELS = { 'debug' => Logger::DEBUG, 'info' => Logger::INFO, 'warn' => Logger::WARN, 'error' => Logger::ERROR, 'fatal' => Logger::FATAL, } # Call this *if* you've included Methadone::Main to set up a --log-level option for your app # that will allow the user to configure the logging level. You can pass an optional hash with # :toggle_debug_on_signal => to enable runtime toggling of the log level by sending the # signal to your app # # +args+:: optional hash # # Example: # # main do # # your app # end # # use_log_level_option # # go! # # Example with runtime toggling: # # # main do # # your app # end # # use_log_level_option :toggle_debug_on_signal => 'USR1' # # go! def use_log_level_option(args = {}) on("--log-level LEVEL",LOG_LEVELS,'Set the logging level', '(' + LOG_LEVELS.keys.join('|') + ')', '(Default: info)') do |level| @log_level = level @log_level_original = level @log_level_toggled = false logger.level = level setup_toggle_trap(args[:toggle_debug_on_signal]) end end private # Call this to toggle the log level between debug and its initial value def toggle_log_level @log_level_original = logger.level unless @log_level_toggled logger.level = if @log_level_toggled @log_level_original else LOG_LEVELS['debug'] end @log_level_toggled = !@log_level_toggled @log_level = logger.level end def setup_toggle_trap(signal) if signal Signal.trap(signal) do toggle_log_level end end end end end