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.
 
 
 
 
 

101 lines
3.5 KiB

module Semantic
# use the Zeitwerk autoloader to reattach_appender for development autoreloading feature
class DevLoader
def initialize(session_key)
@session_key = session_key
force_preload_module
once_and_reload do
append_ansi_formatter
register_log_subscriber
end
# FIXME: proper unsubscribe!!!
# RailsSemanticLogger::ActionController::LogSubscriber.logger.level = :fatal
#
# RailsSemanticLogger.swap_subscriber(
# RailsSemanticLogger::ActionController::LogSubscriber,
# @log_subscriber, # attach missing!!!
# :action_controller
# )
# ActiveSupport::LogSubscriber.subscribers.each do |sub|
# puts "subscriber #{sub.pattern}"
# end
# RailsSemanticLogger.swap_subscriber(RailsSemanticLogger::ActionController::LogSubscriber,
# @log_subscriber, :action_controller)
end
private
def once_and_reload(&)
yield
Rails.autoloaders.main.on_load('ApplicationController', &)
end
def force_preload_module
self.class.module_parent.constants.each { |const| self.class.module_parent.const_get(const) }
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_log_subscriber
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
def register_to_action_controller(hook, method = hook)
@subscribers << ActiveSupport::Notifications.subscribe("#{hook}.action_controller") do |event|
@log_subscriber.send(method, event)
end
end
def subscriber_patterns(subscriber)
subscriber.patterns.respond_to?(:keys) ? subscriber.patterns.keys : subscriber.patterns
end
def unattach(subscriber, pattern)
subscriber_patterns(subscriber).each do |sub_pattern|
ActiveSupport::Notifications.notifier.listeners_for(sub_pattern).each do |sub|
next unless sub.instance_variable_get(:@delegate) == subscriber
next unless pattern.match(sub_pattern)
# puts "FOUND subscriber=#{subscriber} for sub_pattern=#{sub_pattern} with logger #{subscriber.logger.name}"
# puts 'remove notification then log_subscriber'
ActiveSupport::Notifications.unsubscribe(sub)
ActiveSupport::LogSubscriber.subscribers.delete(subscriber)
end
end
end
# pattern could be either a string 'start_processing.action_controller' or a regex /\.action_controller$/
def clear_subscribers(pattern)
ActiveSupport::LogSubscriber.subscribers.each { |sub| unattach(sub, pattern) }
end
def reset_subscribers
clear_subscribers(/\.action_controller$/)
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