diff --git a/Gemfile b/Gemfile index dd523f8..8b72ea0 100644 --- a/Gemfile +++ b/Gemfile @@ -70,6 +70,7 @@ group :development do gem 'rubocop-thread_safety' gem 'ruby-lsp-rails' + gem 'amazing_print' gem 'rails_semantic_logger' end diff --git a/Gemfile.lock b/Gemfile.lock index bc5fc7d..b3afea1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,6 +77,7 @@ GEM tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) + amazing_print (1.5.0) ast (2.4.2) base64 (0.2.0) bigdecimal (3.1.5) @@ -319,6 +320,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + amazing_print bootsnap capybara debug diff --git a/app/controllers/scores_controller.rb b/app/controllers/scores_controller.rb index 441f8a2..4516eb0 100644 --- a/app/controllers/scores_controller.rb +++ b/app/controllers/scores_controller.rb @@ -6,12 +6,12 @@ class ScoresController < ApplicationController def index @scores = Score.all logger.info 'this is an information', { 'one': 1, 'two': 2 } - logger.warn 'this is a warning' - logger.error 'this is an error' - logger.debug 'this is a debug message' - logger.fatal 'FATAL' - logger.info @scores.inspect - logger.info File.basename($0) + logger.info 'this is an object', BigDecimal('0.0001') + # logger.warn 'this is a warning' + # logger.error 'this is an error' + # logger.debug 'this is a debug message' + # logger.fatal 'FATAL' + logger.debug 'score are', @scores end # GET /scores/1 diff --git a/lib/formatters/base.rb b/lib/formatters/base.rb new file mode 100644 index 0000000..8e31a86 --- /dev/null +++ b/lib/formatters/base.rb @@ -0,0 +1,44 @@ +module SemanticLogger + class Base + # Log message at the specified level + def log_internal(level, index, message = nil, payload = nil, exception = nil) + # Handle variable number of arguments by detecting exception object and payload hash. + 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 + # elsif payload && !payload.is_a?(Hash) + # message = message.nil? ? payload : "#{message} -- #{payload}" + # payload = nil + end + + log = Log.new(name, level, index) + should_log = + if exception.nil? && payload.nil? && message.is_a?(Hash) + # All arguments as a hash in the message. + log.assign(**log.extract_arguments(message)) + elsif exception.nil? && message && payload && payload.is_a?(Hash) + # Message supplied along with a hash with the remaining arguments. + log.assign(**log.extract_arguments(payload, message)) + else + # All fields supplied directly. + log.assign(message:, payload:, exception:) + end + + # Add result of block to message or payload if not nil + if block_given? + result = yield(log) + if result.is_a?(String) + log.message = log.message.nil? ? result : "#{log.message} -- #{result}" + elsif result.is_a?(Hash) + log.assign_hash(result) + end + end + + # Log level may change during assign due to :on_exception_level + self.log(log) if should_log && should_log?(log) + end + end +end diff --git a/lib/formatters/basic_formatter.rb b/lib/formatters/basic_formatter.rb index 7662b82..b1c3c51 100644 --- a/lib/formatters/basic_formatter.rb +++ b/lib/formatters/basic_formatter.rb @@ -1,5 +1,7 @@ require_relative 'wrapper' +require_relative 'base' require 'io/console' +require 'amazing_print' # Opinioned Rails custom formatter class BasicFormatter < SemanticLogger::Formatters::Color @@ -54,12 +56,7 @@ class BasicFormatter < SemanticLogger::Formatters::Color message += "\n" unless message.starts_with?('Completed 5') end - begin - wrap_length = IO.console.winsize[1] - TERMINAL_PREFIX - before_message.length + CONTENT_PREFIX.length + 12 - rescue StandardError - wrap_length = 100 - end - + wrap_length = compute_useful_length space_prefix = message.match(/^\s*/) message = Wrapper.wrap("#{CONTENT_COLOR_MAP[log.level]}#{message}", before_message(true, space_prefix), wrap_length - space_prefix.length) @@ -67,6 +64,18 @@ class BasicFormatter < SemanticLogger::Formatters::Color "#{CONTENT_COLOR_MAP[log.level]}#{message}#{color_map.clear}" end + def payload + return unless log.payload + + lines = log.payload.ai(ruby19_syntax: true, indent: 2).split("\n") + first_line = lines.shift + lines = lines.map do |l| + space_prefix = l.match(/^\s*/) + "#{before_message(true, space_prefix)}#{l}" + end + lines.unshift(first_line).join("\n") + end + def level level = log.level == :info ? ' ' : log.level.to_s.chr.upcase "#{color}╣#{level}╠#{color_map.clear}" @@ -87,14 +96,27 @@ class BasicFormatter < SemanticLogger::Formatters::Color end def call(log, logger) + unless log.message.is_a?(String) + log.payload = log.message + log.message = nil + end + self.color = color_map[log.level] self.log = log self.logger = logger - [before_message, message, payload, exception].compact.join(' ') + + self.log.payload = + [before_message, message, payload, exception].compact.join(' ') end private + def compute_useful_length + wrap_length = IO.console.winsize[1] - TERMINAL_PREFIX - before_message.length + CONTENT_PREFIX.length + 12 + rescue StandardError + wrap_length = 100 + end + def before_message(wrapped = false, prefix = '') result = [name, level, tags, named_tags, duration, CONTENT_PREFIX].compact.join(' ') if wrapped