From ba32dfe6a90cf5f94e998720f23afe09c0391f86 Mon Sep 17 00:00:00 2001 From: pvincent Date: Mon, 9 Sep 2024 15:31:54 +0400 Subject: [PATCH] redirect_to hook --- config/environments/development.rb | 2 +- lib/semantic/dev_loader.rb | 45 ++++++++++++++++++++---------- lib/semantic/log_subscriber.rb | 33 +++++++++++++++++++++- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 513ecae..f89e870 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -88,7 +88,7 @@ Rails.application.configure do # rubocop:disable Metrics/BlockLength end elsif Rails.application.server? config.after_initialize do - Semantic::DevLoader.new + Semantic::DevLoader.new('toto1') end end end diff --git a/lib/semantic/dev_loader.rb b/lib/semantic/dev_loader.rb index d8eb391..51ec0c7 100644 --- a/lib/semantic/dev_loader.rb +++ b/lib/semantic/dev_loader.rb @@ -1,14 +1,14 @@ module Semantic # use the Zeitwerk autoloader to reattach_appender for development autoreloading feature class DevLoader - def initialize - @subscribers = [] + def initialize(session_key) + @session_key = session_key + force_preload_module - Rails.autoloaders.main.on_load('ApplicationController') do + once_and_reload do append_ansi_formatter register_log_subscriber end - append_ansi_formatter # FIXME: when final # Rails.logger.level = :error @@ -16,10 +16,13 @@ module Semantic private + def once_and_reload(&) + yield + Rails.autoloaders.main.on_load('ApplicationController', &) + end + def force_preload_module - self.class.module_parent.constants.each do |const| - self.class.module_parent.const_get(const) - end + self.class.module_parent.constants.each { |const| self.class.module_parent.const_get(const) } end def append_ansi_formatter @@ -31,16 +34,30 @@ module Semantic end def register_log_subscriber - @subscribers.each { |sub| ActiveSupport::Notifications.unsubscribe(sub) } - @subscribers.clear + reset_subscribers + register_to_action_controller(:start_processing) + register_to_action_controller(:process_action, :finish_processing) + register_to_action_controller(: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_to_action_controller(hook, :any_hook) + end + end - log_subscriber = Semantic::LogSubscriber.new('toto1') - @subscribers << ActiveSupport::Notifications.subscribe('start_processing.action_controller') do |event| - log_subscriber.start_processing(event) + def register_to_action_controller(hook, method = hook) + @subscribers << ActiveSupport::Notifications.subscribe("#{hook}.action_controller") do |event| + @log_subscriber.send(method, event) end - @subscribers << ActiveSupport::Notifications.subscribe('process_action.action_controller') do |event| - log_subscriber.finish_processing(event) + end + + def reset_subscribers + if defined?(@subscribers) + @subscribers.each { |sub| ActiveSupport::Notifications.unsubscribe(sub) } + @subscribers.clear + else + @subscribers = [] end + @log_subscriber = Semantic::LogSubscriber.new(@session_key) end end end diff --git a/lib/semantic/log_subscriber.rb b/lib/semantic/log_subscriber.rb index cf3b3c4..d0e45d4 100644 --- a/lib/semantic/log_subscriber.rb +++ b/lib/semantic/log_subscriber.rb @@ -5,6 +5,7 @@ module Semantic # def logger = SemanticLogger['Rails'] INTERNAL_PARAMS = %i[controller action format _method only_path].freeze + DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze def initialize(session_key) @session_key = session_key @@ -38,7 +39,7 @@ module Semantic end def finish_processing(event) - session_value = @transactions.delete(event.transaction_id) # get previous session_value from start_processing + session_value = @transactions.delete(event.transaction_id) # delete previous session_value from start_processing SemanticLogger.tagged(session_value) do payload = event.payload additions = ActionController::Base.log_process_action(payload) @@ -63,8 +64,38 @@ module Semantic end end + def redirect_to(event) + SemanticLogger.tagged(@transactions[event.transaction_id]) do + location = capture_path(event.payload[:location]) + logger.debug("Redirected to #{colorize(location, BOLD)}") + end + end + + def any_hook(event) + SemanticLogger.tagged(@transactions[event.transaction_id]) do + logger.warn("action_controller hook=<#{event.name.split('.')[0]}> needs a proper message handling!", + event.payload.keys) + end + end + private + def redirect_regex + return @redirect_regex if defined?(@redirect_regex) + + options = Rails.application.routes.default_url_options + dev_hosts = DEFAULT_DEV_HOSTS + Array.wrap(options[:host]) + dev_hosts_or = dev_hosts.uniq.join('|') + dev_from = "http://(?:#{dev_hosts_or}):#{options[:port]}(.*)" + + @redirect_regex = /^#{dev_from}/ + end + + def capture_path(url) + m = redirect_regex.match(url) + m.nil? ? url : m[1] + end + def session_value(event) = event.payload[:headers]['rack.session'].fetch(@session_key, nil) def process_duration(event, additions) = "Processed in #{event.duration.round}ms (#{additions.join(' | ')})" end