You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.9 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
10 months ago
11 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
10 months ago
  1. require_relative 'wrapper'
  2. require_relative 'base'
  3. require 'io/console'
  4. require 'amazing_print'
  5. # Opinioned Rails custom formatter
  6. class BasicFormatter < SemanticLogger::Formatters::Color
  7. NAME_MAX_SIZE = 25
  8. TERMINAL_PREFIX = ENV['TERMINAL_PREFIX'].to_i || 0
  9. CONTENT_PREFIX = ' '.freeze
  10. WRAP_PREFIX = ' > '.freeze
  11. ANSI_DEBUG = "\e[90m".freeze
  12. ANSI_INFO = SemanticLogger::AnsiColors::GREEN
  13. ANSI_WARN = SemanticLogger::AnsiColors::YELLOW
  14. ANSI_ERROR = "\e[91m".freeze
  15. ANSI_NEUTRAL_INFO = SemanticLogger::AnsiColors::WHITE
  16. ANSI_REVERSED_WARNING = "\e[0;30;43m".freeze
  17. ANSI_REVERSED_ERROR = "\e[1;30;41m".freeze
  18. ANSI_REVERSED_FATAL = "\e[1;30;41m".freeze
  19. CONTENT_COLOR_MAP = ColorMap.new(
  20. debug: ANSI_DEBUG,
  21. info: ANSI_NEUTRAL_INFO,
  22. warn: ANSI_REVERSED_WARNING,
  23. error: ANSI_REVERSED_ERROR,
  24. fatal: ANSI_REVERSED_FATAL
  25. )
  26. EXCLUDE_LAMBDA = lambda { |log|
  27. if log.name == 'ActionView::Base'
  28. !log.message.starts_with?(' Rendering')
  29. elsif log.name == 'Rails' && !log.message.nil?
  30. log.message.exclude?('Started GET "/rails/live/reload')
  31. else
  32. true
  33. end
  34. }
  35. def initialize
  36. super(color_map: ColorMap.new(
  37. debug: ANSI_DEBUG,
  38. info: ANSI_INFO,
  39. warn: ANSI_WARN,
  40. error: ANSI_ERROR,
  41. fatal: ANSI_ERROR
  42. ))
  43. end
  44. def message
  45. return unless log.message
  46. message = log.message
  47. if log.name == 'Rails' && message.starts_with?('Completed')
  48. message.rstrip!
  49. message += "\n" unless message.starts_with?('Completed 5')
  50. end
  51. wrap_length = compute_useful_length
  52. space_prefix = message.match(/^\s*/)
  53. message = Wrapper.wrap("#{CONTENT_COLOR_MAP[log.level]}#{message}", before_message(true, space_prefix),
  54. wrap_length - space_prefix.length)
  55. "#{CONTENT_COLOR_MAP[log.level]}#{message}#{color_map.clear}"
  56. end
  57. def payload
  58. return unless log.payload
  59. lines = log.payload.ai(ruby19_syntax: true, indent: 2).split("\n")
  60. first_line = lines.shift
  61. lines = lines.map do |l|
  62. space_prefix = l.match(/^\s*/)
  63. "#{before_message(true, space_prefix)}#{l}"
  64. end
  65. lines.unshift(first_line).join("\n")
  66. end
  67. def level
  68. level = log.level == :info ? ' ' : log.level.to_s.chr.upcase
  69. "#{color}#{level}#{color_map.clear}"
  70. end
  71. def name
  72. "#{ANSI_DEBUG}#{log.name.truncate(NAME_MAX_SIZE).center(NAME_MAX_SIZE)}#{color_map.clear}"
  73. end
  74. def exception # rubocop:disable Metrics/AbcSize
  75. return unless log.exception
  76. root_path = Rails.root.to_s
  77. stack = log.exception.backtrace.select { |line| line.starts_with?(root_path) }
  78. stack = stack.map { |line| line.delete_prefix("#{root_path}/") }
  79. "#{ANSI_REVERSED_WARNING}#{log.exception.class}#{color_map.clear} #{ANSI_REVERSED_ERROR}#{log.exception.message}#{color_map.clear}#{backtrace(stack)}" # rubocop:disable Layout/LineLength
  80. end
  81. def call(log, logger)
  82. unless log.message.is_a?(String)
  83. log.payload = log.message
  84. log.message = nil
  85. end
  86. self.color = color_map[log.level]
  87. self.log = log
  88. self.logger = logger
  89. self.log.payload =
  90. [before_message, message, payload, exception].compact.join(' ')
  91. end
  92. private
  93. def compute_useful_length
  94. wrap_length = IO.console.winsize[1] - TERMINAL_PREFIX - before_message.length + CONTENT_PREFIX.length + 12
  95. rescue StandardError
  96. wrap_length = 100
  97. end
  98. def before_message(wrapped = false, prefix = '')
  99. result = [name, level, tags, named_tags, duration, CONTENT_PREFIX].compact.join(' ')
  100. if wrapped
  101. [name, level, tags, named_tags, duration,
  102. "#{color}#{WRAP_PREFIX}#{color_map.clear}#{prefix}"].compact.join(' ')
  103. else
  104. [name, level, tags, named_tags, duration,
  105. CONTENT_PREFIX].compact.join(' ')
  106. end
  107. end
  108. def backtrace(stack)
  109. nil unless stack.count.positive?
  110. "\n#{before_message} #{ANSI_ERROR}#{stack.join("\n#{before_message} #{ANSI_ERROR}")}#{color_map.clear}"
  111. end
  112. def color_content
  113. color
  114. end
  115. end