lookout-query_reviewer 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.md +136 -0
- data/Rakefile +24 -0
- data/lib/query_reviewer.rb +66 -0
- data/lib/query_reviewer/array_extensions.rb +29 -0
- data/lib/query_reviewer/controller_extensions.rb +67 -0
- data/lib/query_reviewer/mysql_adapter_extensions.rb +92 -0
- data/lib/query_reviewer/mysql_analyzer.rb +62 -0
- data/lib/query_reviewer/query_warning.rb +17 -0
- data/lib/query_reviewer/rails.rb +37 -0
- data/lib/query_reviewer/sql_query.rb +131 -0
- data/lib/query_reviewer/sql_query_collection.rb +103 -0
- data/lib/query_reviewer/sql_sub_query.rb +45 -0
- data/lib/query_reviewer/tasks.rb +8 -0
- data/lib/query_reviewer/views/_box.html.erb +11 -0
- data/lib/query_reviewer/views/_box_ajax.js +34 -0
- data/lib/query_reviewer/views/_box_body.html.erb +73 -0
- data/lib/query_reviewer/views/_box_disabled.html.erb +2 -0
- data/lib/query_reviewer/views/_box_header.html.erb +1 -0
- data/lib/query_reviewer/views/_box_includes.html.erb +234 -0
- data/lib/query_reviewer/views/_explain.html.erb +30 -0
- data/lib/query_reviewer/views/_js_includes.html.erb +68 -0
- data/lib/query_reviewer/views/_js_includes_new.html.erb +68 -0
- data/lib/query_reviewer/views/_profile.html.erb +26 -0
- data/lib/query_reviewer/views/_query_sql.html.erb +8 -0
- data/lib/query_reviewer/views/_query_trace.html.erb +31 -0
- data/lib/query_reviewer/views/_query_with_warning.html.erb +54 -0
- data/lib/query_reviewer/views/_spectrum.html.erb +10 -0
- data/lib/query_reviewer/views/_warning_no_query.html.erb +8 -0
- data/lib/query_reviewer/views/query_review_box_helper.rb +99 -0
- data/query_reviewer_defaults.yml +39 -0
- metadata +77 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
<li id="query_<%= query_with_warning.id %>">
|
2
|
+
<div>
|
3
|
+
<%= render :partial => "/spectrum", :locals => {:severity => query_with_warning.max_severity} %>
|
4
|
+
<% if QueryReviewer::CONFIGURATION["production_data"] %>
|
5
|
+
<div style="float: left; padding-right: 5px;">
|
6
|
+
<%= duration_with_color(query_with_warning) %>s
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
<p>
|
10
|
+
<% if query_with_warning.count > 1 %>
|
11
|
+
<b title="<%= query_with_warning.count %> queries were executed with the same stack trace and similar SQL structure">
|
12
|
+
<%= query_with_warning.count %> identical queries
|
13
|
+
</b>
|
14
|
+
<% end %>
|
15
|
+
<i>Table <%= (query_with_warning.warnings.detect {|w| !w.table.blank? } || query_with_warning.warnings.last).table %>:</i>
|
16
|
+
<% query_with_warning.warnings.sort{|a,b| a.severity <=> b.severity}.reverse.each_with_index do |warn, index| %>
|
17
|
+
<span style="color: <%= severity_color warn.severity%>;" title="<%= warn.desc%>"><%= warn.problem %></span><%= ", " if index < query_with_warning.warnings.length - 1 %>
|
18
|
+
<% end %>
|
19
|
+
<a href="#" onclick="query_review_toggle('warning_<%= query_with_warning.id %>_desc')" title="show/hide warning message">MSG</a>
|
20
|
+
<a href="#" onclick="query_review_toggle('warning_<%= query_with_warning.id %>_sql')" title="show/hide sql">SQL</a>
|
21
|
+
<% if query_with_warning.select? %>
|
22
|
+
<a href="#" onclick="query_review_toggle('warning_<%= query_with_warning.id %>_explain')" title="show/hide explain output">EXPLN</a>
|
23
|
+
<% end %>
|
24
|
+
<% if QueryReviewer::CONFIGURATION["profiling"] && query_with_warning.profile %>
|
25
|
+
<a href="#" onclick="query_review_toggle('warning_<%= query_with_warning.id %>_profile')" title="show/hide profile output">PROF</a>
|
26
|
+
<% end %>
|
27
|
+
<a href="#" onclick="query_review_toggle('warning_<%= query_with_warning.id %>_trace')" title="show/hide stack trace">TRACE</a>
|
28
|
+
<% if ignore_hash?(query_with_warning.to_hash) %>
|
29
|
+
<a href="#" onclick="remove_ignore_hash('<%= query_with_warning.to_hash %>'); query_review_hide('query_<%= query_with_warning.id %>')" title="stop ignore this query from now on">UNIGNR</a>
|
30
|
+
<% else %>
|
31
|
+
<a href="#" onclick="add_ignore_hash('<%= query_with_warning.to_hash %>'); query_review_hide('query_<%= query_with_warning.id %>')" title="ignoring this query from now on">IGNR</a>
|
32
|
+
<% end %>
|
33
|
+
</p>
|
34
|
+
</div>
|
35
|
+
<p style="display: none" id="warning_<%= query_with_warning.id %>_desc" class="indent">
|
36
|
+
<% query_with_warning.warnings.each do |warn| %>
|
37
|
+
<span style="color: <%= severity_color warn.severity%>"><%= warn.desc %></span><br/>
|
38
|
+
<% end %>
|
39
|
+
</p>
|
40
|
+
<p style="display: none" id="warning_<%= query_with_warning.id %>_sql" class="indent small tbpadded">
|
41
|
+
<%= render :partial => "/query_sql", :locals => {:query_sql => query_with_warning} %>
|
42
|
+
</p>
|
43
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_explain" class="indent small tbpadded">
|
44
|
+
<%= render :partial => "/explain", :locals => {:query => query_with_warning} %>
|
45
|
+
</div>
|
46
|
+
<% if QueryReviewer::CONFIGURATION["profiling"] && query_with_warning.profile %>
|
47
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_profile" class="indent small tbpadded">
|
48
|
+
<%= render :partial => "/profile", :locals => {:query => query_with_warning} %>
|
49
|
+
</div>
|
50
|
+
<% end %>
|
51
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_trace" class="indent small">
|
52
|
+
<%= render :partial => "/query_trace", :locals => {:query_id => query_with_warning.id, :full_trace => query_with_warning.full_trace,:query_trace => query_with_warning.relevant_trace} %>
|
53
|
+
</div>
|
54
|
+
</li>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="spectrum_container" title="Severity: <%= severity%> out of 10">
|
2
|
+
<% 0.upto(15) do |i| %>
|
3
|
+
<div class="spectrum_elem" style="background-color: <%= "##{i.to_s(16)}F0"%>"></div>
|
4
|
+
<% end %>
|
5
|
+
<% 0.upto(15) do |i| %>
|
6
|
+
<div class="spectrum_elem" style="background-color: <%= "#F#{((15-i)).to_s(16)}0"%>"></div>
|
7
|
+
<% end %>
|
8
|
+
<div class="spectrum_elem" style="background-color: #FF0000"></div>
|
9
|
+
<div class="spectrum_pointer" style="left: <%= severity * 3 + 2 %>px;"></div>
|
10
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<li id="warning_<%= warning_no_query.id %>">
|
2
|
+
<div>
|
3
|
+
<%= render :partial => "/spectrum", :locals => {:severity => warning_no_query.severity} %>
|
4
|
+
<p>
|
5
|
+
<span style="color: <%= severity_color warning_no_query.severity%>" title="<%= warning_no_query.desc %>"><%= warning_no_query.problem %></span>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</li>
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module QueryReviewer
|
2
|
+
module Views
|
3
|
+
module QueryReviewBoxHelper
|
4
|
+
def parent_div_class
|
5
|
+
"sql_#{parent_div_status.downcase}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def parent_div_status
|
9
|
+
if !enabled_by_cookie
|
10
|
+
"DISABLED"
|
11
|
+
elsif overall_max_severity < (QueryReviewer::CONFIGURATION["warn_severity"] || 4)
|
12
|
+
"OK"
|
13
|
+
elsif overall_max_severity < (QueryReviewer::CONFIGURATION["critical_severity"] || 7)
|
14
|
+
# uh oh
|
15
|
+
"WARNING"
|
16
|
+
else
|
17
|
+
# oh @#&!
|
18
|
+
"CRITICAL"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def syntax_highlighted_sql(sql)
|
23
|
+
sql = sql.to_sql if sql.respond_to?(:to_sql)
|
24
|
+
if QueryReviewer::CONFIGURATION["uv"]
|
25
|
+
uv_out = Uv.parse(sql, "xhtml", "sql_rails", false, "blackboard")
|
26
|
+
uv_out.gsub("<pre class=\"blackboard\">", "<code class=\"sql\">").gsub("</pre>", "</code>")
|
27
|
+
else
|
28
|
+
sql.gsub(/</, "<").gsub(/>/, ">")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def overall_max_severity
|
33
|
+
max = 0
|
34
|
+
max = queries_with_warnings_sorted_nonignored[0].max_severity unless queries_with_warnings_sorted_nonignored.empty?
|
35
|
+
max = warnings_no_query_sorted.first.severity unless warnings_no_query_sorted.empty? || warnings_no_query_sorted.first.severity < max
|
36
|
+
max
|
37
|
+
end
|
38
|
+
|
39
|
+
def severity_color(severity)
|
40
|
+
red = (severity * 16.0 / 10).to_i
|
41
|
+
green = ((10-severity) * 16.0 / 10).to_i
|
42
|
+
red = 8 if red > 8
|
43
|
+
red = 0 if red < 0
|
44
|
+
green = 8 if green > 8
|
45
|
+
green = 0 if green < 0
|
46
|
+
"##{red.to_s(16)}#{green.to_s(16)}0"
|
47
|
+
end
|
48
|
+
|
49
|
+
def ignore_hash?(h)
|
50
|
+
(controller.send(:cookies)["query_review_ignore_list"] || "").split(",").include?(h.to_s)
|
51
|
+
end
|
52
|
+
|
53
|
+
def queries_with_warnings
|
54
|
+
@queries.queries.select{|q| q.has_warnings?}
|
55
|
+
end
|
56
|
+
|
57
|
+
def queries_with_warnings_sorted
|
58
|
+
queries_with_warnings.sort{|a,b| (b.max_severity * 1000 + (b.duration || 0)) <=> (a.max_severity * 1000 + (a.duration || 0))}
|
59
|
+
end
|
60
|
+
|
61
|
+
def queries_with_warnings_sorted_nonignored
|
62
|
+
queries_with_warnings_sorted.select{|q| q.max_severity >= ::QueryReviewer::CONFIGURATION["warn_severity"] && !ignore_hash?(q.to_hash)}
|
63
|
+
end
|
64
|
+
|
65
|
+
def queries_with_warnings_sorted_ignored
|
66
|
+
queries_with_warnings_sorted.reject{|q| q.max_severity >= ::QueryReviewer::CONFIGURATION["warn_severity"] && !ignore_hash?(q.to_hash)}
|
67
|
+
end
|
68
|
+
|
69
|
+
def warnings_no_query_sorted
|
70
|
+
@queries.collection_warnings.sort{|a,b| a.severity <=> b.severity}.reverse
|
71
|
+
end
|
72
|
+
|
73
|
+
def warnings_no_query_sorted_ignored
|
74
|
+
warnings_no_query_sorted.select{|q| q.severity < ::QueryReviewer::CONFIGURATION["warn_severity"]}
|
75
|
+
end
|
76
|
+
|
77
|
+
def warnings_no_query_sorted_nonignored
|
78
|
+
warnings_no_query_sorted.select{|q| q.severity >= ::QueryReviewer::CONFIGURATION["warn_severity"]}
|
79
|
+
end
|
80
|
+
|
81
|
+
def enabled_by_cookie
|
82
|
+
controller.send(:cookies)["query_review_enabled"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def duration_with_color(query)
|
86
|
+
title = query.duration_stats
|
87
|
+
duration = query.duration
|
88
|
+
span_html = if duration > QueryReviewer::CONFIGURATION["critical_duration_threshold"]
|
89
|
+
"<span style=\"color: #{severity_color(9)}\" title=\"#{title}\">#{"%.3f" % duration}</span>"
|
90
|
+
elsif duration > QueryReviewer::CONFIGURATION["warn_duration_threshold"]
|
91
|
+
"<span style=\"color: #{severity_color(QueryReviewer::CONFIGURATION["critical_severity"])}\" title=\"#{title}\">#{"%.3f" % duration}</span>"
|
92
|
+
else
|
93
|
+
"<span title=\"#{title}\">#{"%.3f" % duration}</span>"
|
94
|
+
end
|
95
|
+
span_html.respond_to?(:html_safe) ? span_html.html_safe : span_html
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
all:
|
2
|
+
inject_view: true
|
3
|
+
stack_trace_lines: 3
|
4
|
+
trace_includes_vendor: false
|
5
|
+
trace_includes_lib: true
|
6
|
+
profiling: enabled
|
7
|
+
production_data: true
|
8
|
+
max_safe_key_length: 100
|
9
|
+
disable_sql_cache: true
|
10
|
+
|
11
|
+
warn_severity: 3
|
12
|
+
critical_severity: 7
|
13
|
+
|
14
|
+
warn_select_count: 20
|
15
|
+
critical_select_count: 50
|
16
|
+
|
17
|
+
warn_update_count: 5
|
18
|
+
critical_update_count: 10
|
19
|
+
|
20
|
+
warn_insert_count: 5
|
21
|
+
critical_insert_count: 10
|
22
|
+
|
23
|
+
warn_delete_count: 5
|
24
|
+
critical_delete_count: 10
|
25
|
+
|
26
|
+
warn_duration_threshold: 0.2
|
27
|
+
critical_duration_threshold: 1.0
|
28
|
+
|
29
|
+
warn_affected_rows: 10
|
30
|
+
critical_affected_rows: 100
|
31
|
+
|
32
|
+
development:
|
33
|
+
enabled: true
|
34
|
+
|
35
|
+
production:
|
36
|
+
enabled: false
|
37
|
+
|
38
|
+
test:
|
39
|
+
enabled: false
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lookout-query_reviewer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- dsboulder, nesquena
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-17 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Runs explain before each select query and displays results in an overlayed
|
15
|
+
div
|
16
|
+
email: nesquena@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- MIT-LICENSE
|
22
|
+
- Rakefile
|
23
|
+
- README.md
|
24
|
+
- query_reviewer_defaults.yml
|
25
|
+
- lib/query_reviewer.rb
|
26
|
+
- lib/query_reviewer/rails.rb
|
27
|
+
- lib/query_reviewer/mysql_analyzer.rb
|
28
|
+
- lib/query_reviewer/sql_query.rb
|
29
|
+
- lib/query_reviewer/controller_extensions.rb
|
30
|
+
- lib/query_reviewer/query_warning.rb
|
31
|
+
- lib/query_reviewer/sql_query_collection.rb
|
32
|
+
- lib/query_reviewer/views/_box_header.html.erb
|
33
|
+
- lib/query_reviewer/views/_js_includes_new.html.erb
|
34
|
+
- lib/query_reviewer/views/_js_includes.html.erb
|
35
|
+
- lib/query_reviewer/views/_box_ajax.js
|
36
|
+
- lib/query_reviewer/views/_query_trace.html.erb
|
37
|
+
- lib/query_reviewer/views/query_review_box_helper.rb
|
38
|
+
- lib/query_reviewer/views/_profile.html.erb
|
39
|
+
- lib/query_reviewer/views/_query_sql.html.erb
|
40
|
+
- lib/query_reviewer/views/_box.html.erb
|
41
|
+
- lib/query_reviewer/views/_warning_no_query.html.erb
|
42
|
+
- lib/query_reviewer/views/_box_body.html.erb
|
43
|
+
- lib/query_reviewer/views/_query_with_warning.html.erb
|
44
|
+
- lib/query_reviewer/views/_spectrum.html.erb
|
45
|
+
- lib/query_reviewer/views/_box_includes.html.erb
|
46
|
+
- lib/query_reviewer/views/_box_disabled.html.erb
|
47
|
+
- lib/query_reviewer/views/_explain.html.erb
|
48
|
+
- lib/query_reviewer/tasks.rb
|
49
|
+
- lib/query_reviewer/mysql_adapter_extensions.rb
|
50
|
+
- lib/query_reviewer/sql_sub_query.rb
|
51
|
+
- lib/query_reviewer/array_extensions.rb
|
52
|
+
homepage: https://github.com/lookout/query_reviewer
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.10
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Runs explain before each select query and displays results in an overlayed
|
76
|
+
div
|
77
|
+
test_files: []
|