lib/semantic_logger/base.rb in semantic_logger-2.7.0 vs lib/semantic_logger/base.rb in semantic_logger-2.8.0
- old
+ new
@@ -7,26 +7,31 @@
# Note: Do not create instances of this class directly
#
module SemanticLogger
class Base
# Class name to be logged
- attr_accessor :name
+ attr_accessor :name, :filter
- attr_reader :level
-
# Set the logging level for this logger
#
- # Note: This level is only for this particular appender. It does not override
+ # Note: This level is only for this particular instance. It does not override
# the log level in any logging instance or the default log level
# SemanticLogger.default_level
#
- # Must be one of the values in SemanticLogger::LEVELS
+ # Must be one of the values in SemanticLogger::LEVELS, or
+ # nil if this logger instance should use the global default log_level
def level=(level)
- @level_index = self.class.map_level_to_index(level)
+ @level_index = SemanticLogger.level_to_index(level)
@level = level
end
+ # Returns the current log level if set, otherwise it returns the global
+ # default log level
+ def level
+ @level || SemanticLogger.default_level
+ end
+
# Implement the log level calls
# logger.debug(message, hash|exception=nil, &block)
#
# Implement the log level query
# logger.debug?
@@ -67,34 +72,44 @@
#
# # Log an exception in a semantic way
# logger.info("Parsing received XML", exc)
#
SemanticLogger::LEVELS.each_with_index do |level, index|
- class_eval <<-EOT, __FILE__, __LINE__
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
def #{level}(message=nil, payload=nil, exception=nil, &block)
- if @level_index <= #{index}
+ if level_index <= #{index}
log_internal(:#{level}, #{index}, message, payload, exception, &block)
true
else
false
end
end
def #{level}?
- @level_index <= #{index}
+ level_index <= #{index}
end
def benchmark_#{level}(message, params = {}, &block)
- if @level_index <= #{index}
+ if level_index <= #{index}
benchmark_internal(:#{level}, #{index}, message, params, &block)
else
block.call(params) if block
end
end
EOT
end
+ # Dynamically supply the log level with every benchmark call
+ def benchmark(level, message, params = {}, &block)
+ index = SemanticLogger.level_to_index(level)
+ if level_index <= index
+ benchmark_internal(level, index, message, params, &block)
+ else
+ block.call(params) if block
+ end
+ end
+
# Add the supplied tags to the list of tags to log for this thread whilst
# the supplied block is active
# Returns nil if no tags are currently set
# To support: ActiveSupport::TaggedLogging V3 and above
def tagged(*tags)
@@ -177,22 +192,48 @@
end
############################################################################
protected
- def initialize(klass, level=nil)
- @name = klass.is_a?(String) ? klass : klass.name
- self.level = level || SemanticLogger.default_level
+ # Initializer for Abstract Class SemanticLogger::Base
+ #
+ # Parameters
+ # klass [String]
+ # Name of the class, module, or other identifier for which the log messages
+ # are being logged
+ #
+ # level [Symbol]
+ # Only allow log entries of this level or higher to be written to this appender
+ # For example if set to :warn, this appender would only log :warn and :fatal
+ # log messages when other appenders could be logging :info and lower
+ #
+ # filter [Regexp|Proc]
+ # RegExp: Only include log messages where the class name matches the supplied
+ # regular expression. All other messages will be ignored
+ # Proc: Only include log messages where the supplied Proc returns true
+ # The Proc must return true or false
+ def initialize(klass, level=nil, filter=nil)
+ # Support filtering all messages to this logger using a Regular Expression
+ # or Proc
+ raise ":filter must be a Regexp or Proc" unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
+
+ @filter = filter.is_a?(Regexp) ? filter.freeze : filter
+ @name = klass.is_a?(String) ? klass : klass.name
+ self.level = level unless level.nil?
end
# Write log data to underlying data storage
def log(log_)
raise NotImplementedError.new("Logging Appender must implement #log(log)")
end
# Return the level index for fast comparisons
- attr_reader :level_index
+ # Returns the global default level index if the level has not been explicitly
+ # set for this instance
+ def level_index
+ @level_index || SemanticLogger.default_level_index
+ end
# Struct Log
#
# level
# Log level of the supplied log call
@@ -224,31 +265,19 @@
#
# metric [Object]
# Object supplied when benchmark_x was called
Log = Struct.new(:level, :thread_name, :name, :message, :payload, :time, :duration, :tags, :level_index, :exception, :metric)
- # Internal method to return the log level as an internal index
- # Also supports mapping the ::Logger levels to SemanticLogger levels
- def self.map_level_to_index(level)
- index = if level.is_a?(Integer) && defined?(::Logger::Severity)
- # Mapping of Rails and Ruby Logger levels to SemanticLogger levels
- @@map_levels ||= begin
- levels = []
- ::Logger::Severity.constants.each do |constant|
- levels[::Logger::Severity.const_get(constant)] = LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error)
- end
- levels
- end
- @@map_levels[level]
- elsif level.is_a?(String)
- level = level.downcase.to_sym
- LEVELS.index(level)
- else
- LEVELS.index(level)
+ # Whether to log the supplied message based on the current filter if any
+ def include_message?(struct)
+ return true if @filter.nil?
+
+ if @filter.is_a?(Regexp)
+ (@filter =~ struct.name) != nil
+ elsif @filter.is_a?(Proc)
+ @filter.call(struct) == true
end
- raise "Invalid level:#{level.inspect} being requested. Must be one of #{LEVELS.inspect}" unless index
- index
end
# Log message at the specified level
def log_internal(level, index, message=nil, payload=nil, exception=nil, &block)
if exception.nil? && payload && payload.is_a?(Exception)
@@ -268,11 +297,12 @@
# Add scoped payload
if self.payload
payload = payload.nil? ? self.payload : self.payload.merge(payload)
end
- log Log.new(level, Thread.current.name, name, message, payload, Time.now, nil, tags, index, exception)
+ struct = Log.new(level, Thread.current.name, name, message, payload, Time.now, nil, tags, index, exception)
+ log(struct) if include_message?(struct)
end
# Measure the supplied block and log the message
def benchmark_internal(level, index, message, params, &block)
start = Time.now
@@ -300,17 +330,20 @@
payload = payload.nil? ? self.payload : self.payload.merge(payload)
end
if exception
case log_exception
when :full
- log Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, exception, metric)
+ struct = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, exception, metric)
+ log(struct) if include_message?(struct)
when :partial
- log Log.new(level, Thread.current.name, name, "#{message} -- Exception: #{exception.class}: #{exception.message}", payload, end_time, duration, tags, index, nil, metric)
+ struct = Log.new(level, Thread.current.name, name, "#{message} -- Exception: #{exception.class}: #{exception.message}", payload, end_time, duration, tags, index, nil, metric)
+ log(struct) if include_message?(struct)
end
raise exception
elsif duration >= min_duration
# Only log if the block took longer than 'min_duration' to complete
- log Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric)
+ struct = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric)
+ log(struct) if include_message?(struct)
end
end
end
end