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.

92 lines
3.1 KiB

3 months ago
3 months ago
2 months ago
3 months ago
3 months ago
2 months ago
3 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
2 months ago
2 months ago
2 months ago
2 months ago
3 months ago
2 months ago
3 months ago
3 months ago
2 months ago
3 months ago
3 months ago
3 months ago
  1. module Semantic
  2. # use the Zeitwerk autoloader to reattach_appender for development autoreloading feature
  3. class DevLoader
  4. def initialize(session_key)
  5. @session_key = session_key
  6. force_preload_module
  7. RailsSemanticLogger::ActionController::LogSubscriber.logger.level = :fatal # useful for remanent Rack::Log started
  8. once_and_reload do
  9. clear_subscribers(/\.action_controller$/)
  10. clear_subscribers(/\.action_view$/)
  11. append_ansi_formatter
  12. reset_subscribers
  13. register_log_subscriber
  14. end
  15. end
  16. private
  17. def once_and_reload(&)
  18. yield
  19. Rails.autoloaders.main.on_load('ApplicationController', &)
  20. end
  21. def force_preload_module
  22. self.class.module_parent.constants.each { |const| self.class.module_parent.const_get(const) }
  23. end
  24. def append_ansi_formatter
  25. SemanticLogger.clear_appenders!
  26. formatter = Semantic::AnsiFormatter.new
  27. SemanticLogger.add_appender(io: $stdout,
  28. formatter:,
  29. filter: ->(log) { !formatter.reject(log) })
  30. end
  31. def register_log_subscriber
  32. register_to_action_controller(:start_processing)
  33. register_to_action_controller(:process_action, :finish_processing)
  34. register_to_action_controller(:redirect_to)
  35. %i[send_file send_data halted_callback unpermitted_parameters send_stream write_fragment
  36. read_fragment expire_fragment exist_fragment?].each do |hook|
  37. register_to_action_controller(hook, :any_hook)
  38. end
  39. end
  40. def register_to_action_controller(hook, method = hook)
  41. @subscribers << ActiveSupport::Notifications.subscribe("#{hook}.action_controller") do |event|
  42. @log_subscriber.send(method, event)
  43. end
  44. end
  45. def subscriber_patterns(subscriber)
  46. subscriber.patterns.respond_to?(:keys) ? subscriber.patterns.keys : subscriber.patterns
  47. end
  48. def unattach(subscriber, pattern)
  49. subscriber_patterns(subscriber).each do |sub_pattern|
  50. ActiveSupport::Notifications.notifier.listeners_for(sub_pattern).each do |sub|
  51. next unless sub.instance_variable_get(:@delegate) == subscriber
  52. next unless pattern.match(sub_pattern)
  53. puts "FOUND subscriber=#{subscriber} for sub_pattern=#{sub_pattern} with logger #{subscriber.logger.name}"
  54. puts subscriber.class.module_parent.const_source_location(subscriber.class.to_s)&.first
  55. ActiveSupport::Notifications.unsubscribe(sub)
  56. end
  57. end
  58. ActiveSupport::LogSubscriber.subscribers.delete(subscriber)
  59. end
  60. # pattern could be either a string 'start_processing.action_controller' or a regex /\.action_controller$/
  61. def clear_subscribers(pattern)
  62. ActiveSupport::LogSubscriber.subscribers.each { |sub| unattach(sub, pattern) }
  63. end
  64. def reset_subscribers
  65. if defined?(@subscribers)
  66. @subscribers.each do |sub|
  67. ActiveSupport::Notifications.unsubscribe(sub)
  68. end
  69. @subscribers.clear
  70. else
  71. @subscribers = []
  72. end
  73. @log_subscriber = Semantic::LogSubscriber.new(@session_key)
  74. end
  75. end
  76. end