lib/lumber/lumber.rb in lumber-0.0.2 vs lib/lumber/lumber.rb in lumber-0.9.0

- old
+ new

@@ -1,6 +1,9 @@ require "socket" +require "active_support/core_ext/duplicable" +require "active_support/core_ext/class" +require "active_support/core_ext/module" module Lumber # Initializes log4r system. Needs to happen in # config/environment.rb before Rails::Initializer.run @@ -34,55 +37,117 @@ if defined?(RAILS_DEFAULT_LOGGER) Object.send(:remove_const, :RAILS_DEFAULT_LOGGER) end Object.const_set('RAILS_DEFAULT_LOGGER', Log4r::Logger['rails']) + @@registered_loggers = {} + self.register_inheritance_handler() end # Makes :logger exist independently for subclasses and sets that logger - # to one that inherits from base_class for each subclass as its created. + # to one that inherits from base_class for each subclass as it is created. # This allows you to have a finer level of control over logging, for example, # put just a single class, or hierarchy of classes, into debug log level # # for example: # - # Lumber.setup_logger_hierarchy(ActiveRecord::Base, "rails::models") + # Lumber.setup_logger_hierarchy("ActiveRecord::Base", "rails::models") # # causes all models that get created to have a log4r logger named # "rails::models::<class_name>". This class can individually be # put into debug log mode in production (see {log4r docs}[http://log4r.sourceforge.net/manual.html]), and log # output will include "<class_name>" on every log from this class # so that you can tell where a log statement came from # - def self.setup_logger_hierarchy(base_class, parent_fullname) - base_class.class_eval do - class_inheritable_accessor :logger - self.logger = Log4r::Logger.new(parent_fullname) + def self.setup_logger_hierarchy(class_name, class_logger_fullname) + @@registered_loggers[class_name] = class_logger_fullname + obj = nil + names = class_name.split '::' + names.each do |name| + root ||= Object + if root.const_defined?(name) + obj = root.const_get(name) + root = obj + else + obj = nil + end + end + + if obj + obj.class_eval do + class_inheritable_accessor :logger + self.logger = Log4r::Logger.new(class_logger_fullname) + end + end + end + + private + + # Adds a inheritance handler to Object so we can know to add loggers + # for classes as they get defined. + def self.register_inheritance_handler() + return if defined?(Object.inherited_with_lumber_log4r) + + Object.class_eval do + class << self + def inherited_with_lumber_log4r(subclass) inherited_without_lumber_log4r(subclass) - # p "#{self} -> #{subclass} -> #{self.logger}" - # Look up the class hierarchy for a useable logger - # A class may have a nil logger if it was created - # before we add logger/inheritance to its superclas, - # e.g. Object/Exception - something tries to subclass - # Exception after we added lumber_inherited to Object, - # but Exception was defined before we added lumber_inherited - while self.logger.nil? - next_class = (next_class ||self).superclass - if next_class.nil? - self.logger = Log4r::Logger.root - else - self.logger = next_class.logger - end + # if the new class is in the list that were registered directly, + # then create their logger attribute directly, otherwise derive it + logger_name = @@registered_loggers[subclass.name] + if logger_name + Lumber.add_lumber_logger(subclass, logger_name) + else + Lumber.derive_lumber_logger(subclass) end - subclass.logger = Log4r::Logger.new("#{logger.fullname}::#{subclass.name}") end + alias_method_chain :inherited, :lumber_log4r + end + end + + end + + def self.add_lumber_logger(clazz, logger_name) + clazz.class_eval do + + class_inheritable_accessor :logger + self.logger = Log4r::Logger.new(logger_name) + + class << self + + # Prevent rails from overwriting our logger + def cattr_accessor_with_lumber_log4r(*syms) + without_logger = syms.reject {|s| s == :logger} + cattr_accessor_without_lumber_log4r(*without_logger) + end + alias_method_chain :cattr_accessor, :lumber_log4r + + end + + end + end + + def self.derive_lumber_logger(clazz) + # otherwise, walk up the classes hierarchy till you find a logger + # that was registered, and use that logger as the parent for the + # logger of the new class + parent = clazz.superclass + while ! parent.nil? + if defined?(parent.logger) && parent.logger + parent_is_registered = @@registered_loggers.values.find {|v| parent.logger.fullname.index(v) == 0} + if parent_is_registered + clazz.logger = Log4r::Logger.new("#{parent.logger.fullname}::#{clazz.name}") + break + end + end + parent = parent.superclass end end end \ No newline at end of file