lib/dldinternet/mixlib/logging.rb in dldinternet-mixlib-logging-0.2.0 vs lib/dldinternet/mixlib/logging.rb in dldinternet-mixlib-logging-0.3.0

- old
+ new

@@ -9,10 +9,115 @@ require "rubygems" require 'rubygems/gem_runner' require 'rubygems/exceptions' require 'logging' + module ::Logging + class << self + + # call-seq: + # Logging.logger( device, age = 7, size = 1048576 ) + # Logging.logger( device, age = 'weekly' ) + # + # This convenience method returns a Logger instance configured to behave + # similarly to a core Ruby Logger instance. + # + # The _device_ is the logging destination. This can be a filename + # (String) or an IO object (STDERR, STDOUT, an open File, etc.). The + # _age_ is the number of old log files to keep or the frequency of + # rotation (+daily+, +weekly+, or +monthly+). The _size_ is the maximum + # logfile size and is only used when _age_ is a number. + # + # Using the same _device_ twice will result in the same Logger instance + # being returned. For example, if a Logger is created using STDOUT then + # the same Logger instance will be returned the next time STDOUT is + # used. A new Logger instance can be obtained by closing the previous + # logger instance. + # + # log1 = Logging.logger(STDOUT) + # log2 = Logging.logger(STDOUT) + # log1.object_id == log2.object_id #=> true + # + # log1.close + # log2 = Logging.logger(STDOUT) + # log1.object_id == log2.object_id #=> false + # + # The format of the log messages can be changed using a few optional + # parameters. The <tt>:pattern</tt> can be used to change the log + # message format. The <tt>:date_pattern</tt> can be used to change how + # timestamps are formatted. + # + # log = Logging.logger(STDOUT, + # :pattern => "[%d] %-5l : %m\n", + # :date_pattern => "%Y-%m-%d %H:%M:%S.%s") + # + # See the documentation for the Logging::Layouts::Pattern class for a + # full description of the :pattern and :date_pattern formatting strings. + # + def logger( *args ) + return ::Logging::Logger if args.empty? + + opts = args.pop if args.last.instance_of?(Hash) + opts ||= Hash.new + + dev = args.shift + keep = age = args.shift + size = args.shift + + name = case dev + when String; dev + when File; dev.path + else dev.object_id.to_s end + + repo = ::Logging::Repository.instance + return repo[name] if repo.has_logger? name + + l_opts = { + :pattern => "%.1l, [%d #%p] %#{::Logging::MAX_LEVEL_LENGTH}l : %m\n", + :date_pattern => '%Y-%m-%dT%H:%M:%S.%s' + } + [:pattern, :date_pattern, :date_method].each do |o| + l_opts[o] = opts.delete(o) if opts.has_key? o + end + layout = ::Logging::Layouts::Pattern.new(l_opts) + + a_opts = Hash.new + a_opts[:size] = size if size.instance_of?(Fixnum) + a_opts[:age] = age if age.instance_of?(String) + a_opts[:keep] = keep if keep.instance_of?(Fixnum) + a_opts[:filename] = dev if dev.instance_of?(String) + a_opts[:layout] = layout + a_opts.merge! opts + + appender = + case dev + when String + ::Logging::Appenders::RollingFile.new(name, a_opts) + else + ::Logging::Appenders::IO.new(name, dev, a_opts) + end + + logger = ::Logging::Logger.new(name, opts) + logger.add_appenders appender + logger.additive = false + + class << logger + def close + @appenders.each {|a| a.close} + h = ::Logging::Repository.instance.instance_variable_get :@h + h.delete(@name) + class << self; undef :close; end + end + end + + logger + end + + end + + end + class ::Logging::ColorScheme def scheme(s=nil) @scheme = s if s @scheme end @@ -23,10 +128,14 @@ def define_log_methods( logger ) ::Logging::LEVELS.each do |name,num| code = "undef :#{name} if method_defined? :#{name}\n" code << "undef :#{name}? if method_defined? :#{name}?\n" + unless logger.level.is_a?(Fixnum) + puts "logger.level for #{logger.name} is a #{logger.level.class} instead of a Fixnum!!!" + exit -1 + end if logger.level > num code << <<-CODE def #{name}?( ) false end def #{name}( data = nil, trace = false ) false end CODE @@ -34,11 +143,12 @@ code << <<-CODE def #{name}?( ) true end def #{name}( data = nil, trace = nil ) caller = Kernel.caller[3] num = #{num} - if num >= #{logger.level} + level = #{logger.level} + if num >= level data = yield if block_given? #log_event(::Logging::LogEvent.new(@name, num, caller, true)) log_event(::Logging::LogEvent.new(@name, num, data, trace.nil? ? @trace : trace)) end true @@ -48,53 +158,127 @@ logger._meta_eval(code, __FILE__, __LINE__) end logger end + + # Overrides the new method such that only one Logger will be created + # for any given logger name. + # + def new( *args ) + return super if args.empty? + + repo = ::Logging::Repository.instance + name = repo.to_key(args.shift) + opts = args.last.instance_of?(Hash) ? args.pop : {} + + @mutex.synchronize do + logger = repo[name] + if logger.nil? + + master = repo.master_for(name) + if master + if repo.has_logger?(master) + logger = repo[master] + else + logger = super(master) + repo[master] = logger + repo.children(master).each {|c| c.__send__(:parent=, logger)} + end + repo[name] = logger + else + logger = super(name, opts) + repo[name] = logger + repo.children(name).each {|c| c.__send__(:parent=, logger)} + end + end + logger + end + end + end + # call-seq: + # Logger.new( name ) + # Logger[name] + # + # Returns the logger identified by _name_. + # + # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to + # retrieve the logger. When _name_ is a +Class+ the class name will be + # used to retrieve the logger. When _name_ is an object the name of the + # object's class will be used to retrieve the logger. + # + # Example: + # + # obj = MyClass.new + # + # log1 = Logger.new(obj) + # log2 = Logger.new(MyClass) + # log3 = Logger['MyClass'] + # + # log1.object_id == log2.object_id # => true + # log2.object_id == log3.object_id # => true + # + def initialize( name, *args ) + case name + when String + raise(ArgumentError, "logger must have a name") if name.empty? + else raise(ArgumentError, "logger name must be a String") end + + repo = ::Logging::Repository.instance + opts = args.last.instance_of?(Hash) ? args.pop : {} + _setup(name, opts.merge({:parent => repo.parent(name)})) + end + + def logEvent(evt) log_event evt end end class ::Logging::Layouts::Pattern # Arguments to sprintf keyed to directive letters verbose, $VERBOSE = $VERBOSE, nil # noinspection RubyStringKeysInHashInspection DIRECTIVE_TABLE = { + 'C' => 'event.file != "" ? "(\e[38;5;25m#{event.file}::#{event.line}\e[0m)" : ""', 'c' => 'event.logger'.freeze, 'd' => 'format_date(event.time)'.freeze, 'F' => 'event.file'.freeze, + 'f' => 'File.basename(event.file)'.freeze, + 'g' => 'event.file != "" ? "(\e[38;5;25m#{File.join(File.dirname(event.file).split(File::SEPARATOR)[-2..-1],File.basename(event.file))}::#{event.line}\e[0m)" : ""', 'l' => '::Logging::LNAMES[event.level]'.freeze, 'L' => 'event.line'.freeze, - 'm' => 'format_obj(event.data)'.freeze, 'M' => 'event.method'.freeze, + 'm' => 'format_obj(event.data)'.freeze, 'p' => 'Process.pid'.freeze, 'r' => 'Integer((event.time-@created_at)*1000).to_s'.freeze, 't' => 'Thread.current.object_id.to_s'.freeze, 'T' => 'Thread.current[:name]'.freeze, - 'C' => 'event.file != "" ? "(\e[38;5;25m#{event.file}::#{event.line}\e[0m)" : ""', '%' => :placeholder }.freeze # Human name aliases for directives - used for colorization of tokens # noinspection RubyStringKeysInHashInspection COLOR_ALIAS_TABLE = { + 'C' => :file_line, 'c' => :logger, 'd' => :date, + 'F' => :file, + 'f' => :file, + 'g' => :file, + 'L' => :line, + 'l' => :logger, + 'M' => :method, 'm' => :message, 'p' => :pid, 'r' => :time, 'T' => :thread, 't' => :thread_id, - 'F' => :file, - 'L' => :line, - 'M' => :method, 'X' => :mdc, 'x' => :ndc, - 'C' => :file_line, }.freeze ensure $VERBOSE = verbose end @@ -245,10 +429,11 @@ logger.level = args[:log_level] ? args[:log_level] : :warn logger.trace = true if args[:trace] @logger_args = args rescue Gem::LoadError logger = FakeLogger.new - rescue => e + rescue Exception => e + puts e # not installed logger = FakeLogger.new end @TODO = {} if @TODO.nil? end # if args