lib/semantic_logger/base.rb in semantic_logger-3.4.1 vs lib/semantic_logger/base.rb in semantic_logger-4.0.0.beta1
- old
+ new
@@ -2,12 +2,10 @@
#
# Abstract base class for loggers
#
# Implements common behavior such as log level, default text formatter etc
#
-# Note: Do not create instances of this class directly
-#
module SemanticLogger
class Base
# Class name to be logged
attr_accessor :name, :filter
@@ -114,12 +112,37 @@
else
block.call(params) if block
end
end
+ # Backward compatibility
alias_method :benchmark, :measure
+ # Log a thread backtrace
+ def backtrace(thread: Thread.current, level: :warn, message: 'Backtrace:', payload: nil, metric: nil, metric_amount: 1)
+ log = Log.new(name, level)
+ backtrace =
+ if thread == Thread.current
+ self.class.cleanse_backtrace
+ else
+ log.thread_name = thread.name
+ log.tags = thread[:semantic_logger_tags].clone
+ log.named_tags = thread[:semantic_logger_named_tags].clone
+ thread.backtrace
+ end
+ # TODO: Keep backtrace instead of transforming into a text message at this point
+ # Maybe log_backtrace: true
+ if backtrace
+ message += "\n"
+ message << backtrace.join("\n")
+ end
+
+ if log.assign(message: message, backtrace: backtrace, payload: payload, metric: metric, metric_amount: metric_amount) && should_log?(log)
+ self.log(log)
+ end
+ end
+
# :nodoc:
def tagged(*tags, &block)
SemanticLogger.tagged(*tags, &block)
end
@@ -149,37 +172,20 @@
# :nodoc:
def fast_tag(tag, &block)
SemanticLogger.fast_tag(tag, &block)
end
- # Thread specific context information to be logged with every log entry
- #
- # Add a payload to all log calls on This Thread within the supplied block
- #
- # logger.with_payload(tracking_number: 12345) do
- # logger.debug('Hello World')
- # end
- #
- # If a log call already includes a pyload, this payload will be merged with
- # the supplied payload, with the supplied payload taking precedence
- #
- # logger.with_payload(tracking_number: 12345) do
- # logger.debug('Hello World', result: 'blah')
- # end
+ # :nodoc:
def with_payload(payload)
- current_payload = self.payload
- Thread.current[:semantic_logger_payload] = current_payload ? current_payload.merge(payload) : payload
- yield
- ensure
- Thread.current[:semantic_logger_payload] = current_payload
+ warn '#with_payload is deprecated, use SemanticLogger.named_tagged'
+ SemanticLogger.named_tagged(payload)
end
- # Returns [Hash] payload to be added to every log entry in the current scope
- # on this thread.
- # Returns nil if no payload is currently set
+ # :nodoc:
def payload
- Thread.current[:semantic_logger_payload]
+ warn '#payload is deprecated, use SemanticLogger.named_tags'
+ SemanticLogger.named_tags
end
protected
# Write log data to underlying data storage
@@ -204,13 +210,12 @@
# 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
+ 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
if level.nil?
@@ -245,147 +250,75 @@
# Ensure minimum log level is met, and check filter
(level_index <= (log.level_index || 0)) && include_message?(log)
end
# Log message at the specified level
- def log_internal(level, index, message=nil, payload=nil, exception=nil)
- # Exception being logged?
- # Under JRuby a java exception is not a Ruby Exception
- # Java::JavaLang::ClassCastException.new.is_a?(Exception) => false
- if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
- exception = message
- message = nil
- elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
- exception = payload
- payload = nil
- end
-
- # Add result of block as message or payload if not nil
- if block_given? && (result = yield)
- if result.is_a?(String)
- message = message.nil? ? result : "#{message} -- #{result}"
- elsif message.nil? && result.is_a?(Hash)
- message = result
- elsif payload && payload.respond_to?(:merge)
- payload.merge(result)
+ def log_internal(level, index, message = nil, payload = nil, exception = nil, &block)
+ log = Log.new(name, level, index)
+ should_log =
+ if payload.nil? && exception.nil? && message.is_a?(Hash)
+ log.assign(message)
else
- payload = result
+ log.assign_positional(message, payload, exception, &block)
end
- end
- # Add scoped payload
- if self.payload
- payload = payload.nil? ? self.payload : self.payload.merge(payload)
- end
-
- # Add caller stack trace
- backtrace = extract_backtrace if index >= SemanticLogger.backtrace_level_index
-
- log = Log.new(level, Thread.current.name, name, message, payload, Time.now, nil, tags, index, exception, nil, backtrace)
-
- # Logging Hash only?
- # logger.info(name: 'value')
- if payload.nil? && exception.nil? && message.is_a?(Hash)
- payload = message.dup
- min_duration = payload.delete(:min_duration) || 0.0
- log.exception = payload.delete(:exception)
- log.message = payload.delete(:message)
- log.metric = payload.delete(:metric)
- log.metric_amount = payload.delete(:metric_amount) || 1
- if duration = payload.delete(:duration)
- return false if duration <= min_duration
- log.duration = duration
- end
- log.payload = payload if payload.size > 0
- end
-
- self.log(log) if include_message?(log)
+ self.log(log) if should_log && include_message?(log)
end
- SELF_PATTERN = File.join('lib', 'semantic_logger')
-
- # Extract the callers backtrace leaving out Semantic Logger
- def extract_backtrace
- stack = caller
- while (first = stack.first) && first.include?(SELF_PATTERN)
- stack.shift
- end
- stack
- end
-
# Measure the supplied block and log the message
def measure_internal(level, index, message, params)
- start = Time.now
exception = nil
+ result = nil
+ # Single parameter is a hash
+ if params.empty? && message.is_a?(Hash)
+ params = message
+ message = nil
+ end
+ start = Time.now
begin
if block_given?
- result =
+ result =
if silence_level = params[:silence]
# In case someone accidentally sets `silence: true` instead of `silence: :error`
silence_level = :error if silence_level == true
silence(silence_level) { yield(params) }
else
yield(params)
end
- exception = params[:exception]
- result
end
rescue Exception => exc
exception = exc
ensure
- end_time = Time.now
- # Extract options after block completes so that block can modify any of the options
- log_exception = params[:log_exception] || :partial
- on_exception_level = params[:on_exception_level]
- min_duration = params[:min_duration] || 0.0
- payload = params[:payload]
- metric = params[:metric]
- duration =
+ # Must use ensure block otherwise a `return` in the yield above will skip the log entry
+ log = Log.new(name, level, index)
+ exception ||= params[:exception]
+ message = params[:message] if params[:message]
+ duration =
if block_given?
- 1000.0 * (end_time - start)
+ 1000.0 * (Time.now - start)
else
params[:duration] || raise('Mandatory block missing when :duration option is not supplied')
end
- # Add scoped payload
- if self.payload
- payload = payload.nil? ? self.payload : self.payload.merge(payload)
- end
- if exception
- logged_exception = exception
- backtrace = nil
- case log_exception
- when :full
- # On exception change the log level
- if on_exception_level
- level = on_exception_level
- index = SemanticLogger.level_to_index(level)
- end
- when :partial
- # On exception change the log level
- if on_exception_level
- level = on_exception_level
- index = SemanticLogger.level_to_index(level)
- end
- message = "#{message} -- Exception: #{exception.class}: #{exception.message}"
- logged_exception = nil
- backtrace = exception.backtrace
- else
- # Log the message with its duration but leave out the exception that was raised
- logged_exception = nil
- backtrace = exception.backtrace
- end
- log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, logged_exception, metric, backtrace)
- self.log(log) if include_message?(log)
- raise exception
- elsif duration >= min_duration
- # Only log if the block took longer than 'min_duration' to complete
- # Add caller stack trace
- backtrace = extract_backtrace if index >= SemanticLogger.backtrace_level_index
+ # Extract options after block completes so that block can modify any of the options
+ payload = params[:payload]
- log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric, backtrace)
- self.log(log) if include_message?(log)
- end
+ should_log = log.assign(
+ message: message,
+ payload: payload,
+ min_duration: params[:min_duration] || 0.0,
+ exception: exception,
+ metric: params[:metric],
+ metric_amount: 1,
+ duration: duration,
+ backtrace: nil,
+ log_exception: params[:log_exception] || :partial,
+ on_exception_level: params[:on_exception_level]
+ )
+
+ self.log(log) if should_log && include_message?(log)
+ raise exception if exception
+ result
end
end
end
end