active_record-sql_analyzer 0.1.0 → 0.2.0
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 +4 -4
- data/lib/active_record/sql_analyzer/background_processor.rb +6 -2
- data/lib/active_record/sql_analyzer/configuration.rb +7 -0
- data/lib/active_record/sql_analyzer/monkeypatches/query.rb +67 -39
- data/lib/active_record/sql_analyzer/redacted_logger.rb +29 -5
- data/lib/active_record/sql_analyzer/version.rb +1 -1
- data/spec/active_record/sql_analyzer/background_processor_spec.rb +3 -3
- data/spec/active_record/sql_analyzer/end_to_end_spec.rb +123 -41
- data/spec/active_record/sql_analyzer/redacted_logger_spec.rb +63 -31
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7987c2a8d140ea3c6dc2b13effcad2f810562171
|
4
|
+
data.tar.gz: b62f71e7563c8e92d11ee5baac0ad8722d669780
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df3a2c7ea88fbc0b86cc9fdcc9fe94c52c9727ff436ade3f6f06869932f842c24101c33cbefe6bae77e381275572dcb6d4e724741c3bb18cd1ac5888d99da971
|
7
|
+
data.tar.gz: 158608b3e248858f41a0084a6787432932e4860f41d48f876fd6cbbf58c9cad8a2eb7bbbb877eca8092fe50af1c7cc3d5aaf38518771111c6183de0b741b920b
|
@@ -19,8 +19,12 @@ module ActiveRecord
|
|
19
19
|
def process_queue
|
20
20
|
event = @queue.pop
|
21
21
|
|
22
|
-
event[:
|
23
|
-
|
22
|
+
event[:calls] = event[:calls].map do |call|
|
23
|
+
{
|
24
|
+
caller: SqlAnalyzer.config[:backtrace_filter_proc].call(call[:caller]),
|
25
|
+
sql: SqlAnalyzer.config[:sql_redactor_complex_proc].call(call[:sql].dup)
|
26
|
+
}
|
27
|
+
end
|
24
28
|
|
25
29
|
logger = event.delete(:logger)
|
26
30
|
logger.filter_event(event)
|
@@ -117,6 +117,12 @@ module ActiveRecord
|
|
117
117
|
@options[:ambiguous_backtrace_lines] = lines
|
118
118
|
end
|
119
119
|
|
120
|
+
# Disable transaction consolidation. With transaction consolidation enabled, the logger will log full transactions
|
121
|
+
# as single statements.
|
122
|
+
def disable_consolidate_transactions
|
123
|
+
@config[:consolidate_transactions] = false
|
124
|
+
end
|
125
|
+
|
120
126
|
def [](key)
|
121
127
|
@options[key]
|
122
128
|
end
|
@@ -169,6 +175,7 @@ module ActiveRecord
|
|
169
175
|
@options[:analyzers] = []
|
170
176
|
@options[:logger_root_path] = Rails.root.join('log')
|
171
177
|
@options[:backtrace_filter_proc] = BacktraceFilter.proc
|
178
|
+
@options[:consolidate_transactions] = true
|
172
179
|
end
|
173
180
|
end
|
174
181
|
end
|
@@ -4,27 +4,27 @@ module ActiveRecord
|
|
4
4
|
module SqlAnalyzer
|
5
5
|
module Monkeypatches
|
6
6
|
module Query
|
7
|
+
QueryAnalyzerCall = Struct.new(:sql, :caller)
|
8
|
+
|
7
9
|
def execute(sql, *args)
|
8
10
|
return super unless SqlAnalyzer.config
|
9
11
|
|
10
|
-
|
12
|
+
if @_query_analyzer_private_transaction_queue
|
13
|
+
@_query_analyzer_private_transaction_queue << QueryAnalyzerCall.new(sql, caller)
|
14
|
+
else
|
15
|
+
safe_sql = nil
|
16
|
+
|
17
|
+
SqlAnalyzer.config[:analyzers].each do |analyzer|
|
18
|
+
if SqlAnalyzer.config[:should_log_sample_proc].call(analyzer[:name])
|
19
|
+
# This is here rather than above intentionally.
|
20
|
+
# We assume we're not going to be analyzing 100% of queries and want to only re-encode
|
21
|
+
# when it's actually relevant.
|
22
|
+
safe_sql ||= sql.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
11
23
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# when it's actually relevant.
|
17
|
-
safe_sql ||= sql.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
18
|
-
|
19
|
-
if safe_sql =~ analyzer[:table_regex]
|
20
|
-
SqlAnalyzer.background_processor << {
|
21
|
-
sql: safe_sql,
|
22
|
-
caller: caller,
|
23
|
-
logger: analyzer[:logger_instance],
|
24
|
-
tag: Thread.current[:_ar_analyzer_tag],
|
25
|
-
request_path: Thread.current[:_ar_analyzer_request_path],
|
26
|
-
transaction: @_query_analyzer_private_transaction_uuid
|
27
|
-
}
|
24
|
+
if safe_sql =~ analyzer[:table_regex]
|
25
|
+
SqlAnalyzer.background_processor <<
|
26
|
+
_query_analyzer_private_query_stanza([QueryAnalyzerCall.new(safe_sql, caller)], analyzer)
|
27
|
+
end
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -32,39 +32,67 @@ module ActiveRecord
|
|
32
32
|
super
|
33
33
|
end
|
34
34
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
# Drain the transaction query queue. Log the current transaction out to any logger that samples it.
|
36
|
+
def _query_analyzer_private_drain_transaction_queue
|
37
|
+
reencoded_calls = nil
|
38
|
+
|
39
|
+
SqlAnalyzer.config[:analyzers].each do |analyzer|
|
40
|
+
if SqlAnalyzer.config[:should_log_sample_proc].call(analyzer[:name])
|
41
|
+
# Again, trying to only re-encode and join strings if the transaction is actually
|
42
|
+
# sampled.
|
43
|
+
reencoded_calls ||= @_query_analyzer_private_transaction_queue.map do |call|
|
44
|
+
QueryAnalyzerCall.new(call.sql.encode(Encoding::UTF_8, invalid: :replace, undef: :replace), call.caller)
|
45
|
+
end
|
46
|
+
|
47
|
+
matching_calls = reencoded_calls.select do |call|
|
48
|
+
(call.sql =~ /^(UPDATE|INSERT|DELETE)/) || (call.sql =~ analyzer[:table_regex])
|
49
|
+
end
|
50
|
+
|
51
|
+
if matching_calls.any?
|
52
|
+
# Add back in the begin and commit statements, using the correct call stack references
|
53
|
+
if reencoded_calls.first.sql == 'BEGIN'
|
54
|
+
matching_calls.unshift(reencoded_calls.first)
|
55
|
+
end
|
56
|
+
|
57
|
+
if ['COMMIT', 'ROLLBACK'].include? reencoded_calls.last.sql
|
58
|
+
matching_calls << reencoded_calls.last
|
59
|
+
end
|
60
|
+
|
61
|
+
SqlAnalyzer.background_processor <<
|
62
|
+
_query_analyzer_private_query_stanza(matching_calls, analyzer)
|
63
|
+
end
|
64
|
+
end
|
42
65
|
end
|
43
66
|
end
|
44
67
|
|
45
|
-
#
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
68
|
+
# Helper method to construct the event for a query or transaction.
|
69
|
+
# safe_sql [string]: SQL statement or combined SQL statement for transaction
|
70
|
+
# calls: A list of QueryAnalyzerCall objects to be turned into call hashes
|
71
|
+
def _query_analyzer_private_query_stanza(calls, analyzer)
|
72
|
+
{
|
73
|
+
# Calls are of the format {sql: String, caller: String}
|
74
|
+
calls: calls.map(&:to_h),
|
75
|
+
logger: analyzer[:logger_instance],
|
76
|
+
tag: Thread.current[:_ar_analyzer_tag],
|
77
|
+
request_path: Thread.current[:_ar_analyzer_request_path],
|
78
|
+
}
|
51
79
|
end
|
52
80
|
|
53
81
|
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
54
|
-
|
82
|
+
must_clear_transaction = false
|
55
83
|
|
56
|
-
if
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
84
|
+
if SqlAnalyzer.config[:consolidate_transactions]
|
85
|
+
if @_query_analyzer_private_transaction_queue.nil?
|
86
|
+
must_clear_transaction = true
|
87
|
+
@_query_analyzer_private_transaction_queue = []
|
88
|
+
end
|
61
89
|
end
|
62
90
|
|
63
91
|
super
|
64
92
|
ensure
|
65
|
-
if
|
66
|
-
|
67
|
-
@
|
93
|
+
if must_clear_transaction
|
94
|
+
_query_analyzer_private_drain_transaction_queue
|
95
|
+
@_query_analyzer_private_transaction_queue = nil
|
68
96
|
end
|
69
97
|
end
|
70
98
|
end
|
@@ -3,19 +3,43 @@ module ActiveRecord
|
|
3
3
|
class RedactedLogger < CompactLogger
|
4
4
|
def filter_event(event)
|
5
5
|
# Determine if we're doing extended tracing or only the first
|
6
|
-
|
7
|
-
|
6
|
+
calls = event.delete(:calls).map do |call|
|
7
|
+
{sql: filter_sql(call[:sql]), caller: filter_caller(call[:caller])}
|
8
|
+
end
|
9
|
+
|
10
|
+
# De-duplicate redacted calls to avoid many transactions with looping "N+1" queries.
|
11
|
+
calls.uniq!
|
12
|
+
|
13
|
+
event[:sql] = calls.map { |call| call[:sql] }
|
14
|
+
event[:caller] = calls.map { |call| call[:caller] }.join(';; ')
|
15
|
+
|
16
|
+
if event[:sql].size == 1
|
17
|
+
event[:sql] = event[:sql].first
|
8
18
|
else
|
9
|
-
event[:
|
19
|
+
event[:sql] = event[:sql].join('; ') + ';'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_caller(kaller)
|
24
|
+
kaller = if config[:ambiguous_tracers].any? { |regex| kaller.first =~ regex }
|
25
|
+
kaller[0, config[:ambiguous_backtrace_lines]].join(", ")
|
26
|
+
else
|
27
|
+
kaller.first
|
10
28
|
end
|
11
29
|
|
12
30
|
config[:backtrace_redactors].each do |redactor|
|
13
|
-
|
31
|
+
kaller.gsub!(redactor.search, redactor.replace)
|
14
32
|
end
|
15
33
|
|
34
|
+
kaller
|
35
|
+
end
|
36
|
+
|
37
|
+
def filter_sql(sql)
|
16
38
|
config[:sql_redactors].each do |redactor|
|
17
|
-
|
39
|
+
sql.gsub!(redactor.search, redactor.replace)
|
18
40
|
end
|
41
|
+
|
42
|
+
sql
|
19
43
|
end
|
20
44
|
end
|
21
45
|
end
|
@@ -3,7 +3,7 @@ RSpec.describe ActiveRecord::SqlAnalyzer::BackgroundProcessor do
|
|
3
3
|
|
4
4
|
let(:instance) { described_class.new }
|
5
5
|
|
6
|
-
let(:event) { {caller: "CALLER", sql: "SQL", logger: logger} }
|
6
|
+
let(:event) { {calls: [{caller: "CALLER", sql: "SQL"}], logger: logger} }
|
7
7
|
|
8
8
|
let(:logger) do
|
9
9
|
Class.new do
|
@@ -34,10 +34,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::BackgroundProcessor do
|
|
34
34
|
|
35
35
|
expect(logger.events).to eq(
|
36
36
|
[
|
37
|
-
{
|
37
|
+
calls: [{
|
38
38
|
caller: "BFP CALLER",
|
39
39
|
sql: "CSRP SQL"
|
40
|
-
}
|
40
|
+
}]
|
41
41
|
]
|
42
42
|
)
|
43
43
|
end
|
@@ -55,6 +55,11 @@ RSpec.describe "End to End" do
|
|
55
55
|
wait_for_pop
|
56
56
|
end
|
57
57
|
|
58
|
+
def transaction
|
59
|
+
DBConnection.connection.transaction { yield }
|
60
|
+
wait_for_pop
|
61
|
+
end
|
62
|
+
|
58
63
|
it "does not log with a non-matching table" do
|
59
64
|
execute "SELECT * FROM nonmatching_table"
|
60
65
|
|
@@ -105,63 +110,135 @@ RSpec.describe "End to End" do
|
|
105
110
|
end
|
106
111
|
|
107
112
|
it "logs multiple queries in a transaction correctly" do
|
108
|
-
|
109
|
-
|
110
|
-
|
113
|
+
transaction do
|
114
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
115
|
+
execute "SELECT * FROM matching_table WHERE test_string = 'abc'"
|
111
116
|
end
|
112
117
|
|
113
|
-
|
114
|
-
|
115
|
-
|
118
|
+
2.times do
|
119
|
+
transaction do
|
120
|
+
execute "SELECT * FROM matching_table WHERE test_string = 'abc'"
|
121
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
122
|
+
end
|
116
123
|
end
|
117
124
|
|
118
|
-
|
119
|
-
|
120
|
-
str_like_sha = log_reverse_hash[2]
|
121
|
-
id_gt_sha = log_reverse_hash[1]
|
122
|
-
|
123
|
-
expect(log_def_hash[id_gt_sha]["sql"]).to include("id = [REDACTED] and id = [REDACTED]")
|
124
|
-
expect(log_def_hash[str_like_sha]["sql"]).to include("test_string LIKE '[REDACTED]'")
|
125
|
-
expect(log_def_hash[id_gt_sha]["transaction"]).to eq(log_def_hash[str_like_sha]["transaction"])
|
125
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
126
|
+
transaction_executed_twice_sha = log_reverse_hash[2]
|
126
127
|
|
127
|
-
expect(log_def_hash[
|
128
|
-
|
129
|
-
|
128
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
129
|
+
"BEGIN; " \
|
130
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
131
|
+
"SELECT * FROM matching_table WHERE test_string = '[REDACTED]'; " \
|
132
|
+
"COMMIT;")
|
130
133
|
|
131
|
-
expect(log_def_hash[
|
134
|
+
expect(log_def_hash[transaction_executed_twice_sha]["sql"]).to eq(
|
135
|
+
"BEGIN; " \
|
136
|
+
"SELECT * FROM matching_table WHERE test_string = '[REDACTED]'; " \
|
137
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
138
|
+
"COMMIT;")
|
132
139
|
end
|
133
140
|
|
134
141
|
it "Logs nested transactions correctly" do
|
135
|
-
|
142
|
+
transaction do
|
136
143
|
execute "SELECT * FROM matching_table WHERE id = 4321"
|
137
|
-
|
138
|
-
|
144
|
+
transaction do
|
145
|
+
execute "SELECT * FROM matching_table WHERE test_string = 'abc'"
|
139
146
|
end
|
140
147
|
end
|
141
148
|
|
149
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
150
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
151
|
+
"BEGIN; " \
|
152
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
153
|
+
"SELECT * FROM matching_table WHERE test_string = '[REDACTED]'; " \
|
154
|
+
"COMMIT;")
|
155
|
+
end
|
142
156
|
|
143
|
-
|
144
|
-
|
157
|
+
it "Logs transactions with inserts correctly" do
|
158
|
+
transaction do
|
159
|
+
execute "INSERT INTO matching_table (test_string) VALUES ('test_value')"
|
160
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
161
|
+
end
|
145
162
|
|
146
|
-
|
147
|
-
expect(log_def_hash[
|
163
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
164
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
165
|
+
"BEGIN; " \
|
166
|
+
"INSERT INTO matching_table (REDACTED_COLUMNS) VALUES ('[REDACTED]'); " \
|
167
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
168
|
+
"COMMIT;")
|
148
169
|
end
|
149
170
|
|
150
|
-
it "Logs
|
151
|
-
|
171
|
+
it "Logs mixed matching-nonmatching selects correctly" do
|
172
|
+
transaction do
|
152
173
|
execute "SELECT * FROM matching_table WHERE id = 4321"
|
174
|
+
execute "SELECT * FROM nonmatching_table WHERE id = 4321"
|
153
175
|
end
|
154
176
|
|
155
|
-
|
177
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
156
178
|
|
157
|
-
|
158
|
-
|
179
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
180
|
+
"BEGIN; " \
|
181
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
182
|
+
"COMMIT;")
|
183
|
+
end
|
159
184
|
|
160
|
-
|
161
|
-
|
185
|
+
it "Logs transaction with repeated selects correctly" do
|
186
|
+
transaction do
|
187
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
188
|
+
['blah', 'bloo'].each do |s|
|
189
|
+
execute "SELECT * FROM matching_table WHERE test_string = '#{s}'"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
162
194
|
|
163
|
-
expect(log_def_hash[
|
164
|
-
|
195
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
196
|
+
"BEGIN; " \
|
197
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
198
|
+
"SELECT * FROM matching_table WHERE test_string = '[REDACTED]'; " \
|
199
|
+
"COMMIT;")
|
200
|
+
end
|
201
|
+
|
202
|
+
it "Logs transaction with repeated inserts correctly" do
|
203
|
+
transaction do
|
204
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
205
|
+
2.times do
|
206
|
+
execute "INSERT INTO matching_table (test_string) VALUES ('test_value')"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
211
|
+
|
212
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
213
|
+
"BEGIN; " \
|
214
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
215
|
+
"INSERT INTO matching_table (REDACTED_COLUMNS) VALUES ('[REDACTED]'); " \
|
216
|
+
"COMMIT;")
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
it "Logs mixed matching-nonmatching with inserts correctly" do
|
221
|
+
transaction do
|
222
|
+
execute "SELECT * FROM matching_table WHERE id = 4321"
|
223
|
+
execute "INSERT INTO nonmatching_table (id) VALUES (1)"
|
224
|
+
end
|
225
|
+
|
226
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
227
|
+
|
228
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
229
|
+
"BEGIN; " \
|
230
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
231
|
+
"INSERT INTO nonmatching_table (REDACTED_COLUMNS) VALUES ('[REDACTED]'); " \
|
232
|
+
"COMMIT;")
|
233
|
+
end
|
234
|
+
|
235
|
+
it "Does not log nonmatching-only queries" do
|
236
|
+
transaction do
|
237
|
+
execute "SELECT * FROM nonmatching_table WHERE id = 4321"
|
238
|
+
execute "SELECT * FROM nonmatching_table WHERE id = 4321"
|
239
|
+
end
|
240
|
+
|
241
|
+
expect(log_def_hash.size).to eq(0)
|
165
242
|
end
|
166
243
|
|
167
244
|
context "Selectively sampling" do
|
@@ -179,24 +256,29 @@ RSpec.describe "End to End" do
|
|
179
256
|
|
180
257
|
expect(log_def_hash.size).to eq(1)
|
181
258
|
expect(log_def_hash.map { |_hash, query| query['sql'] }).to eq([
|
182
|
-
"SELECT * FROM matching_table WHERE id = [REDACTED]"])
|
259
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'"])
|
183
260
|
end
|
184
261
|
|
185
262
|
it "Samples some but not other whole transactions" do
|
186
|
-
|
263
|
+
transaction do
|
187
264
|
execute "SELECT * FROM matching_table WHERE id = 1"
|
188
265
|
execute "SELECT * FROM matching_table WHERE test_string = 'abc'"
|
189
266
|
end
|
190
267
|
|
191
|
-
|
268
|
+
transaction do
|
192
269
|
execute "SELECT * FROM matching_table WHERE id = 1 and test_string = 'abc'"
|
193
270
|
execute "SELECT * FROM matching_table WHERE id > 4 and id < 8"
|
194
271
|
end
|
195
272
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
273
|
+
|
274
|
+
transaction_executed_once_sha = log_reverse_hash[1]
|
275
|
+
|
276
|
+
expect(log_def_hash.size).to eq(1)
|
277
|
+
expect(log_def_hash[transaction_executed_once_sha]["sql"]).to eq(
|
278
|
+
"BEGIN; " \
|
279
|
+
"SELECT * FROM matching_table WHERE id = '[REDACTED]'; " \
|
280
|
+
"SELECT * FROM matching_table WHERE test_string = '[REDACTED]'; " \
|
281
|
+
"COMMIT;")
|
200
282
|
end
|
201
283
|
end
|
202
284
|
|
@@ -21,8 +21,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
21
21
|
[/erb_erb_[0-9]+_[0-9]+/, ""]
|
22
22
|
]
|
23
23
|
end
|
24
|
+
|
24
25
|
# All raw SQL should be valid :)
|
25
|
-
|
26
|
+
event_sql_list = event[:calls].map { |call| call[:sql] }
|
27
|
+
expect { event_sql_list.map { |sql| parser.scan_str sql } }.not_to raise_exception if event_sql_list.any?(&:present?)
|
26
28
|
end
|
27
29
|
|
28
30
|
after do
|
@@ -33,8 +35,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
33
35
|
context "ambiguous backtraces" do
|
34
36
|
let(:event) do
|
35
37
|
{
|
36
|
-
|
37
|
-
|
38
|
+
calls: [{
|
39
|
+
caller: %w(ambiguous foo bar),
|
40
|
+
sql: "",
|
41
|
+
}]
|
38
42
|
}
|
39
43
|
end
|
40
44
|
|
@@ -52,8 +56,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
52
56
|
context "backtrace" do
|
53
57
|
let(:event) do
|
54
58
|
{
|
55
|
-
|
56
|
-
|
59
|
+
calls: [{
|
60
|
+
caller: %w(foo-bar-erb_erb_1_5),
|
61
|
+
sql: "",
|
62
|
+
}]
|
57
63
|
}
|
58
64
|
end
|
59
65
|
|
@@ -65,8 +71,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
65
71
|
context "sql quoted" do
|
66
72
|
let(:event) do
|
67
73
|
{
|
68
|
-
|
69
|
-
|
74
|
+
calls: [{
|
75
|
+
caller: [""],
|
76
|
+
sql: "SELECT * FROM foo WHERE name = 'hello\\'s name'",
|
77
|
+
}]
|
70
78
|
}
|
71
79
|
end
|
72
80
|
|
@@ -78,8 +86,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
78
86
|
context "sql quoted multiple WHERE" do
|
79
87
|
let(:event) do
|
80
88
|
{
|
81
|
-
|
82
|
-
|
89
|
+
calls: [{
|
90
|
+
caller: [""],
|
91
|
+
sql: "SELECT * FROM foo WHERE name = 'hello\\'s name' AND age = '21'",
|
92
|
+
}]
|
83
93
|
}
|
84
94
|
end
|
85
95
|
|
@@ -92,8 +102,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
92
102
|
context "sql escaped and quoted" do
|
93
103
|
let(:event) do
|
94
104
|
{
|
95
|
-
|
96
|
-
|
105
|
+
calls: [{
|
106
|
+
caller: [""],
|
107
|
+
sql: "SELECT * FROM foo WHERE name = 'hello\\\'s name'",
|
108
|
+
}]
|
97
109
|
}
|
98
110
|
end
|
99
111
|
|
@@ -105,8 +117,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
105
117
|
context "sql case insensitivity" do
|
106
118
|
let(:event) do
|
107
119
|
{
|
108
|
-
|
109
|
-
|
120
|
+
calls: [{
|
121
|
+
caller: [""],
|
122
|
+
sql: "SELECT * FROM foo WHERE name lIkE 'hello'",
|
123
|
+
}]
|
110
124
|
}
|
111
125
|
end
|
112
126
|
|
@@ -118,8 +132,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
118
132
|
context "sql" do
|
119
133
|
let(:event) do
|
120
134
|
{
|
121
|
-
|
122
|
-
|
135
|
+
calls: [{
|
136
|
+
caller: [""],
|
137
|
+
sql: "SELECT * FROM foo WHERE id = 1234",
|
138
|
+
}]
|
123
139
|
}
|
124
140
|
end
|
125
141
|
|
@@ -131,8 +147,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
131
147
|
context "like quoted" do
|
132
148
|
let(:event) do
|
133
149
|
{
|
134
|
-
|
135
|
-
|
150
|
+
calls: [{
|
151
|
+
caller: [""],
|
152
|
+
sql: %{SELECT * FROM foo WHERE name LIKE 'A \\'quoted\\' value.' OR name LIKE "another ""quoted"" \\"value\\""},
|
153
|
+
}]
|
136
154
|
}
|
137
155
|
end
|
138
156
|
|
@@ -144,8 +162,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
144
162
|
context "like escaped and quoted" do
|
145
163
|
let(:event) do
|
146
164
|
{
|
147
|
-
|
148
|
-
|
165
|
+
calls: [{
|
166
|
+
caller: [""],
|
167
|
+
sql: "SELECT * FROM foo WHERE name LIKE 'A \\\'quoted\\\' value.'",
|
168
|
+
}]
|
149
169
|
}
|
150
170
|
end
|
151
171
|
|
@@ -157,8 +177,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
157
177
|
context "in quoted" do
|
158
178
|
let(:event) do
|
159
179
|
{
|
160
|
-
|
161
|
-
|
180
|
+
calls: [{
|
181
|
+
caller: [""],
|
182
|
+
sql: "SELECT * FROM foo WHERE name IN ('A ''quoted'' value.')",
|
183
|
+
}]
|
162
184
|
}
|
163
185
|
end
|
164
186
|
|
@@ -170,8 +192,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
170
192
|
context "in escaped and quoted" do
|
171
193
|
let(:event) do
|
172
194
|
{
|
173
|
-
|
174
|
-
|
195
|
+
calls: [{
|
196
|
+
caller: [""],
|
197
|
+
sql: %{SELECT * FROM foo WHERE name IN ('A ''quoted'' value.', "another ""quoted"" \\"value\\"")},
|
198
|
+
}]
|
175
199
|
}
|
176
200
|
end
|
177
201
|
|
@@ -183,8 +207,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
183
207
|
context "between strings" do
|
184
208
|
let(:event) do
|
185
209
|
{
|
186
|
-
|
187
|
-
|
210
|
+
calls: [{
|
211
|
+
caller: [""],
|
212
|
+
sql: "SELECT * FROM foo WHERE name BETWEEN 'A value.' AND 'Another value'",
|
213
|
+
}]
|
188
214
|
}
|
189
215
|
end
|
190
216
|
|
@@ -196,8 +222,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
196
222
|
context "between strings with escaped quotes" do
|
197
223
|
let(:event) do
|
198
224
|
{
|
199
|
-
|
200
|
-
|
225
|
+
calls: [{
|
226
|
+
caller: [""],
|
227
|
+
sql: "SELECT * FROM foo WHERE name BETWEEN 'A ''quoted'' value.' AND 'Another \\'value\\''",
|
228
|
+
}]
|
201
229
|
}
|
202
230
|
end
|
203
231
|
|
@@ -209,8 +237,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
209
237
|
context "in with = and other where clauses" do
|
210
238
|
let(:event) do
|
211
239
|
{
|
212
|
-
|
213
|
-
|
240
|
+
calls: [{
|
241
|
+
caller: [""],
|
242
|
+
sql: "SELECT * FROM foo WHERE name IN ('value=') AND name = 'value'",
|
243
|
+
}]
|
214
244
|
}
|
215
245
|
end
|
216
246
|
|
@@ -222,8 +252,10 @@ RSpec.describe ActiveRecord::SqlAnalyzer::RedactedLogger do
|
|
222
252
|
context "insert" do
|
223
253
|
let(:event) do
|
224
254
|
{
|
225
|
-
|
226
|
-
|
255
|
+
calls: [{
|
256
|
+
caller: [""],
|
257
|
+
sql: "INSERT INTO `boom` (`bam`, `foo`) VALUES ('howdy', 'dowdy')",
|
258
|
+
}]
|
227
259
|
}
|
228
260
|
end
|
229
261
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record-sql_analyzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zachary Anker
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-08-
|
12
|
+
date: 2016-08-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|