sqreen 1.20.1-java → 1.20.4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +25 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/attack_detected.html +1 -2
  7. data/lib/sqreen/condition_evaluator.rb +8 -2
  8. data/lib/sqreen/configuration.rb +1 -1
  9. data/lib/sqreen/deferred_logger.rb +50 -14
  10. data/lib/sqreen/deprecation.rb +38 -0
  11. data/lib/sqreen/events/request_record.rb +0 -1
  12. data/lib/sqreen/frameworks/generic.rb +9 -0
  13. data/lib/sqreen/frameworks/rails.rb +0 -7
  14. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  15. data/lib/sqreen/graft/call.rb +76 -18
  16. data/lib/sqreen/graft/callback.rb +1 -1
  17. data/lib/sqreen/graft/hook.rb +187 -85
  18. data/lib/sqreen/graft/hook_point.rb +1 -1
  19. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  20. data/lib/sqreen/legacy/old_event_submission_strategy.rb +2 -1
  21. data/lib/sqreen/log.rb +3 -2
  22. data/lib/sqreen/log/loggable.rb +1 -0
  23. data/lib/sqreen/logger.rb +24 -0
  24. data/lib/sqreen/metrics_store.rb +11 -0
  25. data/lib/sqreen/null_logger.rb +22 -0
  26. data/lib/sqreen/remote_command.rb +1 -0
  27. data/lib/sqreen/rules.rb +8 -4
  28. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  29. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  30. data/lib/sqreen/rules/rule_cb.rb +2 -0
  31. data/lib/sqreen/rules/waf_cb.rb +3 -3
  32. data/lib/sqreen/runner.rb +28 -2
  33. data/lib/sqreen/version.rb +1 -1
  34. data/lib/sqreen/weave/budget.rb +46 -0
  35. data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
  36. data/lib/sqreen/worker.rb +6 -2
  37. metadata +7 -6
  38. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -21,7 +21,7 @@ module Sqreen
21
21
  end
22
22
 
23
23
  def call(*args, &block)
24
- Sqreen::Graft.logger.debug { "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}" }
24
+ # Sqreen::Graft.logger.debug { "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}" } if Sqreen::Graft.logger.debug?
25
25
  return if @disabled
26
26
  @block.call(*args, &block)
27
27
  end
@@ -21,6 +21,13 @@ module Sqreen
21
21
  self[hook_point, strategy].add(&block)
22
22
  end
23
23
 
24
+ def self.ignore
25
+ Thread.current[:sqreen_hook_entered] = true
26
+ yield
27
+ ensure
28
+ Thread.current[:sqreen_hook_entered] = false
29
+ end
30
+
24
31
  attr_reader :point
25
32
 
26
33
  def initialize(hook_point, dependency_test = nil, strategy = :chain)
@@ -46,27 +53,31 @@ module Sqreen
46
53
  end
47
54
 
48
55
  def before(tag = nil, opts = {}, &block)
49
- return @before.sort_by(&:rank) if block.nil?
56
+ return @before if block.nil?
50
57
 
51
58
  @before << Callback.new(callback_name(:before, tag), opts, &block)
59
+ @before.sort_by!(&:rank)
52
60
  end
53
61
 
54
62
  def after(tag = nil, opts = {}, &block)
55
- return @after.sort_by(&:rank) if block.nil?
63
+ return @after if block.nil?
56
64
 
57
65
  @after << Callback.new(callback_name(:after, tag), opts, &block)
66
+ @after.sort_by!(&:rank)
58
67
  end
59
68
 
60
69
  def raised(tag = nil, opts = {}, &block)
61
- return @raised.sort_by(&:rank) if block.nil?
70
+ return @raised if block.nil?
62
71
 
63
72
  @raised << Callback.new(callback_name(:raised, tag), opts, &block)
73
+ @raised.sort_by!(&:rank)
64
74
  end
65
75
 
66
76
  def ensured(tag = nil, opts = {}, &block)
67
- return @ensured.sort_by(&:rank) if block.nil?
77
+ return @ensured if block.nil?
68
78
 
69
79
  @ensured << Callback.new(callback_name(:ensured, tag), opts, &block)
80
+ @ensured.sort_by!(&:rank)
70
81
  end
71
82
 
72
83
  def depends_on(&block)
@@ -109,11 +120,25 @@ module Sqreen
109
120
  @before = []
110
121
  @after = []
111
122
  @raised = []
123
+ @ensured = []
112
124
  end
113
125
 
114
126
  def self.wrapper(hook)
127
+ timed_hooks_proc = proc do |t|
128
+ if (request = Thread.current[:sqreen_http_request])
129
+ request[:timed_hooks] << t if request[:timed_level] >= 1
130
+ end
131
+ end
132
+ timed_callbacks_proc = proc do |t|
133
+ if (request = Thread.current[:sqreen_http_request])
134
+ request[:timed_callbacks] << t if request[:timed_level] >= 1
135
+ end
136
+ end
137
+
115
138
  Proc.new do |*args, &block|
116
- if Thread.current[:sqreen_hook_entered] || Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:time_budget_expended]
139
+ request = Thread.current[:sqreen_http_request]
140
+
141
+ if Thread.current[:sqreen_hook_entered]
117
142
  if hook.point.super?
118
143
  return super(*args, &block)
119
144
  else
@@ -121,49 +146,88 @@ module Sqreen
121
146
  end
122
147
  end
123
148
 
124
- Timer.new(hook.point) do |t|
125
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks] << t
126
- end.measure do |chrono|
127
- Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} caller:#{Kernel.caller[2].inspect}" }
149
+ if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
150
+ if request[:timed_level] >= 2
151
+ begin
152
+ request[:skipped_callbacks].concat(hook.before)
153
+
154
+ if hook.point.super?
155
+ return super(*args, &block)
156
+ else
157
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
158
+ end
159
+ rescue ::Exception # rubocop:disable Lint/RescueException
160
+ request[:skipped_callbacks].concat(hook.raised)
161
+ raise
162
+ else
163
+ request[:skipped_callbacks].concat(hook.after)
164
+ ensure
165
+ request[:skipped_callbacks].concat(hook.ensured)
166
+ end
167
+ else
168
+ if hook.point.super? # rubocop:disable Style/IfInsideElse
169
+ return super(*args, &block)
170
+ else
171
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
172
+ end
173
+ end
174
+ end
175
+
176
+ hook_point_super = hook.point.super?
177
+ logger = Sqreen::Graft.logger
178
+ logger_debug = Sqreen::Graft.logger.debug?
179
+
180
+ Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
181
+ # budget implies request
182
+ # TODO: make budget depend on a generic context (currently "request")
183
+ budget = request[:time_budget] if request
184
+ if budget
185
+ budget_threshold = request[:time_budget_threshold]
186
+ budget_ratio = request[:time_budget_ratio]
187
+ sqreen_timer = request[:sqreen_timer]
188
+ request_timer = request[:request_timer]
189
+ end
128
190
 
129
- budget = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:time_budget]
130
- timer = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timer] if budget
131
191
  hooked_call = HookedCall.new(self, args)
132
192
 
133
193
  begin
134
- timer.start if timer
135
- Thread.current[:sqreen_hook_entered] = true
136
-
137
- # TODO: make Call have #ball to throw by cb
138
- # TODO: can Call be the ball? r = catch(Call.new, &c)
139
- # TODO: is catch return value a Call? a #dispatch?
140
- # TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
141
- # TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
142
- # TODO: HookCall x CallbackCollection#each_with_call x Flow
143
- # TODO: TimedHookCall TimedCallbackCall
144
- # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
145
-
146
- Timer.new("#{hook.point}@before") do |t|
147
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_before] << t
148
- end.measure do |before_chrono|
194
+ begin
195
+ sqreen_timer.start if budget
196
+ Thread.current[:sqreen_hook_entered] = true
197
+
198
+ # TODO: make Call have #ball to throw by cb
199
+ # TODO: can Call be the ball? r = catch(Call.new, &c)
200
+ # TODO: is catch return value a Call? a #dispatch?
201
+ # TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
202
+ # TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
203
+ # TODO: HookCall x CallbackCollection#each_with_call x Flow
204
+ # TODO: TimedHookCall TimedCallbackCall
205
+ # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
206
+
207
+ request_elapsed = request_timer.elapsed if budget
208
+
149
209
  hook.before.each do |c|
150
210
  next if c.ignore && c.ignore.call
151
211
 
152
- if timer && !c.mandatory
153
- remaining = budget - timer.elapsed
212
+ if budget && !c.mandatory
213
+ sqreen_elapsed = sqreen_timer.elapsed
214
+ if budget_ratio && !request[:time_budget_expended]
215
+ fixed_budget = budget_threshold
216
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
217
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
218
+ else
219
+ remaining = budget_threshold - sqreen_elapsed
220
+ end
154
221
  unless remaining > 0
155
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
222
+ request[:skipped_callbacks] << c
223
+ request[:time_budget_expended] = true
156
224
  next
157
225
  end
158
226
  end
159
227
 
160
228
  flow = catch(Ball.new) do |ball|
161
- Timer.new(c.name) do |t|
162
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
163
- end.measure do
164
- before_chrono.ignore do
165
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
166
- end
229
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
230
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
167
231
  end
168
232
  end
169
233
 
@@ -173,52 +237,59 @@ module Sqreen
173
237
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
174
238
  break if flow.break?
175
239
  end unless hook.disabled?
240
+ rescue StandardError => e
241
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
242
+ Sqreen::RemoteException.record(e) if Sqreen.queue
176
243
  end
177
244
 
178
245
  raise hooked_call.raise if hooked_call.raising
179
246
  return hooked_call.return if hooked_call.returning
180
247
  ensure
181
248
  Thread.current[:sqreen_hook_entered] = false
182
- timer.stop if timer
183
- end
249
+ sqreen_timer.stop if budget
250
+ end unless hook.before.empty?
184
251
 
185
252
  begin
186
253
  chrono.ignore do
187
- if hook.point.super?
254
+ if hook_point_super
188
255
  hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
189
256
  else
190
257
  hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
191
258
  end
192
259
  end
193
260
  rescue ::Exception => e # rubocop:disable Lint/RescueException
194
- timer.start if timer
195
- Thread.current[:sqreen_hook_entered] = true
196
- hooked_call.raised = e
261
+ begin
262
+ sqreen_timer.start if budget
263
+ Thread.current[:sqreen_hook_entered] = true
264
+ hooked_call.raised = e
197
265
 
198
- Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" }
199
- raise if hook.raised.empty?
266
+ logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
267
+ raise if hook.raised.empty?
268
+
269
+ request_elapsed = request_timer.elapsed if budget
200
270
 
201
- Timer.new("#{hook.point}@raised") do |t|
202
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_raised] << t
203
- end.measure do |raised_chrono|
204
271
  hook.raised.each do |c|
205
272
  next if c.ignore && c.ignore.call
206
273
 
207
- if timer && !c.mandatory
208
- remaining = budget - timer.elapsed
274
+ if budget && !c.mandatory
275
+ sqreen_elapsed = sqreen_timer.elapsed
276
+ if budget_ratio && !request[:time_budget_expended]
277
+ fixed_budget = budget_threshold
278
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
279
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
280
+ else
281
+ remaining = budget_threshold - sqreen_elapsed
282
+ end
209
283
  unless remaining > 0
210
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
284
+ request[:skipped_callbacks] << c
285
+ request[:time_budget_expended] = true
211
286
  next
212
287
  end
213
288
  end
214
289
 
215
290
  flow = catch(Ball.new) do |ball|
216
- Timer.new(c.name) do |t|
217
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
218
- end.measure do
219
- raised_chrono.ignore do
220
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, hooked_call.raised), ball)
221
- end
291
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
292
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, hooked_call.raised), ball)
222
293
  end
223
294
  end
224
295
 
@@ -228,6 +299,9 @@ module Sqreen
228
299
  hooked_call.retrying = true if flow.retry?
229
300
  break if flow.break?
230
301
  end unless hook.disabled?
302
+ rescue StandardError => e
303
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
304
+ Sqreen::RemoteException.record(e) if Sqreen.queue
231
305
  end
232
306
 
233
307
  retry if hooked_call.retrying
@@ -235,30 +309,37 @@ module Sqreen
235
309
  return hooked_call.return if hooked_call.returning
236
310
  raise
237
311
  else
238
- timer.start if timer
239
- Thread.current[:sqreen_hook_entered] = true
312
+ begin
313
+ sqreen_timer.start if budget
314
+ Thread.current[:sqreen_hook_entered] = true
315
+
316
+ # TODO: hooked_call.returning should be always false here?
317
+ return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
318
+
319
+ request_elapsed = request_timer.elapsed if budget
240
320
 
241
- Timer.new("#{hook.point}@after") do |t|
242
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_after] << t
243
- end.measure do |after_chrono|
244
321
  hook.after.each do |c|
245
322
  next if c.ignore && c.ignore.call
246
323
 
247
- if timer && !c.mandatory
248
- remaining = budget - timer.elapsed
324
+ if budget && !c.mandatory
325
+ sqreen_elapsed = sqreen_timer.elapsed
326
+ if budget_ratio && !request[:time_budget_expended]
327
+ fixed_budget = budget_threshold
328
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
329
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
330
+ else
331
+ remaining = budget_threshold - sqreen_elapsed
332
+ end
249
333
  unless remaining > 0
250
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
334
+ request[:skipped_callbacks] << c
335
+ request[:time_budget_expended] = true
251
336
  next
252
337
  end
253
338
  end
254
339
 
255
340
  flow = catch(Ball.new) do |ball|
256
- Timer.new(c.name) do |t|
257
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
258
- end.measure do
259
- after_chrono.ignore do
260
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
261
- end
341
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
342
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
262
343
  end
263
344
  end
264
345
 
@@ -267,34 +348,48 @@ module Sqreen
267
348
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
268
349
  break if flow.break?
269
350
  end unless hook.disabled?
351
+ rescue StandardError => e
352
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
353
+ Sqreen::RemoteException.record(e) if Sqreen.queue
270
354
  end
271
355
 
272
356
  raise hooked_call.raise if hooked_call.raising
273
357
  return hooked_call.returning ? hooked_call.return : hooked_call.returned
274
358
  ensure
275
- # TODO: timer.start if someone has thrown?
359
+ begin
360
+ # TODO: sqreen_timer.start if someone has thrown?
361
+ # TODO: sqreen_timer.stop at end of rescue+else?
362
+ # TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
363
+ # TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
364
+
365
+ # TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
366
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
367
+
368
+ # done at either rescue or else
369
+ # request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
276
370
 
277
- Timer.new("#{hook.point}@ensured") do |t|
278
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_ensured] << t
279
- end.measure do |ensured_chrono|
280
371
  hook.ensured.each do |c|
281
372
  next if c.ignore && c.ignore.call
282
373
 
283
- if timer && !c.mandatory
284
- remaining = budget - timer.elapsed
374
+ if budget && !c.mandatory
375
+ sqreen_elapsed = sqreen_timer.elapsed
376
+ if budget_ratio && !request[:time_budget_expended]
377
+ fixed_budget = budget_threshold
378
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
379
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
380
+ else
381
+ remaining = budget_threshold - sqreen_elapsed
382
+ end
285
383
  unless remaining > 0
286
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
384
+ request[:skipped_callbacks] << c
385
+ request[:time_budget_expended] = true
287
386
  next
288
387
  end
289
388
  end
290
389
 
291
390
  flow = catch(Ball.new) do |ball|
292
- Timer.new(c.name) do |t|
293
- Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
294
- end.measure do
295
- ensured_chrono.ignore do
296
- c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
297
- end
391
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
392
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
298
393
  end
299
394
  end
300
395
 
@@ -302,11 +397,18 @@ module Sqreen
302
397
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
303
398
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
304
399
  break if flow.break?
305
- end unless hook.disabled?
400
+ end unless hook.ensured.empty? || hook.disabled?
401
+
402
+ Thread.current[:sqreen_hook_entered] = false
403
+ sqreen_timer.stop if budget
404
+ rescue StandardError => e
405
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
406
+ Sqreen::RemoteException.record(e) if Sqreen.queue
306
407
  end
307
408
 
308
- Thread.current[:sqreen_hook_entered] = false
309
- timer.stop if timer
409
+ # TODO: should we run the following?
410
+ # raise hooked_call.raise if hooked_call.raising
411
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned
310
412
  end
311
413
  end # chrono
312
414
  end
@@ -42,7 +42,7 @@ module Sqreen
42
42
  end
43
43
 
44
44
  def to_s
45
- "#{@klass_name}#{@method_kind == :instance_method ? '#' : '.'}#{@method_name}"
45
+ @to_s ||= "#{@klass_name}#{@method_kind == :instance_method ? '#' : '.'}#{@method_name}"
46
46
  end
47
47
 
48
48
  def exist?
@@ -109,7 +109,7 @@ module Legacy
109
109
  break if res.is_a?(Hash) && res[:skip_rem_cbs]
110
110
  rescue StandardError => e
111
111
  Sqreen.log.warn { "we catch an exception: #{e.inspect}" }
112
- Sqreen.log.debug e.backtrace
112
+ Sqreen.log.debug { e.backtrace }
113
113
  if cb.respond_to?(:record_exception)
114
114
  cb.record_exception(e)
115
115
  else
@@ -162,7 +162,7 @@ module Legacy
162
162
  returns << res
163
163
  rescue StandardError => e
164
164
  Sqreen.log.warn { "we catch an exception: #{e.inspect}" }
165
- Sqreen.log.debug e.backtrace
165
+ Sqreen.log.debug { e.backtrace }
166
166
  if cb.respond_to?(:record_exception)
167
167
  cb.record_exception(e)
168
168
  else
@@ -597,16 +597,25 @@ module Legacy
597
597
  method = cb.method
598
598
  key = [klass, method]
599
599
 
600
+ if (call_count = ENV['SQREEN_DEBUG_CALL_COUNT'])
601
+ call_count = JSON.parse(call_count)
602
+ if cb.respond_to?(:rule_name) && call_count.key?(cb.rule_name)
603
+ count = call_count[cb.rule_name]
604
+ Sqreen.log.debug { "override rule:#{cb.rule_name} call_count:#{count.inspect}" }
605
+ cb.instance_eval { @call_count_interval = call_count[cb.rule_name] }
606
+ end
607
+ end
608
+
600
609
  @@record_request_hookpoints << key if cb.is_a?(Sqreen::Rules::RecordRequestContext)
601
610
 
602
611
  already_overriden = @@overriden_methods.include? key
603
612
 
604
613
  if !already_overriden
605
614
  if is_class_method?(klass, method)
606
- Sqreen.log.debug "overriding class method for #{cb}"
615
+ Sqreen.log.debug { "overriding class method for #{cb}" }
607
616
  success = override_class_method(klass, method)
608
617
  elsif is_instance_method?(klass, method)
609
- Sqreen.log.debug "overriding instance method for #{cb}"
618
+ Sqreen.log.debug { "overriding instance method for #{cb}" }
610
619
  success = override_instance_method(klass, method)
611
620
  else
612
621
  # FIXME: Override define_method and other dynamic ways to
@@ -623,7 +632,7 @@ module Legacy
623
632
 
624
633
  @@overriden_methods += [key] if success
625
634
  else
626
- Sqreen.log.debug "#{key} was already overriden"
635
+ Sqreen.log.debug { "#{key} was already overriden" }
627
636
  end
628
637
 
629
638
  if klass != Object && klass != Kernel && !Sqreen.features['instrument_all_instances'] && !defined?(::JRUBY_VERSION)
@@ -638,7 +647,7 @@ module Legacy
638
647
  end
639
648
  end
640
649
 
641
- Sqreen.log.debug "Adding callback #{cb} for #{klass} #{method}"
650
+ Sqreen.log.debug { "Adding callback #{cb} for #{klass} #{method}" }
642
651
  @@registered_callbacks.add(cb)
643
652
  @@unovertimable_hookpoints << key unless cb.overtimeable
644
653
  @@instrumented_pid = Process.pid
@@ -659,7 +668,7 @@ module Legacy
659
668
 
660
669
  already_overriden = @@overriden_methods.include? key
661
670
  unless already_overriden
662
- Sqreen.log.debug "#{key} apparently not overridden"
671
+ Sqreen.log.debug { "#{key} apparently not overridden" }
663
672
  end
664
673
 
665
674
  defined_cbs = @@registered_callbacks.get(klass, method).flatten
@@ -667,17 +676,17 @@ module Legacy
667
676
  nb_removed = 0
668
677
  defined_cbs.each do |found_cb|
669
678
  if found_cb == cb
670
- Sqreen.log.debug "Removing callback #{found_cb}"
679
+ Sqreen.log.debug { "Removing callback #{found_cb}" }
671
680
  @@registered_callbacks.remove(found_cb)
672
681
  nb_removed += 1
673
682
  else
674
- Sqreen.log.debug "Not removing callback #{found_cb} (remains #{defined_cbs.size} cbs)"
683
+ Sqreen.log.debug { "Not removing callback #{found_cb} (remains #{defined_cbs.size} cbs)" }
675
684
  end
676
685
  end
677
686
 
678
687
  return unless nb_removed == defined_cbs.size
679
688
 
680
- Sqreen.log.debug "Removing overriden method #{key}"
689
+ Sqreen.log.debug { "Removing overriden method #{key}" }
681
690
  @@overriden_methods.delete(key)
682
691
 
683
692
  if is_class_method?(klass, method)
@@ -705,6 +714,7 @@ module Legacy
705
714
  remove_callback_no_lock(cb)
706
715
  end
707
716
  Sqreen.instrumentation_ready = false
717
+ Sqreen.log.info('Instrumentation deactivated')
708
718
  end
709
719
  end
710
720
 
@@ -757,6 +767,8 @@ module Legacy
757
767
  ### globally declare instrumentation ready
758
768
  ### from within instance method? not even thread local?
759
769
  Sqreen.instrumentation_ready = true
770
+
771
+ Sqreen.log.info('Instrumentation activated')
760
772
  end
761
773
 
762
774
  def initialize(metrics_engine = nil)