require "#{File.dirname(__FILE__)}/abstract_note"
module Footnotes
module Notes
class QueriesNote < AbstractNote
@@alert_db_time = 16.0
@@alert_sql_number = 8
@@sql = []
@@include_when_new_relic_installed = false
@@loaded = false
@@query_subscriber = nil
cattr_accessor :sql, :alert_db_time, :alert_sql_number, :alert_explain, :loaded, :sql_explain, :instance_writter => false
cattr_reader :include_when_new_relic_installed
def self.include_when_new_relic_installed=(include_me)
@@include_when_new_relic_installed = include_me
load if include_me
end
def self.start!(controller)
@@sql = []
@@query_subscriber = Footnotes::Notes::QuerySubscriber.new
# There appears to be nothing wrong with registering with a non-existant notifier, so we just attach to both :-).
ActiveSupport::LogSubscriber.attach_to(:data_mapper, @@query_subscriber)
ActiveSupport::LogSubscriber.attach_to(:active_record, @@query_subscriber)
end
def self.to_sym
:queries
end
def title
queries = @@query_subscriber.events.length
total_time = @@query_subscriber.events.map{|e| e.duration }.sum / 1000.0
query_color = generate_red_color(@@query_subscriber.events.length, alert_sql_number)
db_color = generate_red_color(total_time, alert_db_time)
<<-TITLE
Queries (#{queries})
DB (#{"%.3f" % total_time}ms)
TITLE
end
def stylesheet
<<-STYLESHEET
#queries_debug_info table td, #queries_debug_info table th{border:1px solid #A00; padding:0 3px; text-align:center;}
#queries_debug_info table thead, #queries_debug_info table tbody {color:#A00;}
#queries_debug_info p {background-color:#F3F3FF; border:1px solid #CCC; margin:12px; padding:4px 6px;}
#queries_debug_info a:hover {text-decoration:underline;}
STYLESHEET
end
# FIXME (andre 2011-04-04) This should look like the old query log, preferably with links to trace the queries.
def content
html = ''
@@query_subscriber.events.each_with_index do |item, i|
html << <<-HTML
#{print_name_and_time(item.payload[:name], item.duration / 1000.0)}
#{print_query(item.payload[:sql])}
HTML
end
return html
end
def self.load
self.loaded = true unless loaded
end
protected
def print_name_and_time(name, time)
"#{escape(name || 'SQL')} (#{'%.3fms' % time})"
end
def print_query(query)
escape(query.to_s.gsub(/(\s)+/, ' ').gsub('`', ''))
end
def generate_red_color(value, alert)
c = ((value.to_f/alert).to_i - 1) * 16
c = 0 if c < 0
c = 15 if c > 15
c = (15-c).to_s(16)
"#ff#{c*4}"
end
def alert_ratio
alert_db_time / alert_sql_number
end
end
class QuerySubscriber < ActiveSupport::LogSubscriber
attr_accessor :events
def self.runtime=(value)
Thread.current["orm_sql_runtime"] = value
end
def self.runtime
Thread.current["orm_sql_runtime"] ||= 0
end
def self.reset_runtime
rt, self.runtime = runtime, 0
rt
end
def initialize
@events = Array.new
super
end
def sql(event)
@events << event.dup
end
end
end
end
Footnotes::Notes::QueriesNote.load