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.

102 lines
3.7 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. module Semantic
  2. class LogSubscriber < ActiveSupport::LogSubscriber
  3. include SemanticLogger::Loggable
  4. include AnsiColors
  5. # def logger = SemanticLogger['Rails']
  6. INTERNAL_PARAMS = %i[controller action format _method only_path].freeze
  7. DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze
  8. def initialize(session_key)
  9. @session_key = session_key
  10. @transactions = {}
  11. super()
  12. end
  13. def start_processing(event)
  14. session_value = session_value(event)
  15. @transactions[event.transaction_id] = session_value # preserve session_value to help finish_processing
  16. SemanticLogger.tagged(session_value) do
  17. request = event.payload[:request]
  18. path = colorize(request.filtered_path, BOLD)
  19. logger.info("Started #{request.raw_request_method} #{path}")
  20. format = event.payload[:format]
  21. format = format.to_s.upcase if format.is_a?(Symbol)
  22. format = '*/*' if format.nil?
  23. format = colorize(format, BOLD)
  24. logger.debug("Processing by #{event.payload[:controller]}##{event.payload[:action]} as #{format}")
  25. params = event.payload[:params].deep_symbolize_keys.except(*INTERNAL_PARAMS)
  26. unless params.empty?
  27. params = params.ai(ruby19_syntax: true, plain: true, multiline: false)
  28. params.gsub!(/(\w+):/, "#{TEXT_CYAN}\\1#{CLEAR}:")
  29. params.gsub!(/"(.*?)"/, "\"#{TEXT_YELLOW}\\1#{CLEAR}\"")
  30. end
  31. logger.debug("Parameters: #{params}") unless params.empty?
  32. end
  33. end
  34. def finish_processing(event)
  35. session_value = @transactions.delete(event.transaction_id) # delete previous session_value from start_processing
  36. SemanticLogger.tagged(session_value) do
  37. payload = event.payload
  38. additions = ActionController::Base.log_process_action(payload)
  39. status = payload[:status]
  40. if status.nil? && (exception_class_name = payload[:exception]&.first)
  41. status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
  42. end
  43. additions << "GC: #{event.gc_time.round(1)}ms"
  44. if event.duration >= 1200
  45. logger.error process_duration(event, additions)
  46. elsif event.duration >= 600
  47. logger.warn process_duration(event, additions)
  48. elsif event.duration >= 250
  49. logger.info process_duration(event, additions)
  50. elsif event.duration >= 80
  51. logger.debug process_duration(event, additions)
  52. end
  53. logger.info("Completed #{colorize(status, BOLD)} #{Rack::Utils::HTTP_STATUS_CODES[status]}")
  54. end
  55. end
  56. def redirect_to(event)
  57. SemanticLogger.tagged(@transactions[event.transaction_id]) do
  58. location = capture_path(event.payload[:location])
  59. logger.debug("Redirected to #{colorize(location, BOLD)}")
  60. end
  61. end
  62. def any_hook(event)
  63. SemanticLogger.tagged(@transactions[event.transaction_id]) do
  64. logger.warn("action_controller hook=<#{event.name.split('.')[0]}> needs a proper message handling!",
  65. event.payload.keys)
  66. end
  67. end
  68. private
  69. def redirect_regex
  70. return @redirect_regex if defined?(@redirect_regex)
  71. options = Rails.application.routes.default_url_options
  72. dev_hosts = DEFAULT_DEV_HOSTS + Array.wrap(options[:host])
  73. dev_hosts_or = dev_hosts.uniq.join('|')
  74. dev_from = "http://(?:#{dev_hosts_or}):#{options[:port]}(.*)"
  75. @redirect_regex = /^#{dev_from}/
  76. end
  77. def capture_path(url)
  78. m = redirect_regex.match(url)
  79. m.nil? ? url : m[1]
  80. end
  81. def session_value(event) = event.payload[:headers]['rack.session'].fetch(@session_key, nil)
  82. def process_duration(event, additions) = "Processed in #{event.duration.round}ms (#{additions.join(' | ')})"
  83. end
  84. end