instrumentation.rb 3.0 KB
Newer Older
1 2 3 4
require 'abstract_controller/logger'

module ActionController
  # Adds instrumentation to several ends in ActionController::Base. It also provides
5 6 7 8
  # some hooks related with process_action, this allows an ORM like ActiveRecord
  # and/or DataMapper to plug in ActionController and show related information.
  #
  # Check ActiveRecord::Railties::ControllerRuntime for an example.
9 10 11
  module Instrumentation
    extend ActiveSupport::Concern

12 13
    include AbstractController::Logger
    include ActionController::FilterParameterLogging
14 15 16 17

    attr_internal :view_runtime

    def process_action(action, *args)
18 19 20 21 22 23 24 25 26 27
      raw_payload = {
        :controller => self.class.name,
        :action     => self.action_name,
        :params     => filter_parameters(params),
        :formats    => request.formats.map(&:to_sym)
      }

      ActiveSupport::Notifications.instrument("action_controller.start_processing", raw_payload.dup)

      ActiveSupport::Notifications.instrument("action_controller.process_action", raw_payload) do |payload|
28
        result = super
29
        payload[:status] = response.status
30 31
        append_info_to_payload(payload)
        result
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
      end
    end

    def render(*args, &block)
      if logger
        render_output = nil

        self.view_runtime = cleanup_view_runtime do
          Benchmark.ms { render_output = super }
        end

        render_output
      else
        super
      end
    end

    def send_file(path, options={})
      ActiveSupport::Notifications.instrument("action_controller.send_file",
        options.merge(:path => path)) do
        super
      end
    end

    def send_data(data, options = {})
      ActiveSupport::Notifications.instrument("action_controller.send_data", options) do
        super
      end
    end

    def redirect_to(*args)
63 64 65 66 67 68
      ActiveSupport::Notifications.instrument("action_controller.redirect_to") do |payload|
        result = super
        payload[:status]   = self.status
        payload[:location] = self.location
        result
      end
69 70
    end

71 72
  protected

73 74 75 76 77 78 79 80 81 82 83 84
    # A hook which allows you to clean up any time taken into account in
    # views wrongly, like database querying time.
    #
    #   def cleanup_view_runtime
    #     super - time_taken_in_something_expensive
    #   end
    #
    # :api: plugin
    def cleanup_view_runtime #:nodoc:
      yield
    end

85 86 87 88 89 90 91
    # Everytime after an action is processed, this method is invoked
    # with the payload, so you can add more information.
    # :api: plugin
    def append_info_to_payload(payload) #:nodoc:
      payload[:view_runtime] = view_runtime
    end

92 93
    module ClassMethods
      # A hook which allows other frameworks to log what happened during
94
      # controller process action. This method should return an array
95
      # with the messages to be added.
96
      # :api: plugin
97 98
      def log_process_action(payload) #:nodoc:
        messages, view_runtime = [], payload[:view_runtime]
99 100
        messages << ("Views: %.1fms" % view_runtime.to_f) if view_runtime
        messages
101 102 103 104
      end
    end
  end
end