lookout-query_reviewer 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +136 -0
  3. data/Rakefile +24 -0
  4. data/lib/query_reviewer.rb +66 -0
  5. data/lib/query_reviewer/array_extensions.rb +29 -0
  6. data/lib/query_reviewer/controller_extensions.rb +67 -0
  7. data/lib/query_reviewer/mysql_adapter_extensions.rb +92 -0
  8. data/lib/query_reviewer/mysql_analyzer.rb +62 -0
  9. data/lib/query_reviewer/query_warning.rb +17 -0
  10. data/lib/query_reviewer/rails.rb +37 -0
  11. data/lib/query_reviewer/sql_query.rb +131 -0
  12. data/lib/query_reviewer/sql_query_collection.rb +103 -0
  13. data/lib/query_reviewer/sql_sub_query.rb +45 -0
  14. data/lib/query_reviewer/tasks.rb +8 -0
  15. data/lib/query_reviewer/views/_box.html.erb +11 -0
  16. data/lib/query_reviewer/views/_box_ajax.js +34 -0
  17. data/lib/query_reviewer/views/_box_body.html.erb +73 -0
  18. data/lib/query_reviewer/views/_box_disabled.html.erb +2 -0
  19. data/lib/query_reviewer/views/_box_header.html.erb +1 -0
  20. data/lib/query_reviewer/views/_box_includes.html.erb +234 -0
  21. data/lib/query_reviewer/views/_explain.html.erb +30 -0
  22. data/lib/query_reviewer/views/_js_includes.html.erb +68 -0
  23. data/lib/query_reviewer/views/_js_includes_new.html.erb +68 -0
  24. data/lib/query_reviewer/views/_profile.html.erb +26 -0
  25. data/lib/query_reviewer/views/_query_sql.html.erb +8 -0
  26. data/lib/query_reviewer/views/_query_trace.html.erb +31 -0
  27. data/lib/query_reviewer/views/_query_with_warning.html.erb +54 -0
  28. data/lib/query_reviewer/views/_spectrum.html.erb +10 -0
  29. data/lib/query_reviewer/views/_warning_no_query.html.erb +8 -0
  30. data/lib/query_reviewer/views/query_review_box_helper.rb +99 -0
  31. data/query_reviewer_defaults.yml +39 -0
  32. 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(/</, "&lt;").gsub(/>/, "&gt;")
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: []