require 'rex/sync' require 'rex/logging/log_sink' module Rex module Logging ### # # The log dispatcher associates log sources with log sinks. A log source # is a unique identity that is associated with one and only one log sink. # For instance, the framework-core registers the 'core' # ### class LogDispatcher # # Creates the global log dispatcher instance and initializes it for use. # def initialize() self.log_sinks = {} self.log_levels = {} self.log_sinks_rwlock = ReadWriteLock.new end # # Returns the sink that is associated with the supplied source. # def [](src) sink = nil log_sinks_rwlock.synchronize_read { sink = log_sinks[src] } return sink end # # Calls the source association routie. # def []=(src, sink) store(src, sink) end # # Associates the supplied source with the supplied sink. If a log level # has already been defined for the source, the level argument is ignored. # Use set_log_level to alter it. # def store(src, sink, level = 0) log_sinks_rwlock.synchronize_write { if (log_sinks[src] == nil) log_sinks[src] = sink set_log_level(src, level) if (log_levels[src] == nil) else raise( RuntimeError, "The supplied log source #{src} is already registered.", caller) end } end # # Removes a source association if one exists. # def delete(src) sink = nil log_sinks_rwlock.synchronize_write { sink = log_sinks[src] log_sinks.delete(src) } if (sink) sink.cleanup return true end return false end # # Performs the actual log operation against the supplied source # def log(sev, src, level, msg, from) log_sinks_rwlock.synchronize_read { if ((sink = log_sinks[src])) next if (log_levels[src] and level > log_levels[src]) sink.log(sev, src, level, msg, from) end } end # # This method sets the log level threshold for a given source. # def set_level(src, level) log_levels[src] = level.to_i end # # This method returns the log level threshold of a given source. # def get_level(src) log_levels[src] end attr_accessor :log_sinks, :log_sinks_rwlock # :nodoc: attr_accessor :log_levels # :nodoc: end end end ### # # An instance of the log dispatcher exists in the global namespace, along # with stubs for many of the common logging methods. Various sources can # register themselves as a log sink such that logs can be directed at # various targets depending on where they're sourced from. By doing it # this way, things like sessions can use the global logging stubs and # still be directed at the correct log file. # ### ExceptionCallStack = "__EXCEPTCALLSTACK__" def dlog(msg, src = 'core', level = 0, from = caller) $dispatcher.log(LOG_DEBUG, src, level, msg, from) end def elog(msg, src = 'core', level = 0, from = caller) $dispatcher.log(LOG_ERROR, src, level, msg, from) end def wlog(msg, src = 'core', level = 0, from = caller) $dispatcher.log(LOG_WARN, src, level, msg, from) end def ilog(msg, src = 'core', level = 0, from = caller) $dispatcher.log(LOG_INFO, src, level, msg, from) end def rlog(msg, src = 'core', level = 0, from = caller) if (msg == ExceptionCallStack) msg = "\nCall stack:\n" + $@.join("\n") + "\n" end $dispatcher.log(LOG_RAW, src, level, msg, from) end def log_source_registered?(src) ($dispatcher[src] != nil) end def register_log_source(src, sink, level = nil) $dispatcher[src] = sink set_log_level(src, level) if (level) end def deregister_log_source(src) $dispatcher.delete(src) end def set_log_level(src, level) $dispatcher.set_level(src, level) end def get_log_level(src) $dispatcher.get_level(src) end # Creates the global log dispatcher $dispatcher = Rex::Logging::LogDispatcher.new