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.

94 lines
2.4 KiB

4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. require_relative 'ansi_wrapper'
  2. require_relative 'ansi_colors'
  3. require 'io/console'
  4. require 'amazing_print'
  5. require 'json'
  6. # wraps meanwhile takes care of ansi colors
  7. class AnsiFormatter < SemanticLogger::Formatters::Color
  8. include AnsiColors
  9. ANSI_DEBUG = CLEAR + TEXT_GRAY_400
  10. ANSI_INFO = CLEAR + TEXT_GRAY_100
  11. ANSI_WARN = CLEAR + BG_YELLOW + TEXT_BLACK
  12. ANSI_ERROR = CLEAR + BG_RED + TEXT_WHITE
  13. ANSI_FATAL = CLEAR + BG_MAGENTA + BOLD + TEXT_WHITE
  14. NAME_MAX_SIZE = 20
  15. FOREMAN_PREFIX_LENGTH = 18
  16. DEFAULT_UNDETECTED_WRAP = 80
  17. def initialize
  18. super(color_map: ColorMap.new(
  19. debug: ANSI_DEBUG,
  20. info: ANSI_INFO,
  21. warn: ANSI_WARN,
  22. error: ANSI_ERROR,
  23. fatal: ANSI_FATAL
  24. ))
  25. end
  26. def call(log, logger)
  27. self.log = log
  28. self.logger = logger
  29. self.color = color_map[log.level]
  30. wrap_length = compute_useful_length
  31. wrap_level(wrap_length, message, payload, exception)
  32. end
  33. def origin
  34. origin = log.name.truncate(NAME_MAX_SIZE).center(NAME_MAX_SIZE)
  35. colorize(origin, AnsiColors::TEXT_CYAN)
  36. end
  37. def message
  38. return unless log.message
  39. colorize(log.message)
  40. end
  41. def exception
  42. return unless log.exception
  43. clazz = "#{log.exception.class}\n"
  44. message = log.exception.message.chomp('')
  45. backtrace = clean_backtrace(log.exception.backtrace)
  46. "#{colorize(clazz, ANSI_FATAL)}#{colorize(message, ANSI_ERROR)}#{backtrace}"
  47. end
  48. private
  49. def colorize(text, tint = color) = "#{tint}#{text}#{AnsiColors::CLEAR}"
  50. def build_prefix = "#{origin} #{colorize(draw_rails(level_char))} "
  51. def build_continuation = "#{origin} #{colorize(draw_rails('┆'))} "
  52. def draw_rails(char) = "#{char}"
  53. def compute_useful_length
  54. IO.console.winsize[1] - FOREMAN_PREFIX_LENGTH
  55. rescue StandardError
  56. DEFAULT_UNDETECTED_WRAP
  57. end
  58. def clean_backtrace(backtrace)
  59. root_path = Rails.root.to_s
  60. backtrace = backtrace.select { |line| line.starts_with?(root_path) }
  61. backtrace = backtrace.map { |line| line.delete_prefix("#{root_path}/") }
  62. backtrace.compact.join("\n")
  63. end
  64. def level_char
  65. case log.level
  66. when :info, :debug then ' '
  67. else log.level.to_s.chr.upcase
  68. end
  69. end
  70. def wrap_level(length, *items)
  71. prefix = build_prefix
  72. continuation = build_continuation
  73. items.map do |item|
  74. AnsiWrapper.wrap(item, length, prefix, continuation)
  75. end.compact.join("\n")
  76. end
  77. end