4 changed files with 159 additions and 141 deletions
			
			
		- 
					27lib/semantic/dev_loader.rb
- 
					124lib/semantic/log_subscriber.rb
- 
					130lib/semantic/subscribers/action_controller.rb
- 
					19lib/semantic/subscribers/action_view.rb
| @ -1,124 +0,0 @@ | |||
| module Semantic | |||
|   class LogSubscriber < ActiveSupport::LogSubscriber | |||
|     include SemanticLogger::Loggable | |||
|     include AnsiColors | |||
|     def logger = SemanticLogger['Rails'] | |||
| 
 | |||
|     INTERNAL_PARAMS = %i[controller action format _method only_path].freeze | |||
|     DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze | |||
|     TERMINUS_STRING = '╙─╜'.freeze | |||
| 
 | |||
|     def initialize(session_key) | |||
|       @session_key = session_key | |||
|       @transactions = {} | |||
|       super() | |||
|     end | |||
| 
 | |||
|     def start_processing(event) | |||
|       session_value = session_value(event) | |||
|       @transactions[event.transaction_id] = session_value # preserve session_value to help finish_processing | |||
| 
 | |||
|       SemanticLogger.tagged(session_value) do | |||
|         request = event.payload[:request] | |||
|         path = colorize(request.filtered_path, BOLD) | |||
| 
 | |||
|         dimensions = Semantic::AnsiDimensions.new(rails: '╓─╖', before: 1) | |||
|         if defined?(@previously_redirect) && @previously_redirect | |||
|           dimensions = Semantic::AnsiDimensions.new(rails: '╓║╖', before: 0) | |||
|           @previously_redirect = false | |||
|         end | |||
|         logger.info("Started #{request.raw_request_method} #{path}", dimensions:) | |||
| 
 | |||
|         format = event.payload[:format] | |||
|         format = format.to_s.upcase if format.is_a?(Symbol) | |||
|         format = '*/*' if format.nil? | |||
|         format = colorize(format, BOLD) | |||
|         logger.debug("Processing by #{event.payload[:controller]}##{event.payload[:action]} as #{format}") | |||
| 
 | |||
|         params = event.payload[:params].deep_symbolize_keys.except(*INTERNAL_PARAMS) | |||
|         unless params.empty? | |||
|           params = params.ai(ruby19_syntax: true, plain: true, multiline: false) | |||
|           params.gsub!(/(\w+):/, "#{TEXT_CYAN}\\1#{CLEAR}:") | |||
|           params.gsub!(/"(.*?)"/, "\"#{TEXT_YELLOW}\\1#{CLEAR}\"") | |||
|         end | |||
|         logger.debug("Parameters: #{params}") unless params.empty? | |||
|       end | |||
|     end | |||
| 
 | |||
|     def finish_processing(event) | |||
|       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) | |||
|         status = payload[:status] | |||
| 
 | |||
|         if status.nil? && (exception_class_name = payload[:exception]&.first) | |||
|           status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name) | |||
|         end | |||
| 
 | |||
|         additions << "GC: #{event.gc_time.round(1)}ms" | |||
|         if event.duration >= 1200 | |||
|           logger.error process_duration(event, additions) | |||
|         elsif event.duration >= 600 | |||
|           logger.warn process_duration(event, additions) | |||
|         elsif event.duration >= 300 | |||
|           logger.info process_duration(event, additions) | |||
|         elsif event.duration >= 100 | |||
|           logger.debug process_duration(event, additions) | |||
|         end | |||
| 
 | |||
|         status_family = status / 100 | |||
| 
 | |||
|         dimensions = case status_family | |||
|                      when 2 | |||
|                        Semantic::AnsiDimensions.new(rails: TERMINUS_STRING) | |||
|                      when 3 | |||
|                        Semantic::AnsiDimensions.new(rails: '╙║╜') | |||
|                      when 4 | |||
|                        Semantic::AnsiDimensions.new(rails: '╙╨╜') | |||
|                      when 5 | |||
|                        Semantic::AnsiDimensions.new(rails: '╙║╜') | |||
|                      end | |||
|         logger.info("Completed #{colorize(status, BOLD)} #{Rack::Utils::HTTP_STATUS_CODES[status]}", dimensions:) | |||
|         logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: ' ║ ')) if status_family == 3 | |||
|         logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: '╓║╖')) if status_family == 5 | |||
|       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 | |||
|       @previously_redirect = true | |||
|     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 | |||
| end | |||
| @ -0,0 +1,130 @@ | |||
| module Semantic | |||
|   module Subscribers | |||
|     class ActionController < ActiveSupport::LogSubscriber | |||
|       include AnsiColors | |||
| 
 | |||
|       INTERNAL_PARAMS = %i[controller action format _method only_path].freeze | |||
|       DEFAULT_DEV_HOSTS = ['127.0.0.1', 'localhost'].freeze | |||
|       TERMINUS_STRING = '╙─╜'.freeze | |||
| 
 | |||
|       attr_reader :logger | |||
| 
 | |||
|       def initialize(session_key) | |||
|         @session_key = session_key | |||
|         @transactions = {} | |||
| 
 | |||
|         short_name = self.class.to_s.split('::').last | |||
|         @logger = SemanticLogger[short_name] | |||
| 
 | |||
|         super() | |||
|       end | |||
| 
 | |||
|       def start_processing(event) | |||
|         session_value = session_value(event) | |||
|         @transactions[event.transaction_id] = session_value # preserve session_value to help finish_processing | |||
| 
 | |||
|         SemanticLogger.tagged(session_value) do | |||
|           request = event.payload[:request] | |||
|           path = colorize(request.filtered_path, BOLD) | |||
| 
 | |||
|           dimensions = Semantic::AnsiDimensions.new(rails: '╓─╖', before: 1) | |||
|           if defined?(@previously_redirect) && @previously_redirect | |||
|             dimensions = Semantic::AnsiDimensions.new(rails: '╓║╖', before: 0) | |||
|             @previously_redirect = false | |||
|           end | |||
|           logger.info("Started #{request.raw_request_method} #{path}", dimensions:) | |||
| 
 | |||
|           format = event.payload[:format] | |||
|           format = format.to_s.upcase if format.is_a?(Symbol) | |||
|           format = '*/*' if format.nil? | |||
|           format = colorize(format, BOLD) | |||
|           logger.debug("Processing by #{event.payload[:controller]}##{event.payload[:action]} as #{format}") | |||
| 
 | |||
|           params = event.payload[:params].deep_symbolize_keys.except(*INTERNAL_PARAMS) | |||
|           unless params.empty? | |||
|             params = params.ai(ruby19_syntax: true, plain: true, multiline: false) | |||
|             params.gsub!(/(\w+):/, "#{TEXT_CYAN}\\1#{CLEAR}:") | |||
|             params.gsub!(/"(.*?)"/, "\"#{TEXT_YELLOW}\\1#{CLEAR}\"") | |||
|           end | |||
|           logger.debug("Parameters: #{params}") unless params.empty? | |||
|         end | |||
|       end | |||
| 
 | |||
|       def finish_processing(event) | |||
|         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) | |||
|           status = payload[:status] | |||
| 
 | |||
|           if status.nil? && (exception_class_name = payload[:exception]&.first) | |||
|             status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name) | |||
|           end | |||
| 
 | |||
|           additions << "GC: #{event.gc_time.round(1)}ms" | |||
|           if event.duration >= 1200 | |||
|             logger.error process_duration(event, additions) | |||
|           elsif event.duration >= 600 | |||
|             logger.warn process_duration(event, additions) | |||
|           elsif event.duration >= 300 | |||
|             logger.info process_duration(event, additions) | |||
|           elsif event.duration >= 100 | |||
|             logger.debug process_duration(event, additions) | |||
|           end | |||
| 
 | |||
|           status_family = status / 100 | |||
| 
 | |||
|           dimensions = case status_family | |||
|                        when 2 | |||
|                          Semantic::AnsiDimensions.new(rails: TERMINUS_STRING) | |||
|                        when 3 | |||
|                          Semantic::AnsiDimensions.new(rails: '╙║╜') | |||
|                        when 4 | |||
|                          Semantic::AnsiDimensions.new(rails: '╙╨╜') | |||
|                        when 5 | |||
|                          Semantic::AnsiDimensions.new(rails: '╙║╜') | |||
|                        end | |||
|           logger.info("Completed #{colorize(status, BOLD)} #{Rack::Utils::HTTP_STATUS_CODES[status]}", dimensions:) | |||
|           logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: ' ║ ')) if status_family == 3 | |||
|           logger.info(' ', dimensions: Semantic::AnsiDimensions.new(rails: '╓║╖')) if status_family == 5 | |||
|         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 | |||
|         @previously_redirect = true | |||
|       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 | |||
|   end | |||
| end | |||
| @ -0,0 +1,19 @@ | |||
| module Semantic | |||
|   module Subscribers | |||
|     class ActionView < ActiveSupport::LogSubscriber | |||
|       include AnsiColors | |||
| 
 | |||
|       attr_reader :logger | |||
| 
 | |||
|       def initialize | |||
|         short_name = self.class.to_s.split('::').last | |||
|         @logger = SemanticLogger[short_name] | |||
|         super | |||
|       end | |||
| 
 | |||
|       def render_partial(event) | |||
|         logger.info('Rendered partial', event) | |||
|       end | |||
|     end | |||
|   end | |||
| end | |||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue