diff --git a/Gemfile b/Gemfile index 07770ad..dd523f8 100644 --- a/Gemfile +++ b/Gemfile @@ -69,6 +69,8 @@ group :development do gem 'rubocop-shopify' gem 'rubocop-thread_safety' gem 'ruby-lsp-rails' + + gem 'rails_semantic_logger' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index c4d464f..bc5fc7d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -195,6 +195,10 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) + rails_semantic_logger (4.14.0) + rack + railties (>= 5.1) + semantic_logger (~> 4.13) railties (7.1.2) actionpack (= 7.1.2) activesupport (= 7.1.2) @@ -258,6 +262,8 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + semantic_logger (4.15.0) + concurrent-ruby (~> 1.0) sorbet-runtime (0.5.11175) sprockets (4.2.1) concurrent-ruby (~> 1.0) @@ -321,6 +327,7 @@ DEPENDENCIES pg (~> 1.1) puma (>= 5.0) rails (~> 7.1.2) + rails_semantic_logger rainbow rubocop rubocop-packaging diff --git a/app/controllers/scores_controller.rb b/app/controllers/scores_controller.rb index d7d4f40..f5d58b7 100644 --- a/app/controllers/scores_controller.rb +++ b/app/controllers/scores_controller.rb @@ -48,6 +48,7 @@ class ScoresController < ApplicationController # DELETE /scores/1 def destroy + raise 'Unable to destroy this score' @score.destroy! redirect_to scores_url, notice: 'Score was successfully destroyed.', status: :see_other end diff --git a/config/environments/development.rb b/config/environments/development.rb index a2997a3..9de2b06 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,5 +1,4 @@ require 'active_support/core_ext/integer/time' -require_relative '../../lib/formatter/colored_formatter' Rails.application.configure do # rubocop:disable Metrics/BlockLength # Settings specified here will take precedence over those in config/application.rb. @@ -75,8 +74,12 @@ Rails.application.configure do # rubocop:disable Metrics/BlockLength # Raise error when a before_action's only/except options reference missing actions config.action_controller.raise_on_missing_callback_actions = true - # Colorful Simple Logger Formatter - config.log_formatter = ColoredFormatter.new + # Customized Semantic Logger + config.rails_semantic_logger.semantic = false + config.rails_semantic_logger.started = true + config.rails_semantic_logger.processing = true + config.rails_semantic_logger.rendered = true + config.rails_semantic_logger.add_file_appender = false + require Rails.root.join('lib', 'formatters', 'basic_formatter') + config.semantic_logger.add_appender(io: $stdout, formatter: BasicFormatter.new) end - -Rainbow.enabled = true diff --git a/lib/formatter/colored_formatter.rb b/lib/formatter/colored_formatter.rb deleted file mode 100644 index 9c3c23c..0000000 --- a/lib/formatter/colored_formatter.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'rainbow' - -# ColoredFormatter outputs colored message according to severity -class ColoredFormatter < Logger::Formatter - def call(severity, _time, _program_name, message) # rubocop:disable Metrics/MethodLength - # msg = message.is_a?(String) ? message : message.inspect - msg = message - tint = case severity - when 'DEBUG' - :darkgray - when 'INFO' - :white - when 'WARN' - # :orange - '#FFC482' - when 'ERROR' - :red - when 'FATAL' - :magenta - else - raise "unknown severity #{severity}" - end - "#{Rainbow('╞' + severity.ljust(5) + '╡').bg(:cyan).color(:darkgray)}╠ #{Rainbow(msg).color(tint)}\n" - end -end diff --git a/lib/formatters/basic_formatter.rb b/lib/formatters/basic_formatter.rb new file mode 100644 index 0000000..f4de5b5 --- /dev/null +++ b/lib/formatters/basic_formatter.rb @@ -0,0 +1,60 @@ +# My Custom colorized formatter +class BasicFormatter < SemanticLogger::Formatters::Color + ANSI_REVERSED_WARNING = "\e[0;30;43m".freeze + ANSI_REVERSED_ERROR = "\e[1;30;41m".freeze + ANSI_GRAY = "\e[90m".freeze + + def initialize + super(time_format: nil, + color_map: ColorMap.new( + debug: ANSI_GRAY, + info: SemanticLogger::AnsiColors::GREEN, + warn: SemanticLogger::AnsiColors::YELLOW + )) + end + + def message + return unless log.message + + prefix = "#{color}--#{color_map.clear}" + + case log.level + when :info + "#{prefix} #{SemanticLogger::AnsiColors::WHITE}#{log.message}#{color_map.clear}" + when :warn + "#{prefix} #{ANSI_REVERSED_WARNING}#{log.message}#{color_map.clear}" + when :error, :fatal + "#{prefix} #{ANSI_REVERSED_ERROR}#{log.message}#{color_map.clear}" + else + "#{prefix} #{color}#{log.message}#{color_map.clear}" + end + end + + def process_info + fname = file_name_and_line + "#{color}[#{fname}]#{color_map.clear}" if fname + end + + def exception + return unless log.exception + + root_path = Rails.root.to_s + backtrace = log.exception.backtrace.select do |line| + line.starts_with?(root_path) + end + + if backtrace.count.positive? + "-- #{ANSI_REVERSED_ERROR}#{log.exception.class}#{color_map.clear} #{color}#{log.exception.message}#{color_map.clear}#{SemanticLogger::AnsiColors::WHITE}\n\t#{backtrace.join("\n\t")}#{color_map.clear}\n\n" + else + "-- #{ANSI_REVERSED_ERROR}#{log.exception.class}: #{log.exception.message}#{color_map.clear}\n\n" + end + end + + def call(log, logger) + self.color = color_map[log.level] + self.log = log + self.logger = logger + + [level, tags, named_tags, duration, name, message, payload, exception].compact.join(' ') + end +end