require "rails_instrument/version" module RailsInstrument class < 0 } end def init #:nodoc: $rails_instrument ||= {} $rails_instrument[:sql_count] ||= 0 end def data #:nodoc: $rails_instrument end # Return the number of sql fired from the last reset def sql_count data[:sql_count] end # Taken a block and return the instrument object for the operation done on the block. # TODO: Make it to work with nested instrument blocks def instrument(&block) raise "A block is not passed" unless block_given? RailsInstrument.reset! yield self end def increment_sql_count #:nodoc: data[:sql_count] += 1 end end class Middleware #:nodoc: def initialize(app, options = {}) @app = app end def call(env) RailsInstrument.reset! status, headers, body = @app.call(env) begin headers["X-View-Runtime"] = (view_runtime / 1000).to_s headers["X-DB-Runtime"] = (db_runtime / 1000).to_s headers["X-DB-Query-Count"] = sql_count.to_s if html_reponse?(headers) new_body = Rack::Response.new([], status, headers) body.each do |fragment| new_body.write fragment.gsub("", "#{sql_html_overlay}") end body = new_body end rescue => e headers["X-Rails-Instrument"] = "Error" end [status, headers, body] end private def html_reponse?(headers) headers['Content-Type'] =~ /html/ end def sql_html_overlay %Q{
#{sql_count} / #{"%.3f" % db_runtime}
} end def db_runtime RailsInstrument.data["process_action.action_controller"][:db_runtime] end def view_runtime RailsInstrument.data["process_action.action_controller"][:view_runtime] end def sql_count RailsInstrument.sql_count end end class Engine < ::Rails::Engine #:nodoc: initializer "my_engine.add_middleware" do |app| app.middleware.use RailsInstrument::Middleware ActiveSupport::Notifications.subscribe("process_action.action_controller") do |name, start, finish, id, payload| RailsInstrument.init $rails_instrument[name] = payload end ActiveSupport::Notifications.subscribe("sql.active_record") do |name, start, finish, id, payload| RailsInstrument.init RailsInstrument.increment_sql_count unless (payload[:name] == "SCHEMA" || %w(BEGIN COMMIT ROLLBACK).include?(payload[:sql])) end end end end