sql_tracer 0.0.6 → 0.0.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 554687b0e5ff1f0aeabbffa232513722309d2b5c
4
- data.tar.gz: 4e1b7e5d40d3e4462bdb70087620b5501feff05b
3
+ metadata.gz: 982974c81f2a39e7c1cb812423788ed733434750
4
+ data.tar.gz: 14a302d2095e86805fb12e6f164f553293c89ed5
5
5
  SHA512:
6
- metadata.gz: a3363dd4e9e43ee0369036b2b4938b82eba73a18fffb88104375008c110c63a16a797eb5fda2b8d37d05ab1d13bd002bcb669bcf071a33c1780ad19b3a2efe21
7
- data.tar.gz: d961a3be4e1842306e17eb9c48dc1e706bde60a3f339586da03a5feb9fc9374f6b3e8591634ff28dd04c87209973d207306faab702a3c94aa57308f193c58f86
6
+ metadata.gz: b72ef9736956a00c8561dc64246079bcf79805ef32a24ccd4f4e0efc7baa3244d8293ad69fd24c312ca74885deb83705a00a5f81fd655db9d71b3a4791b6b72d
7
+ data.tar.gz: bfa565ccb801c5fa052277ec22f8ddfd2eb3c42fa74542a1a1ffe9620178b030508d4a6d2595743e7350a78e059bb59105ab7ebfbf14a1aaa95dcea9fb60703a
@@ -0,0 +1,5 @@
1
+ /*
2
+ ...ommitted code...
3
+ *= require_self
4
+ *= require_tree .
5
+ */
@@ -0,0 +1,191 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: 'Roboto';
4
+ font-size: 14px;
5
+ background: #ffffff;
6
+ }
7
+
8
+ h3 {
9
+ color: #fff;
10
+ font-size: 24px;
11
+ text-align: center;
12
+ margin-top: 30px;
13
+ padding-bottom: 30px;
14
+ border-bottom: 1px solid #eee;
15
+ margin-bottom: 30px;
16
+ font-weight: 300;
17
+ }
18
+
19
+ /*.container {*/
20
+ /*max-width: 970px;*/
21
+ /*}*/
22
+
23
+ div[class*='col-'] {
24
+ padding: 0 30px;
25
+ }
26
+
27
+ .wrap {
28
+ box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
29
+ border-radius: 4px;
30
+ }
31
+
32
+ a:focus,
33
+ a:hover,
34
+ a:active {
35
+ outline: 0;
36
+ text-decoration: none;
37
+ }
38
+
39
+ .container {
40
+ width: 90%;
41
+ }
42
+ .panel {
43
+ border-width: 0 0 1px 0;
44
+ border-style: solid;
45
+ border-color: #fff;
46
+ background: none;
47
+ box-shadow: none;
48
+ }
49
+
50
+ .panel:last-child {
51
+ border-bottom: none;
52
+ }
53
+
54
+ .panel-group > .panel:first-child .panel-heading {
55
+ border-radius: 4px 4px 0 0;
56
+ }
57
+
58
+ .panel-group .panel {
59
+ border-radius: 0;
60
+ }
61
+
62
+ .panel-group .panel + .panel {
63
+ margin-top: 0;
64
+ }
65
+
66
+ .panel-heading {
67
+ background-color: #18504a;
68
+ border-radius: 0;
69
+ border: none;
70
+ color: #fff;
71
+ padding: 0;
72
+ }
73
+
74
+ .panel-title a {
75
+ display: block;
76
+ color: #fff;
77
+ padding: 15px;
78
+ position: relative;
79
+ font-size: 16px;
80
+ font-weight: 400;
81
+ }
82
+
83
+ .panel-body {
84
+ background: rgba(153,153,153,0.29);
85
+ }
86
+
87
+ .panel:last-child .panel-body {
88
+ border-radius: 0 0 4px 4px;
89
+ }
90
+
91
+ .panel:last-child .panel-heading {
92
+ border-radius: 0 0 4px 4px;
93
+ -webkit-transition: border-radius 0.3s linear 0.2s;
94
+ transition: border-radius 0.3s linear 0.2s;
95
+ }
96
+
97
+ .panel:last-child .panel-heading.active {
98
+ border-radius: 0;
99
+ -webkit-transition: border-radius linear 0s;
100
+ transition: border-radius linear 0s;
101
+ }
102
+
103
+ /* #bs-collapse icon scale option */
104
+
105
+ .panel-heading a:before {
106
+ content: '\e146';
107
+ position: absolute;
108
+ font-family: 'Material Icons';
109
+ right: 5px;
110
+ top: 10px;
111
+ font-size: 24px;
112
+ -webkit-transition: all 0.5s;
113
+ transition: all 0.5s;
114
+ -webkit-transform: scale(1);
115
+ transform: scale(1);
116
+ }
117
+
118
+ .panel-heading.active a:before {
119
+ content: ' ';
120
+ -webkit-transition: all 0.5s;
121
+ transition: all 0.5s;
122
+ -webkit-transform: scale(0);
123
+ transform: scale(0);
124
+ }
125
+
126
+ /*.panel-heading a:after {*/
127
+ /*content: ' ';*/
128
+ /*font-size: 24px;*/
129
+ /*position: absolute;*/
130
+ /*font-family: 'Material Icons';*/
131
+ /*right: 5px;*/
132
+ /*top: 10px;*/
133
+ /*-webkit-transform: scale(0);*/
134
+ /*transform: scale(0);*/
135
+ /*-webkit-transition: all 0.5s;*/
136
+ /*transition: all 0.5s;*/
137
+ /*}*/
138
+
139
+ /*.panel-heading.active a:after {*/
140
+ /*content: '\e909';*/
141
+ /*-webkit-transform: scale(1);*/
142
+ /*transform: scale(1);*/
143
+ /*-webkit-transition: all 0.5s;*/
144
+ /*transition: all 0.5s;*/
145
+ /*}*/
146
+
147
+ /* #accordion rotate icon option */
148
+
149
+ .panel-heading a:before {
150
+ content: '\e316';
151
+ font-size: 24px;
152
+ position: absolute;
153
+ font-family: 'Material Icons';
154
+ right: 5px;
155
+ top: 10px;
156
+ -webkit-transform: rotate(180deg);
157
+ transform: rotate(180deg);
158
+ -webkit-transition: all 0.5s;
159
+ transition: all 0.5s;
160
+ }
161
+
162
+ .panel-heading.active a:before {
163
+ -webkit-transform: rotate(0deg);
164
+ transform: rotate(0deg);
165
+ -webkit-transition: all 0.5s;
166
+ transition: all 0.5s;
167
+ }
168
+
169
+ .sql_template {
170
+ padding-left: 20px;
171
+ background-color: #009688;
172
+ line-break: auto;
173
+ word-break: break-all;
174
+ }
175
+
176
+ .stack_info {
177
+ word-break: break-all;
178
+ /*padding-left: 40px;*/
179
+ }
180
+
181
+ .stack_info div {
182
+ padding-left: 50px;
183
+ /*padding-left: 40px;*/
184
+ }
185
+
186
+ #url_template,
187
+ #sqls_template,
188
+ #sql_template,
189
+ #stack_info {
190
+ display: none;
191
+ }
@@ -0,0 +1,15 @@
1
+ module SqlTracer
2
+ class SqlTracerController < ActionController::Base
3
+ skip_filter :build_navigations
4
+ skip_after_filter :persist_reqeust_logger
5
+
6
+ def index
7
+ end
8
+
9
+ def get_latest_stack_info
10
+ ret = SqlTracer::SqlStack.to_json
11
+ SqlTracer::SqlStack.clear
12
+ render :json => ret
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,141 @@
1
+ <!doctype html>
2
+ <html lang="zh">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Sql Tracer</title>
8
+ <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700' rel='stylesheet' type='text/css'>
9
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
+ <link rel="stylesheet" type="text/css" href="http://www.jq22.com/jquery/bootstrap-3.3.4.css">
11
+ <%= stylesheet_link_tag 'sql_tracer/application' %>
12
+ </head>
13
+ <body>
14
+
15
+ <section class="jq22-container">
16
+ <div class="container">
17
+
18
+ <div class="row-fluid">
19
+ <div class="span12">
20
+ <div class="hero-unit">
21
+ <h1>
22
+ Sql Tracer
23
+ </h1>
24
+ <p>
25
+ It helps you figure out what sqls are executed and trace method call stack, you can take a look at
26
+ <a class="btn btn-primary btn-xs" target="_blank" href="https://git.dev.fwmrm.net/qzhang/sql_tracer"> READ
27
+ ME</a>
28
+ to acquire more information.
29
+ </p>
30
+ <p>
31
+ If you have any questions or improvement, please open a issue.
32
+ <a class="btn btn-primary btn-xs" target="_blank" href="https://git.dev.fwmrm.net/qzhang/sql_tracer/issues/new">
33
+ New Issue
34
+ </a>
35
+ </p>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ <!-- end of #bs-collapse -->
40
+ </div>
41
+
42
+
43
+ <div id="url_template" class="url_template">
44
+ <div class="panel-heading">
45
+ <h4 class="panel-title">
46
+ <a data-toggle="collapse" data-parent="#" href="#one">
47
+ </a>
48
+ </h4>
49
+ </div>
50
+ </div>
51
+
52
+ <div id="sql_template" class="panel-heading sql_template">
53
+ <h4 class="panel-title">
54
+ <a data-toggle="collapse" data-parent="#" href="#one-2" class="sql">
55
+ </a>
56
+ </h4>
57
+ </div>
58
+ <div id="stack_info" class="panel-collapse collapse stack_info" style="display: none">
59
+ <div class="panel-body ruby">
60
+ </div>
61
+ </div>
62
+
63
+ <div id="sqls_template" style="display: none"></div>
64
+ <!-- end of container -->
65
+ </section>
66
+
67
+ <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script>
68
+ <script src="http://www.jq22.com/jquery/bootstrap-3.3.4.js"></script>
69
+ <script type="text/javascript">
70
+ $(document).ready(function() {
71
+ refresh();
72
+ });
73
+
74
+ function refresh() {
75
+ $.ajax({
76
+ url: "/sql_tracer/get_latest_stack_info",
77
+ success: function(result, status) {
78
+ if (result) {
79
+ $.each(result, function(index, requestInfo) {
80
+ appendRequestInfo(requestInfo);
81
+ });
82
+ }
83
+ },
84
+ complete: function() {
85
+ setTimeout("refresh()", 3000)
86
+ }
87
+ });
88
+ }
89
+
90
+ function appendRequestInfo(requestInfo) {
91
+ var url = requestInfo.url;
92
+ var sqls = requestInfo.sqls || [];
93
+ var $url_template = $("#url_template").clone();
94
+ $url_template.attr("id", "");
95
+ $url_template.find("a").attr("href", "#");
96
+ $url_template.find("a").html(url);
97
+ $url_template.css("display", "block");
98
+
99
+ var $sqls_template = $("#sqls_template").clone();
100
+ $sqls_template.attr("id", "");
101
+
102
+ if (sqls && sqls.length > 0) {
103
+ $.each(sqls, function(index, sql_info) {
104
+ var $stack_info = $("#stack_info").clone();
105
+ $stack_info.attr("id", "");
106
+ $stack_info.find("div").html(sql_info.stack.join("<br\/>"));
107
+
108
+ var $sql_template = $("#sql_template").clone();
109
+ $sql_template.attr("id", "");
110
+ $sql_template.find("a").attr("href", "#");
111
+ $sql_template.find("a").html(sql_info.sql);
112
+ $sql_template.find("a").click(function() {
113
+ if ($stack_info.is(":visible")) {
114
+ $sql_template.removeClass('active');
115
+ } else {
116
+ $sql_template.addClass('active');
117
+ }
118
+ $stack_info.slideToggle();
119
+ });
120
+ $sqls_template.append($sql_template);
121
+ $sqls_template.append($stack_info);
122
+ });
123
+ } else {
124
+ $sqls_template.html('No effective sqls are detected.')
125
+ }
126
+
127
+ $url_template.find("a").click(function() {
128
+ if ($sqls_template.is(":visible")) {
129
+ $url_template.find(".panel-heading:first").removeClass('active');
130
+ } else {
131
+ $url_template.find(".panel-heading:first").addClass('active');
132
+ }
133
+ $sqls_template.slideToggle();
134
+ });
135
+ $url_template.append($sqls_template);
136
+ $(".container").append($url_template);
137
+ }
138
+
139
+ </script>
140
+ </body>
141
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ get '/sql_tracer/index' => 'sql_tracer/sql_tracer#index'
3
+ get '/sql_tracer/get_latest_stack_info' => 'sql_tracer/sql_tracer#get_latest_stack_info'
4
+ end
@@ -0,0 +1,4 @@
1
+ module SqlTracer
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,80 @@
1
+ require 'anbt-sql-formatter/formatter'
2
+
3
+ module SqlTracer
4
+ class Formatter
5
+ HEADER_PROMPT= '='*10 << '>'
6
+ FOOTER_PROMPT= '<' << '='*10
7
+ FORMATTER_CONFIG_TIP =
8
+ <<-TIP
9
+ You can add config to ui_config.yml to acquire advanced features
10
+ SQL_TRACER_FORMAT_SQL_ENABLED: true # show formatted and colored sql, default false
11
+ SQL_TRACER_FORMAT_STACK_ENABLED: true # show colored stack, default fasle
12
+ SQL_TRACER_SKIP_LIB: false # show all paths including the files in ruby gems, default true
13
+ TIP
14
+
15
+ def self.start_print
16
+ puts HEADER_PROMPT
17
+ end
18
+
19
+ def self.end_print
20
+ puts FOOTER_PROMPT
21
+ end
22
+
23
+ def self.print_tips
24
+ puts 'SqlTracer is watching and will capture backtrace when sql is executed.'
25
+ puts FORMATTER_CONFIG_TIP
26
+ end
27
+
28
+ def self.print_sql(sql)
29
+ puts 'SQL:'
30
+ return sql if sql.blank?
31
+ formatted_sql = ' ' << (Helper.format_sql_enabled? ? colorize(sql_formatter.format(sql.squeeze(' ')), 32) : sql)
32
+ puts formatted_sql
33
+ end
34
+
35
+ def self.print_backtrace(backtrace)
36
+ puts Helper.should_skip_lib? ? 'Backtrace: note that paths in ruby libs have been hidden' : 'Backtrace:'
37
+ backtrace.each do |line|
38
+ line = format_line(line) if Helper.format_stack_enabled?
39
+ (puts ' ' << line) if line.present?
40
+ end
41
+ end
42
+
43
+ def self.print_all(sql, backtrace)
44
+ Formatter.start_print
45
+ Formatter.print_sql(sql)
46
+ Formatter.print_backtrace(backtrace)
47
+ Formatter.end_print
48
+ end
49
+
50
+ def self.remove_lib_path(backtrace)
51
+ backtrace.map do |path|
52
+ next if Helper.should_skip_lib? && path.include?('/.rvm/gems/')
53
+ path
54
+ end.compact
55
+ end
56
+
57
+ def self.sql_formatter
58
+ return @formatter if @formatter
59
+ rule = AnbtSql::Rule.new
60
+ rule.keyword = AnbtSql::Rule::KEYWORD_UPPER_CASE
61
+ rule.function_names += %w(count sum)
62
+ rule.indent_string = ' '
63
+ @formatter = AnbtSql::Formatter.new(rule)
64
+ end
65
+
66
+ def self.format_line(line)
67
+ parts = line.match(/^(?<file>.+):(?<line>\d+):in `(?<code>.*)'$/)
68
+ if parts
69
+ "#{colorize(parts[:file], 32)}:#{colorize(parts[:line], 36)}:#{colorize(parts[:code], 31)}"
70
+ else
71
+ "#{colorize(line, 32)}"
72
+ end
73
+ end
74
+
75
+ def self.colorize(text, color_code)
76
+ "\e[#{color_code}m#{text}\e[0m"
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,29 @@
1
+ require 'anbt-sql-formatter/formatter'
2
+
3
+ module SqlTracer
4
+ class Helper
5
+ class << self
6
+ def format_sql_enabled?
7
+ @format_sql_enabled ||= (UIConfig.get(:SQL_TRACER_FORMAT_SQL_ENABLED) || false)
8
+ end
9
+
10
+ def format_stack_enabled?
11
+ @format_stack_enabled ||= (UIConfig.get(:SQL_TRACER_FORMAT_STACK_ENABLED) || false)
12
+ end
13
+
14
+ def should_skip_lib?
15
+ @should_skip_lib ||= (UIConfig.get(:SQL_TRACER_SKIP_LIB) || true)
16
+ end
17
+
18
+ def should_skip_by_keywords?(sql)
19
+ @keywords ||= (UIConfig.get(:SQL_TRACER_SQL_FILTER) || [])
20
+ return false if @keywords.blank?
21
+ @keywords.any? { |keyword| sql.include?(keyword) }
22
+ end
23
+
24
+ def disable_console_output?
25
+ @console_output_disabled ||= (UIConfig.get(:SQL_TRACER_CONSOLE_OUTPUT_DISABLED) || false)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module SqlTracer
2
+ module RequestLogger
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ after_filter :persist_reqeust_logger
6
+
7
+ def persist_reqeust_logger
8
+ SqlTracer::SqlStack.url = "#{request.method} #{request.path}"
9
+ SqlTracer::SqlStack.push
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'anbt-sql-formatter/formatter'
2
+
3
+ module SqlTracer
4
+ module SqlLogger
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ alias_method :execute_without_sql_tracer, :execute
8
+
9
+ def execute(*args)
10
+ begin
11
+ sql = args.first
12
+
13
+ if sql =~ /^\s*(insert|update|delete)\s/i && !Helper.should_skip_by_keywords?(sql)
14
+ backtrace = Thread.current.backtrace
15
+ backtrace = Formatter.remove_lib_path(backtrace) if Helper.should_skip_lib?
16
+ Formatter.print_all(sql, backtrace) unless Helper.disable_console_output?
17
+ SqlTracer::SqlStack.sql_stack << { :sql => sql, :stack => backtrace }
18
+ end
19
+ rescue => e
20
+ Rails.logger.error "Failed to log sql in SqlTracer. Error: #{e.message}"
21
+ Rails.logger.error e.backtrace.join("\n")
22
+ end
23
+ execute_without_sql_tracer(*args)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'fileutils'
2
+
3
+ module SqlTracer
4
+ class SqlStack
5
+ @url = ''
6
+ @sql_stack = []
7
+ @sql_stacks = []
8
+
9
+ class << self
10
+ attr_accessor :url, :sql_stack, :sql_stacks
11
+
12
+ def clear
13
+ @sql_stacks = []
14
+ end
15
+
16
+ def push
17
+ @sql_stacks << { :url => "[#{Time.now.strftime('%H:%M:%S')}] #{@url}", :sqls => @sql_stack }
18
+ @sql_stack = []
19
+ @url = ''
20
+ end
21
+
22
+ def to_json
23
+ @sql_stacks.to_json
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module SqlTracer
2
+ VERSION = '0.0.7'
3
+ end
data/lib/sql_tracer.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'sql_tracer/engine'
2
+
3
+ module SqlTracer
4
+ autoload :SqlLogger, 'sql_tracer/sql_logger'
5
+ autoload :Helper, 'sql_tracer/helper'
6
+ autoload :Formatter, 'sql_tracer/formatter'
7
+ autoload :RequestLogger, 'sql_tracer/request_logger'
8
+ autoload :SqlStack, 'sql_tracer/sql_stack'
9
+ end
10
+
11
+ # why does not work when wrapped in block ActiveSupport.on_load(:active_record) do
12
+ begin
13
+ require 'active_record/connection_adapters/mysql2_adapter'
14
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:include, SqlTracer::SqlLogger)
15
+ SqlTracer::Formatter.print_tips
16
+
17
+ ActiveSupport.on_load(:action_controller) do
18
+ ActionController::Base.send(:include, SqlTracer::RequestLogger)
19
+ end
20
+ rescue LoadError, NameError => e
21
+ Rails.logger.error('Failed to injuect SqlTracer to ActiveRecord due to :' + e.message)
22
+ end
23
+
24
+
25
+
26
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - xiaoye
@@ -30,7 +30,20 @@ email:
30
30
  executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
- files: []
33
+ files:
34
+ - app/assets/stylesheets/sql_tracer/application.css
35
+ - app/assets/stylesheets/sql_tracer/style.css
36
+ - app/controllers/sql_tracer/sql_tracer_controller.rb
37
+ - app/views/sql_tracer/sql_tracer/index.html.erb
38
+ - config/routes.rb
39
+ - lib/sql_tracer.rb
40
+ - lib/sql_tracer/engine.rb
41
+ - lib/sql_tracer/formatter.rb
42
+ - lib/sql_tracer/helper.rb
43
+ - lib/sql_tracer/request_logger.rb
44
+ - lib/sql_tracer/sql_logger.rb
45
+ - lib/sql_tracer/sql_stack.rb
46
+ - lib/sql_tracer/version.rb
34
47
  homepage: https://git.dev.fwmrm.net/qzhang/sql_tracer
35
48
  licenses: []
36
49
  metadata: {}