module Semantic # use the Zeitwerk autoloader to reattach_appender for development autoreloading feature class DevLoader def initialize(session_key) @session_key = session_key RailsSemanticLogger::ActionController::LogSubscriber.logger.level = :fatal # useful for remanent Rack::Log started once_and_reload do Semantic::NotificationUtil.clear_subscribers(/\.action_controller$/) Semantic::NotificationUtil.clear_subscribers(/\.action_view$/) append_ansi_formatter reset_subscribers register_action_controller end end private def once_and_reload(&) yield Rails.autoloaders.main.on_load('ApplicationController', &) end def append_ansi_formatter SemanticLogger.clear_appenders! formatter = Semantic::AnsiFormatter.new SemanticLogger.add_appender(io: $stdout, formatter:, filter: ->(log) { !formatter.reject(log) }) end def register_action_controller @log_subscriber = Semantic::Subscribers::ActionController.new(@session_key) register_action_controller_hook(:start_processing) register_action_controller_hook(:process_action, :finish_processing) register_action_controller_hook(:redirect_to) %i[send_file send_data halted_callback unpermitted_parameters send_stream write_fragment read_fragment expire_fragment exist_fragment?].each do |hook| register_action_controller_hook(hook, :any_hook) end end def register_action_controller_hook(hook, method = hook) @subscribers << ActiveSupport::Notifications.subscribe("#{hook}.action_controller") do |event| @log_subscriber.send(method, event) end end def reset_subscribers if defined?(@subscribers) @subscribers.each { |sub| ActiveSupport::Notifications.unsubscribe(sub) } @subscribers.clear else @subscribers = [] end end end end