lib/semantic_logger/appender/base.rb in semantic_logger-2.17.0 vs lib/semantic_logger/appender/base.rb in semantic_logger-2.18.0

- old
+ new

@@ -9,20 +9,31 @@ module SemanticLogger module Appender # Formatting & colors used by optional colorized_formatter module AnsiColors - CLEAR = "\e[0m" - BOLD = "\e[1m" - BLACK = "\e[30m" - RED = "\e[31m" - GREEN = "\e[32m" - YELLOW = "\e[33m" - BLUE = "\e[34m" - MAGENTA = "\e[35m" - CYAN = "\e[36m" - WHITE = "\e[37m" + CLEAR = "\e[0m" + BOLD = "\e[1m" + BLACK = "\e[30m" + RED = "\e[31m" + GREEN = "\e[32m" + YELLOW = "\e[33m" + BLUE = "\e[34m" + MAGENTA = "\e[35m" + CYAN = "\e[36m" + WHITE = "\e[37m" + + # Maps the log level to a color for colorized formatters + # Since this map is not frozen, it can be modified as needed + LEVEL_MAP = { + trace: MAGENTA, + debug: GREEN, + info: CYAN, + warn: BOLD, + error: RED, + fatal: RED + } end class Base < SemanticLogger::Base attr_accessor :formatter @@ -30,73 +41,77 @@ # Replace this formatter by supplying a Block to the initializer # Generates logs of the form: # 2011-07-19 14:36:15.660 D [1149:ScriptThreadProcess] Rails -- Hello World def default_formatter Proc.new do |log| - tags = log.tags.collect { |tag| "[#{tag}]" }.join(' ') + ' ' if log.tags && (log.tags.size > 0) + # Header with date, time, log level and process info + entry = "#{log.formatted_time} #{log.level_to_s} [#{log.process_info}]" - message = log.message.to_s.dup - message << ' -- ' << log.payload.inspect unless log.payload.nil? || (log.payload.respond_to?(:empty?) && log.payload.empty?) - message << ' -- Exception: ' << "#{log.exception.class}: #{log.exception.message}\n#{(log.exception.backtrace || []).join("\n")}" if log.exception + # Tags + entry << ' ' << log.tags.collect { |tag| "[#{tag}]" }.join(' ') if log.tags && (log.tags.size > 0) - duration_str = log.duration ? "(#{'%.1f' % log.duration}ms) " : '' + # Duration + entry << " (#{log.duration_human})" if log.duration - file_name = - if log.backtrace || log.exception - backtrace = log.backtrace || log.exception.backtrace - location = backtrace[0].split('/').last - file, line = location.split(':') - " #{file}:#{line}" - end + # Class / app name + entry << " #{log.name}" - "#{SemanticLogger::Appender::Base.formatted_time(log.time)} #{log.level.to_s[0..0].upcase} [#{$$}:#{'%.50s' % log.thread_name}#{file_name}] #{tags}#{duration_str}#{log.name} -- #{message}" + # Log message + entry << " -- #{log.message}" if log.message + + # Payload + unless log.payload.nil? || (log.payload.respond_to?(:empty?) && log.payload.empty?) + entry << ' -- ' << log.payload.inspect + end + + # Exceptions + log.each_exception do |exception, i| + entry << (i == 0 ? ' -- Exception: ' : "\nCause: ") + entry << "#{exception.class}: #{exception.message}\n#{(exception.backtrace || []).join("\n")}" + end + entry end end # Optional log formatter to colorize log output # To use this formatter - # SemanticLogger.add_appender($stdout, nil, &SemanticLogger::Logger.colorized_formatter) + # SemanticLogger.add_appender($stdout, &SemanticLogger::Appender::Base.colorized_formatter) # # 2011-07-19 14:36:15.660 D [1149:ScriptThreadProcess] Rails -- Hello World def self.colorized_formatter Proc.new do |log| - colors = SemanticLogger::Appender::AnsiColors - tags = log.tags.collect { |tag| "[#{colors::CYAN}#{tag}#{colors::CLEAR}]" }.join(' ') + ' ' if log.tags && (log.tags.size > 0) + colors = SemanticLogger::Appender::AnsiColors + level_color = colors::LEVEL_MAP[log.level] - message = log.message.to_s.dup + # Header with date, time, log level and process info + entry = "#{log.formatted_time} #{level_color}#{log.level_to_s}#{colors::CLEAR} [#{log.process_info}]" + + # Tags + entry << ' ' << log.tags.collect { |tag| "[#{level_color}#{tag}#{colors::CLEAR}]" }.join(' ') if log.tags && (log.tags.size > 0) + + # Duration + entry << " (#{colors::BOLD}#{log.duration_human}#{colors::CLEAR})" if log.duration + + # Class / app name + entry << " #{level_color}#{log.name}#{colors::CLEAR}" + + # Log message + entry << " -- #{log.message}" if log.message + + # Payload unless log.payload.nil? || (log.payload.respond_to?(:empty?) && log.payload.empty?) payload = log.payload payload = (defined?(AwesomePrint) && payload.respond_to?(:ai)) ? payload.ai(multiline: false) : payload.inspect - message << ' -- ' << payload + entry << ' -- ' << payload end - message << ' -- Exception: ' << "#{colors::BOLD}#{log.exception.class}: #{log.exception.message}#{colors::CLEAR}\n#{(log.exception.backtrace || []).join("\n")}" if log.exception - duration_str = log.duration ? "(#{colors::BOLD}#{'%.1f' % log.duration}ms#{colors::CLEAR}) " : '' - - level_color = - case log.level - when :trace - colors::MAGENTA - when :debug - colors::GREEN - when :info - colors::CYAN - when :warn - colors::BOLD - when :error, :fatal - colors::RED - end - - file_name = - if log.backtrace || log.exception - backtrace = log.backtrace || log.exception.backtrace - location = backtrace[0].split('/').last - file, line = location.split(':') - " #{level_color}#{file}:#{line}#{colors::CLEAR}" - end - - "#{SemanticLogger::Appender::Base.formatted_time(log.time)} #{level_color}#{colors::BOLD}#{log.level.to_s[0..0].upcase}#{colors::CLEAR} [#{$$}:#{'%.30s' % log.thread_name}#{file_name}] #{tags}#{duration_str}#{level_color}#{log.name}#{colors::CLEAR} -- #{message}" + # Exceptions + log.each_exception do |exception, i| + entry << (i == 0 ? ' -- Exception: ' : "\nCause: ") + entry << "#{colors::BOLD}#{exception.class}: #{exception.message}#{colors::CLEAR}\n#{(exception.backtrace || []).join("\n")}" + end + entry end end def flush # An appender can implement a flush method if it supports it. @@ -137,20 +152,21 @@ # set for this instance def level_index @level_index || 0 end - # For JRuby include the Thread name rather than its id if defined? Java # Return the Time as a formatted string # JRuby only supports time in ms def self.formatted_time(time) + warn '[deprecated] SemanticLogger::Base.formatted_time is deprecated please use log.formatted_time' "#{time.strftime('%Y-%m-%d %H:%M:%S')}.#{'%03d' % (time.usec/1000)}" end else # Return the Time as a formatted string # Ruby MRI supports micro seconds def self.formatted_time(time) + warn '[deprecated] SemanticLogger::Base.formatted_time is deprecated please use log.formatted_time' "#{time.strftime('%Y-%m-%d %H:%M:%S')}.#{'%06d' % (time.usec)}" end end end