require 'facter' module Facter::Core::Logging extend self # @api private GREEN = "" # @api private RESET = "" # @api private @@debug = false # @api private @@timing = false # @api private @@trace = false # @api private @@warn_messages = {} # @api private @@debug_messages = {} # @api private @@message_callback = nil # Used to register a callback that is called when a message is logged. # If a block is given, Facter will not log messages. # If a block is not given, Facter will resume logging messages. # @param block [Proc] the callback to call when a message is logged. # The first argument to the callback will be a symbol representing a level. The supported # levels are: :trace, :debug, :info, :warn, :error, and :fatal. # The second argument to the callback will be a string containing the message # that was logged. # @api public def on_message(&block) @@message_callback = block end # Prints a debug message if debugging is turned on # # @param msg [String] the debug message # @return [void] def debug(msg) if self.debugging? if msg.nil? or msg.empty? invoker = caller[0].slice(/.*:\d+/) self.warn "#{self.class}#debug invoked with invalid message #{msg.inspect}:#{msg.class} at #{invoker}" elsif @@message_callback @@message_callback.call(:debug, msg) else puts GREEN + msg + RESET end end end # Prints a debug message only once. # # @note Uniqueness is based on the string, not the specific location # of the method call. # # @param msg [String] the debug message # @return [void] def debugonce(msg) if msg and not msg.empty? and @@debug_messages[msg].nil? @@debug_messages[msg] = true debug(msg) end end # Prints a warning message. The message is only printed if debugging # is enabled. # # @param msg [String] the warning message to be printed # # @return [void] def warn(msg) if msg.nil? or msg.empty? invoker = caller[0].slice(/.*:\d+/) msg = "#{self.class}#debug invoked with invalid message #{msg.inspect}:#{msg.class} at #{invoker}" end if @@message_callback @@message_callback.call(:warn, msg) else Kernel.warn msg end end # Prints a warning message only once per process. Each unique string # is printed once. # # @note Unlike {warn} the message will be printed even if debugging is # not turned on. This behavior is likely to change and should not be # relied on. # # @param msg [String] the warning message to be printed # # @return [void] def warnonce(msg) if @@warn_messages[msg].nil? self.warn(msg) @@warn_messages[msg] = true end end def log_exception(exception, message = :default) self.warn(format_exception(exception, message, @@trace)) end def format_exception(exception, message, trace) arr = [] if message == :default arr << exception.message elsif message arr << message end if trace arr.concat(exception.backtrace) end arr.flatten.join("\n") end # Print an exception message, and optionally a backtrace if trace is set # Print timing information # # @param string [String] the time to print # @return [void] # # @api private def show_time(string) return unless string && self.timing? if @@message_callback @@message_callback.call(:info, string) else $stderr.puts "#{GREEN}#{string}#{RESET}" end end # Enable or disable logging of debug messages # # @param bool [true, false] # @return [void] # # @api private def debugging(bool) @@debug = bool end # Is debugging enabled? # # @return [true, false] # # @api private def debugging? @@debug end # Enable or disable logging of timing information # # @param bool [true, false] # @return [void] # # @api private def timing(bool) @@timing = bool end # Returns whether timing output is turned on # # @api private def timing? @@timing end def trace(bool) @@trace = bool end def trace? @@trace end # Clears the seen state of debug and warning messages. See {debugonce} and {warnonce}. # # @return [void] # # @api private def clear_messages @@debug_messages.clear @@warn_messages.clear end end