sqreen 1.23.0 → 1.23.1
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/CHANGELOG.md +4 -0
- data/lib/sqreen/graft/hook.rb +7 -295
- data/lib/sqreen/graft/hook.ruby_2.rb +305 -0
- data/lib/sqreen/graft/hook.ruby_3.rb +305 -0
- data/lib/sqreen/graft/hook_point.rb +6 -6
- data/lib/sqreen/graft/hook_point.ruby_2.rb +18 -0
- data/lib/sqreen/graft/hook_point.ruby_3.rb +19 -0
- data/lib/sqreen/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a273f9a80bf30fbd4dcf8fc21551639e1c8df66b3dfa8be2d16e8ad5d58d4b47
|
4
|
+
data.tar.gz: cf2ff1d623cdae5a55ec39bc9959351775375836e5cf2ae71844bb7ee51b5ab6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68e69af0cb0d36971cea1ea58919372840faa792d620d99e7bc9e30c6afc39aa2aa564cf529a8f67bea8da79411c5d270df9e27a4db71e015461eba1c2d9f788
|
7
|
+
data.tar.gz: 14b82f5804bf6da658f44c3702ca8f877811cb0363f754703f2f7efa6440c0ffaa1a19e09c17c96f920e2855382041420069169bed8d7a77d1b4285d083af3ca
|
data/CHANGELOG.md
CHANGED
data/lib/sqreen/graft/hook.rb
CHANGED
@@ -4,9 +4,8 @@
|
|
4
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
5
|
|
6
6
|
require 'sqreen/graft'
|
7
|
-
require 'sqreen/graft/call'
|
8
|
-
require 'sqreen/graft/callback'
|
9
7
|
require 'sqreen/graft/hook_point'
|
8
|
+
require 'sqreen/graft/callback'
|
10
9
|
|
11
10
|
module Sqreen
|
12
11
|
module Graft
|
@@ -124,299 +123,12 @@ module Sqreen
|
|
124
123
|
@raised = []
|
125
124
|
@ensured = []
|
126
125
|
end
|
127
|
-
|
128
|
-
def self.wrapper(hook)
|
129
|
-
timed_hooks_proc = proc do |t|
|
130
|
-
if (request = Thread.current[:sqreen_http_request])
|
131
|
-
request[:timed_hooks] << t if request[:timed_level] >= 1
|
132
|
-
end
|
133
|
-
end
|
134
|
-
timed_callbacks_proc = proc do |t|
|
135
|
-
if (request = Thread.current[:sqreen_http_request])
|
136
|
-
request[:timed_callbacks] << t if request[:timed_level] >= 1
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
Proc.new do |*args, &block|
|
141
|
-
request = Thread.current[:sqreen_http_request]
|
142
|
-
|
143
|
-
if Thread.current[:sqreen_hook_entered]
|
144
|
-
if hook.point.super?
|
145
|
-
return super(*args, &block)
|
146
|
-
else
|
147
|
-
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
|
152
|
-
if request[:timed_level] >= 2
|
153
|
-
begin
|
154
|
-
request[:skipped_callbacks].concat(hook.before)
|
155
|
-
|
156
|
-
if hook.point.super?
|
157
|
-
return super(*args, &block)
|
158
|
-
else
|
159
|
-
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
160
|
-
end
|
161
|
-
rescue ::Exception # rubocop:disable Lint/RescueException
|
162
|
-
request[:skipped_callbacks].concat(hook.raised)
|
163
|
-
raise
|
164
|
-
else
|
165
|
-
request[:skipped_callbacks].concat(hook.after)
|
166
|
-
ensure
|
167
|
-
request[:skipped_callbacks].concat(hook.ensured)
|
168
|
-
end
|
169
|
-
else
|
170
|
-
if hook.point.super? # rubocop:disable Style/IfInsideElse
|
171
|
-
return super(*args, &block)
|
172
|
-
else
|
173
|
-
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
hook_point_super = hook.point.super?
|
179
|
-
logger = Sqreen::Graft.logger
|
180
|
-
logger_debug = Sqreen::Graft.logger.debug?
|
181
|
-
|
182
|
-
Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
|
183
|
-
# budget implies request
|
184
|
-
# TODO: make budget depend on a generic context (currently "request")
|
185
|
-
budget = request[:time_budget] if request
|
186
|
-
if budget
|
187
|
-
budget_threshold = request[:time_budget_threshold]
|
188
|
-
budget_ratio = request[:time_budget_ratio]
|
189
|
-
sqreen_timer = request[:sqreen_timer]
|
190
|
-
request_timer = request[:request_timer]
|
191
|
-
end
|
192
|
-
|
193
|
-
hooked_call = HookedCall.new(self, args)
|
194
|
-
|
195
|
-
begin
|
196
|
-
begin
|
197
|
-
sqreen_timer.start if budget
|
198
|
-
Thread.current[:sqreen_hook_entered] = true
|
199
|
-
|
200
|
-
# TODO: make Call have #ball to throw by cb
|
201
|
-
# TODO: can Call be the ball? r = catch(Call.new, &c)
|
202
|
-
# TODO: is catch return value a Call? a #dispatch?
|
203
|
-
# TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
|
204
|
-
# TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
|
205
|
-
# TODO: HookCall x CallbackCollection#each_with_call x Flow
|
206
|
-
# TODO: TimedHookCall TimedCallbackCall
|
207
|
-
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
208
|
-
|
209
|
-
request_elapsed = request_timer.elapsed if budget
|
210
|
-
|
211
|
-
hook.before.each do |c|
|
212
|
-
next if c.ignore && c.ignore.call
|
213
|
-
|
214
|
-
if budget && !c.mandatory
|
215
|
-
sqreen_elapsed = sqreen_timer.elapsed
|
216
|
-
if budget_ratio && !request[:time_budget_expended]
|
217
|
-
fixed_budget = budget_threshold
|
218
|
-
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
219
|
-
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
220
|
-
else
|
221
|
-
remaining = budget_threshold - sqreen_elapsed
|
222
|
-
end
|
223
|
-
unless remaining > 0
|
224
|
-
request[:skipped_callbacks] << c
|
225
|
-
request[:time_budget_expended] = true
|
226
|
-
next
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
flow = catch(Ball.new) do |ball|
|
231
|
-
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
232
|
-
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
next unless c.flow && flow.is_a?(Flow)
|
237
|
-
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
238
|
-
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
239
|
-
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
240
|
-
break if flow.break?
|
241
|
-
end unless hook.disabled?
|
242
|
-
rescue StandardError => e
|
243
|
-
Sqreen::Weave.logger.debug { "exception:#{e.class} when:before message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
244
|
-
Sqreen::RemoteException.record(e) if Sqreen.queue
|
245
|
-
end
|
246
|
-
|
247
|
-
raise hooked_call.raise if hooked_call.raising
|
248
|
-
return hooked_call.return if hooked_call.returning
|
249
|
-
ensure
|
250
|
-
Thread.current[:sqreen_hook_entered] = false
|
251
|
-
sqreen_timer.stop if budget
|
252
|
-
end unless hook.before.empty?
|
253
|
-
|
254
|
-
begin
|
255
|
-
chrono.ignore do
|
256
|
-
if hook_point_super
|
257
|
-
hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
258
|
-
else
|
259
|
-
hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
260
|
-
end
|
261
|
-
end
|
262
|
-
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
263
|
-
begin
|
264
|
-
sqreen_timer.start if budget
|
265
|
-
Thread.current[:sqreen_hook_entered] = true
|
266
|
-
hooked_call.raised = e
|
267
|
-
|
268
|
-
logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
|
269
|
-
|
270
|
-
# TODO: early escape causes raise too early then caught by ensure which mistakenly reports legit errors to sqreen
|
271
|
-
# raise if hook.raised.empty?
|
272
|
-
|
273
|
-
request_elapsed = request_timer.elapsed if budget
|
274
|
-
|
275
|
-
hook.raised.each do |c|
|
276
|
-
next if c.ignore && c.ignore.call
|
277
|
-
|
278
|
-
if budget && !c.mandatory
|
279
|
-
sqreen_elapsed = sqreen_timer.elapsed
|
280
|
-
if budget_ratio && !request[:time_budget_expended]
|
281
|
-
fixed_budget = budget_threshold
|
282
|
-
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
283
|
-
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
284
|
-
else
|
285
|
-
remaining = budget_threshold - sqreen_elapsed
|
286
|
-
end
|
287
|
-
unless remaining > 0
|
288
|
-
request[:skipped_callbacks] << c
|
289
|
-
request[:time_budget_expended] = true
|
290
|
-
next
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
flow = catch(Ball.new) do |ball|
|
295
|
-
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
296
|
-
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)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
next unless c.flow && flow.is_a?(Flow)
|
301
|
-
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
302
|
-
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
303
|
-
hooked_call.retrying = true if flow.retry?
|
304
|
-
break if flow.break?
|
305
|
-
end unless hook.disabled?
|
306
|
-
rescue StandardError => e
|
307
|
-
Sqreen::Weave.logger.debug { "exception:#{e.class} when:raised message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
308
|
-
Sqreen::RemoteException.record(e) if Sqreen.queue
|
309
|
-
end
|
310
|
-
|
311
|
-
retry if hooked_call.retrying
|
312
|
-
raise hooked_call.raise if hooked_call.raising
|
313
|
-
return hooked_call.return if hooked_call.returning
|
314
|
-
raise
|
315
|
-
else
|
316
|
-
begin
|
317
|
-
sqreen_timer.start if budget
|
318
|
-
Thread.current[:sqreen_hook_entered] = true
|
319
|
-
|
320
|
-
# TODO: hooked_call.returning should be always false here?
|
321
|
-
return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
|
322
|
-
|
323
|
-
request_elapsed = request_timer.elapsed if budget
|
324
|
-
|
325
|
-
hook.after.each do |c|
|
326
|
-
next if c.ignore && c.ignore.call
|
327
|
-
|
328
|
-
if budget && !c.mandatory
|
329
|
-
sqreen_elapsed = sqreen_timer.elapsed
|
330
|
-
if budget_ratio && !request[:time_budget_expended]
|
331
|
-
fixed_budget = budget_threshold
|
332
|
-
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
333
|
-
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
334
|
-
else
|
335
|
-
remaining = budget_threshold - sqreen_elapsed
|
336
|
-
end
|
337
|
-
unless remaining > 0
|
338
|
-
request[:skipped_callbacks] << c
|
339
|
-
request[:time_budget_expended] = true
|
340
|
-
next
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
flow = catch(Ball.new) do |ball|
|
345
|
-
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
346
|
-
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)
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
next unless c.flow && flow.is_a?(Flow)
|
351
|
-
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
352
|
-
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
353
|
-
break if flow.break?
|
354
|
-
end unless hook.disabled?
|
355
|
-
rescue StandardError => e
|
356
|
-
Sqreen::Weave.logger.debug { "exception:#{e.class} when:after message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
357
|
-
Sqreen::RemoteException.record(e) if Sqreen.queue
|
358
|
-
end
|
359
|
-
|
360
|
-
raise hooked_call.raise if hooked_call.raising
|
361
|
-
return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
362
|
-
ensure
|
363
|
-
begin
|
364
|
-
# TODO: sqreen_timer.start if someone has thrown?
|
365
|
-
# TODO: sqreen_timer.stop at end of rescue+else?
|
366
|
-
# TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
|
367
|
-
# TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
|
368
|
-
|
369
|
-
# TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
|
370
|
-
# return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
|
371
|
-
|
372
|
-
# done at either rescue or else
|
373
|
-
# request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
|
374
|
-
|
375
|
-
hook.ensured.each do |c|
|
376
|
-
next if c.ignore && c.ignore.call
|
377
|
-
|
378
|
-
if budget && !c.mandatory
|
379
|
-
sqreen_elapsed = sqreen_timer.elapsed
|
380
|
-
if budget_ratio && !request[:time_budget_expended]
|
381
|
-
fixed_budget = budget_threshold
|
382
|
-
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
383
|
-
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
384
|
-
else
|
385
|
-
remaining = budget_threshold - sqreen_elapsed
|
386
|
-
end
|
387
|
-
unless remaining > 0
|
388
|
-
request[:skipped_callbacks] << c
|
389
|
-
request[:time_budget_expended] = true
|
390
|
-
next
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
flow = catch(Ball.new) do |ball|
|
395
|
-
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
396
|
-
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)
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
next unless c.flow && flow.is_a?(Flow)
|
401
|
-
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
402
|
-
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
403
|
-
break if flow.break?
|
404
|
-
end unless hook.ensured.empty? || hook.disabled?
|
405
|
-
|
406
|
-
Thread.current[:sqreen_hook_entered] = false
|
407
|
-
sqreen_timer.stop if budget
|
408
|
-
rescue StandardError => e
|
409
|
-
Sqreen::Weave.logger.debug { "exception:#{e.class} when:ensured message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
410
|
-
Sqreen::RemoteException.record(e) if Sqreen.queue
|
411
|
-
end
|
412
|
-
|
413
|
-
# TODO: should we run the following?
|
414
|
-
# raise hooked_call.raise if hooked_call.raising
|
415
|
-
# return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
416
|
-
end
|
417
|
-
end # chrono
|
418
|
-
end
|
419
|
-
end
|
420
126
|
end
|
421
127
|
end
|
422
128
|
end
|
129
|
+
|
130
|
+
if RUBY_VERSION =~ /^2\./
|
131
|
+
load File.join(__dir__, 'hook.ruby_2.rb')
|
132
|
+
else
|
133
|
+
load File.join(__dir__, 'hook.ruby_3.rb')
|
134
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
require 'sqreen/graft/call'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Graft
|
10
|
+
class Hook
|
11
|
+
def self.wrapper(hook)
|
12
|
+
timed_hooks_proc = proc do |t|
|
13
|
+
if (request = Thread.current[:sqreen_http_request])
|
14
|
+
request[:timed_hooks] << t if request[:timed_level] >= 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
timed_callbacks_proc = proc do |t|
|
18
|
+
if (request = Thread.current[:sqreen_http_request])
|
19
|
+
request[:timed_callbacks] << t if request[:timed_level] >= 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Proc.new do |*args, &block|
|
24
|
+
request = Thread.current[:sqreen_http_request]
|
25
|
+
|
26
|
+
if Thread.current[:sqreen_hook_entered]
|
27
|
+
if hook.point.super?
|
28
|
+
return super(*args, &block)
|
29
|
+
else
|
30
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
|
35
|
+
if request[:timed_level] >= 2
|
36
|
+
begin
|
37
|
+
request[:skipped_callbacks].concat(hook.before)
|
38
|
+
|
39
|
+
if hook.point.super?
|
40
|
+
return super(*args, &block)
|
41
|
+
else
|
42
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
43
|
+
end
|
44
|
+
rescue ::Exception # rubocop:disable Lint/RescueException
|
45
|
+
request[:skipped_callbacks].concat(hook.raised)
|
46
|
+
raise
|
47
|
+
else
|
48
|
+
request[:skipped_callbacks].concat(hook.after)
|
49
|
+
ensure
|
50
|
+
request[:skipped_callbacks].concat(hook.ensured)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
if hook.point.super? # rubocop:disable Style/IfInsideElse
|
54
|
+
return super(*args, &block)
|
55
|
+
else
|
56
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
hook_point_super = hook.point.super?
|
62
|
+
logger = Sqreen::Graft.logger
|
63
|
+
logger_debug = Sqreen::Graft.logger.debug?
|
64
|
+
|
65
|
+
Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
|
66
|
+
# budget implies request
|
67
|
+
# TODO: make budget depend on a generic context (currently "request")
|
68
|
+
budget = request[:time_budget] if request
|
69
|
+
if budget
|
70
|
+
budget_threshold = request[:time_budget_threshold]
|
71
|
+
budget_ratio = request[:time_budget_ratio]
|
72
|
+
sqreen_timer = request[:sqreen_timer]
|
73
|
+
request_timer = request[:request_timer]
|
74
|
+
end
|
75
|
+
|
76
|
+
hooked_call = HookedCall.new(self, args)
|
77
|
+
|
78
|
+
begin
|
79
|
+
begin
|
80
|
+
sqreen_timer.start if budget
|
81
|
+
Thread.current[:sqreen_hook_entered] = true
|
82
|
+
|
83
|
+
# TODO: make Call have #ball to throw by cb
|
84
|
+
# TODO: can Call be the ball? r = catch(Call.new, &c)
|
85
|
+
# TODO: is catch return value a Call? a #dispatch?
|
86
|
+
# TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
|
87
|
+
# TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
|
88
|
+
# TODO: HookCall x CallbackCollection#each_with_call x Flow
|
89
|
+
# TODO: TimedHookCall TimedCallbackCall
|
90
|
+
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
91
|
+
|
92
|
+
request_elapsed = request_timer.elapsed if budget
|
93
|
+
|
94
|
+
hook.before.each do |c|
|
95
|
+
next if c.ignore && c.ignore.call
|
96
|
+
|
97
|
+
if budget && !c.mandatory
|
98
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
99
|
+
if budget_ratio && !request[:time_budget_expended]
|
100
|
+
fixed_budget = budget_threshold
|
101
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
102
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
103
|
+
else
|
104
|
+
remaining = budget_threshold - sqreen_elapsed
|
105
|
+
end
|
106
|
+
unless remaining > 0
|
107
|
+
request[:skipped_callbacks] << c
|
108
|
+
request[:time_budget_expended] = true
|
109
|
+
next
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
flow = catch(Ball.new) do |ball|
|
114
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
115
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
next unless c.flow && flow.is_a?(Flow)
|
120
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
121
|
+
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
122
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
123
|
+
break if flow.break?
|
124
|
+
end unless hook.disabled?
|
125
|
+
rescue StandardError => e
|
126
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:before message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
127
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
128
|
+
end
|
129
|
+
|
130
|
+
raise hooked_call.raise if hooked_call.raising
|
131
|
+
return hooked_call.return if hooked_call.returning
|
132
|
+
ensure
|
133
|
+
Thread.current[:sqreen_hook_entered] = false
|
134
|
+
sqreen_timer.stop if budget
|
135
|
+
end unless hook.before.empty?
|
136
|
+
|
137
|
+
begin
|
138
|
+
chrono.ignore do
|
139
|
+
if hook_point_super
|
140
|
+
hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
141
|
+
else
|
142
|
+
hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
146
|
+
begin
|
147
|
+
sqreen_timer.start if budget
|
148
|
+
Thread.current[:sqreen_hook_entered] = true
|
149
|
+
hooked_call.raised = e
|
150
|
+
|
151
|
+
logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
|
152
|
+
|
153
|
+
# TODO: early escape causes raise too early then caught by ensure which mistakenly reports legit errors to sqreen
|
154
|
+
# raise if hook.raised.empty?
|
155
|
+
|
156
|
+
request_elapsed = request_timer.elapsed if budget
|
157
|
+
|
158
|
+
hook.raised.each do |c|
|
159
|
+
next if c.ignore && c.ignore.call
|
160
|
+
|
161
|
+
if budget && !c.mandatory
|
162
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
163
|
+
if budget_ratio && !request[:time_budget_expended]
|
164
|
+
fixed_budget = budget_threshold
|
165
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
166
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
167
|
+
else
|
168
|
+
remaining = budget_threshold - sqreen_elapsed
|
169
|
+
end
|
170
|
+
unless remaining > 0
|
171
|
+
request[:skipped_callbacks] << c
|
172
|
+
request[:time_budget_expended] = true
|
173
|
+
next
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
flow = catch(Ball.new) do |ball|
|
178
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
179
|
+
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)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
next unless c.flow && flow.is_a?(Flow)
|
184
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
185
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
186
|
+
hooked_call.retrying = true if flow.retry?
|
187
|
+
break if flow.break?
|
188
|
+
end unless hook.disabled?
|
189
|
+
rescue StandardError => e
|
190
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:raised message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
191
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
192
|
+
end
|
193
|
+
|
194
|
+
retry if hooked_call.retrying
|
195
|
+
raise hooked_call.raise if hooked_call.raising
|
196
|
+
return hooked_call.return if hooked_call.returning
|
197
|
+
raise
|
198
|
+
else
|
199
|
+
begin
|
200
|
+
sqreen_timer.start if budget
|
201
|
+
Thread.current[:sqreen_hook_entered] = true
|
202
|
+
|
203
|
+
# TODO: hooked_call.returning should be always false here?
|
204
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
|
205
|
+
|
206
|
+
request_elapsed = request_timer.elapsed if budget
|
207
|
+
|
208
|
+
hook.after.each do |c|
|
209
|
+
next if c.ignore && c.ignore.call
|
210
|
+
|
211
|
+
if budget && !c.mandatory
|
212
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
213
|
+
if budget_ratio && !request[:time_budget_expended]
|
214
|
+
fixed_budget = budget_threshold
|
215
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
216
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
217
|
+
else
|
218
|
+
remaining = budget_threshold - sqreen_elapsed
|
219
|
+
end
|
220
|
+
unless remaining > 0
|
221
|
+
request[:skipped_callbacks] << c
|
222
|
+
request[:time_budget_expended] = true
|
223
|
+
next
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
flow = catch(Ball.new) do |ball|
|
228
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
229
|
+
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)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
next unless c.flow && flow.is_a?(Flow)
|
234
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
235
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
236
|
+
break if flow.break?
|
237
|
+
end unless hook.disabled?
|
238
|
+
rescue StandardError => e
|
239
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:after message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
240
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
241
|
+
end
|
242
|
+
|
243
|
+
raise hooked_call.raise if hooked_call.raising
|
244
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
245
|
+
ensure
|
246
|
+
begin
|
247
|
+
# TODO: sqreen_timer.start if someone has thrown?
|
248
|
+
# TODO: sqreen_timer.stop at end of rescue+else?
|
249
|
+
# TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
|
250
|
+
# TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
|
251
|
+
|
252
|
+
# TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
|
253
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
|
254
|
+
|
255
|
+
# done at either rescue or else
|
256
|
+
# request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
|
257
|
+
|
258
|
+
hook.ensured.each do |c|
|
259
|
+
next if c.ignore && c.ignore.call
|
260
|
+
|
261
|
+
if budget && !c.mandatory
|
262
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
263
|
+
if budget_ratio && !request[:time_budget_expended]
|
264
|
+
fixed_budget = budget_threshold
|
265
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
266
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
267
|
+
else
|
268
|
+
remaining = budget_threshold - sqreen_elapsed
|
269
|
+
end
|
270
|
+
unless remaining > 0
|
271
|
+
request[:skipped_callbacks] << c
|
272
|
+
request[:time_budget_expended] = true
|
273
|
+
next
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
flow = catch(Ball.new) do |ball|
|
278
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
279
|
+
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)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
next unless c.flow && flow.is_a?(Flow)
|
284
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
285
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
286
|
+
break if flow.break?
|
287
|
+
end unless hook.ensured.empty? || hook.disabled?
|
288
|
+
|
289
|
+
Thread.current[:sqreen_hook_entered] = false
|
290
|
+
sqreen_timer.stop if budget
|
291
|
+
rescue StandardError => e
|
292
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:ensured message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
293
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
294
|
+
end
|
295
|
+
|
296
|
+
# TODO: should we run the following?
|
297
|
+
# raise hooked_call.raise if hooked_call.raising
|
298
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
299
|
+
end
|
300
|
+
end # chrono
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
require 'sqreen/graft/call'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Graft
|
10
|
+
class Hook
|
11
|
+
def self.wrapper(hook)
|
12
|
+
timed_hooks_proc = proc do |t|
|
13
|
+
if (request = Thread.current[:sqreen_http_request])
|
14
|
+
request[:timed_hooks] << t if request[:timed_level] >= 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
timed_callbacks_proc = proc do |t|
|
18
|
+
if (request = Thread.current[:sqreen_http_request])
|
19
|
+
request[:timed_callbacks] << t if request[:timed_level] >= 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Proc.new do |*args, **kwargs, &block|
|
24
|
+
request = Thread.current[:sqreen_http_request]
|
25
|
+
|
26
|
+
if Thread.current[:sqreen_hook_entered]
|
27
|
+
if hook.point.super?
|
28
|
+
return super(*args, **kwargs, &block)
|
29
|
+
else
|
30
|
+
return hook.point.apply(self, 'sqreen_hook', *args, **kwargs, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
|
35
|
+
if request[:timed_level] >= 2
|
36
|
+
begin
|
37
|
+
request[:skipped_callbacks].concat(hook.before)
|
38
|
+
|
39
|
+
if hook.point.super?
|
40
|
+
return super(*args, **kwargs, &block)
|
41
|
+
else
|
42
|
+
return hook.point.apply(self, 'sqreen_hook', *args, **kwargs, &block)
|
43
|
+
end
|
44
|
+
rescue ::Exception # rubocop:disable Lint/RescueException
|
45
|
+
request[:skipped_callbacks].concat(hook.raised)
|
46
|
+
raise
|
47
|
+
else
|
48
|
+
request[:skipped_callbacks].concat(hook.after)
|
49
|
+
ensure
|
50
|
+
request[:skipped_callbacks].concat(hook.ensured)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
if hook.point.super? # rubocop:disable Style/IfInsideElse
|
54
|
+
return super(*args, **kwargs, &block)
|
55
|
+
else
|
56
|
+
return hook.point.apply(self, 'sqreen_hook', *args, **kwargs, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
hook_point_super = hook.point.super?
|
62
|
+
logger = Sqreen::Graft.logger
|
63
|
+
logger_debug = Sqreen::Graft.logger.debug?
|
64
|
+
|
65
|
+
Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
|
66
|
+
# budget implies request
|
67
|
+
# TODO: make budget depend on a generic context (currently "request")
|
68
|
+
budget = request[:time_budget] if request
|
69
|
+
if budget
|
70
|
+
budget_threshold = request[:time_budget_threshold]
|
71
|
+
budget_ratio = request[:time_budget_ratio]
|
72
|
+
sqreen_timer = request[:sqreen_timer]
|
73
|
+
request_timer = request[:request_timer]
|
74
|
+
end
|
75
|
+
|
76
|
+
hooked_call = HookedCall.new(self, args)
|
77
|
+
|
78
|
+
begin
|
79
|
+
begin
|
80
|
+
sqreen_timer.start if budget
|
81
|
+
Thread.current[:sqreen_hook_entered] = true
|
82
|
+
|
83
|
+
# TODO: make Call have #ball to throw by cb
|
84
|
+
# TODO: can Call be the ball? r = catch(Call.new, &c)
|
85
|
+
# TODO: is catch return value a Call? a #dispatch?
|
86
|
+
# TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
|
87
|
+
# TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
|
88
|
+
# TODO: HookCall x CallbackCollection#each_with_call x Flow
|
89
|
+
# TODO: TimedHookCall TimedCallbackCall
|
90
|
+
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
91
|
+
|
92
|
+
request_elapsed = request_timer.elapsed if budget
|
93
|
+
|
94
|
+
hook.before.each do |c|
|
95
|
+
next if c.ignore && c.ignore.call
|
96
|
+
|
97
|
+
if budget && !c.mandatory
|
98
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
99
|
+
if budget_ratio && !request[:time_budget_expended]
|
100
|
+
fixed_budget = budget_threshold
|
101
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
102
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
103
|
+
else
|
104
|
+
remaining = budget_threshold - sqreen_elapsed
|
105
|
+
end
|
106
|
+
unless remaining > 0
|
107
|
+
request[:skipped_callbacks] << c
|
108
|
+
request[:time_budget_expended] = true
|
109
|
+
next
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
flow = catch(Ball.new) do |ball|
|
114
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
115
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
next unless c.flow && flow.is_a?(Flow)
|
120
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
121
|
+
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
122
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
123
|
+
break if flow.break?
|
124
|
+
end unless hook.disabled?
|
125
|
+
rescue StandardError => e
|
126
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:before message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
127
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
128
|
+
end
|
129
|
+
|
130
|
+
raise hooked_call.raise if hooked_call.raising
|
131
|
+
return hooked_call.return if hooked_call.returning
|
132
|
+
ensure
|
133
|
+
Thread.current[:sqreen_hook_entered] = false
|
134
|
+
sqreen_timer.stop if budget
|
135
|
+
end unless hook.before.empty?
|
136
|
+
|
137
|
+
begin
|
138
|
+
chrono.ignore do
|
139
|
+
if hook_point_super
|
140
|
+
hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), **kwargs, &block)
|
141
|
+
else
|
142
|
+
hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), **kwargs, &block)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
146
|
+
begin
|
147
|
+
sqreen_timer.start if budget
|
148
|
+
Thread.current[:sqreen_hook_entered] = true
|
149
|
+
hooked_call.raised = e
|
150
|
+
|
151
|
+
logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
|
152
|
+
|
153
|
+
# TODO: early escape causes raise too early then caught by ensure which mistakenly reports legit errors to sqreen
|
154
|
+
# raise if hook.raised.empty?
|
155
|
+
|
156
|
+
request_elapsed = request_timer.elapsed if budget
|
157
|
+
|
158
|
+
hook.raised.each do |c|
|
159
|
+
next if c.ignore && c.ignore.call
|
160
|
+
|
161
|
+
if budget && !c.mandatory
|
162
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
163
|
+
if budget_ratio && !request[:time_budget_expended]
|
164
|
+
fixed_budget = budget_threshold
|
165
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
166
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
167
|
+
else
|
168
|
+
remaining = budget_threshold - sqreen_elapsed
|
169
|
+
end
|
170
|
+
unless remaining > 0
|
171
|
+
request[:skipped_callbacks] << c
|
172
|
+
request[:time_budget_expended] = true
|
173
|
+
next
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
flow = catch(Ball.new) do |ball|
|
178
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
179
|
+
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)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
next unless c.flow && flow.is_a?(Flow)
|
184
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
185
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
186
|
+
hooked_call.retrying = true if flow.retry?
|
187
|
+
break if flow.break?
|
188
|
+
end unless hook.disabled?
|
189
|
+
rescue StandardError => e
|
190
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:raised message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
191
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
192
|
+
end
|
193
|
+
|
194
|
+
retry if hooked_call.retrying
|
195
|
+
raise hooked_call.raise if hooked_call.raising
|
196
|
+
return hooked_call.return if hooked_call.returning
|
197
|
+
raise
|
198
|
+
else
|
199
|
+
begin
|
200
|
+
sqreen_timer.start if budget
|
201
|
+
Thread.current[:sqreen_hook_entered] = true
|
202
|
+
|
203
|
+
# TODO: hooked_call.returning should be always false here?
|
204
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
|
205
|
+
|
206
|
+
request_elapsed = request_timer.elapsed if budget
|
207
|
+
|
208
|
+
hook.after.each do |c|
|
209
|
+
next if c.ignore && c.ignore.call
|
210
|
+
|
211
|
+
if budget && !c.mandatory
|
212
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
213
|
+
if budget_ratio && !request[:time_budget_expended]
|
214
|
+
fixed_budget = budget_threshold
|
215
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
216
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
217
|
+
else
|
218
|
+
remaining = budget_threshold - sqreen_elapsed
|
219
|
+
end
|
220
|
+
unless remaining > 0
|
221
|
+
request[:skipped_callbacks] << c
|
222
|
+
request[:time_budget_expended] = true
|
223
|
+
next
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
flow = catch(Ball.new) do |ball|
|
228
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
229
|
+
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)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
next unless c.flow && flow.is_a?(Flow)
|
234
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
235
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
236
|
+
break if flow.break?
|
237
|
+
end unless hook.disabled?
|
238
|
+
rescue StandardError => e
|
239
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:after message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
240
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
241
|
+
end
|
242
|
+
|
243
|
+
raise hooked_call.raise if hooked_call.raising
|
244
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
245
|
+
ensure
|
246
|
+
begin
|
247
|
+
# TODO: sqreen_timer.start if someone has thrown?
|
248
|
+
# TODO: sqreen_timer.stop at end of rescue+else?
|
249
|
+
# TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
|
250
|
+
# TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
|
251
|
+
|
252
|
+
# TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
|
253
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
|
254
|
+
|
255
|
+
# done at either rescue or else
|
256
|
+
# request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
|
257
|
+
|
258
|
+
hook.ensured.each do |c|
|
259
|
+
next if c.ignore && c.ignore.call
|
260
|
+
|
261
|
+
if budget && !c.mandatory
|
262
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
263
|
+
if budget_ratio && !request[:time_budget_expended]
|
264
|
+
fixed_budget = budget_threshold
|
265
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
266
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
267
|
+
else
|
268
|
+
remaining = budget_threshold - sqreen_elapsed
|
269
|
+
end
|
270
|
+
unless remaining > 0
|
271
|
+
request[:skipped_callbacks] << c
|
272
|
+
request[:time_budget_expended] = true
|
273
|
+
next
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
flow = catch(Ball.new) do |ball|
|
278
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
279
|
+
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)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
next unless c.flow && flow.is_a?(Flow)
|
284
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
285
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
286
|
+
break if flow.break?
|
287
|
+
end unless hook.ensured.empty? || hook.disabled?
|
288
|
+
|
289
|
+
Thread.current[:sqreen_hook_entered] = false
|
290
|
+
sqreen_timer.stop if budget
|
291
|
+
rescue StandardError => e
|
292
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} when:ensured message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
293
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
294
|
+
end
|
295
|
+
|
296
|
+
# TODO: should we run the following?
|
297
|
+
# raise hooked_call.raise if hooked_call.raising
|
298
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
299
|
+
end
|
300
|
+
end # chrono
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
@@ -105,12 +105,6 @@ module Sqreen
|
|
105
105
|
@strategy == :prepend
|
106
106
|
end
|
107
107
|
|
108
|
-
def apply(obj, suffix, *args, &block)
|
109
|
-
raise 'use super' if super?
|
110
|
-
|
111
|
-
obj.send("#{method_name}_without_#{suffix}", *args, &block)
|
112
|
-
end
|
113
|
-
|
114
108
|
def install(key, &block)
|
115
109
|
if installed?(key)
|
116
110
|
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{self} already installed" }
|
@@ -344,3 +338,9 @@ module Sqreen
|
|
344
338
|
end
|
345
339
|
end
|
346
340
|
end
|
341
|
+
|
342
|
+
if RUBY_VERSION =~ /^2\./
|
343
|
+
load File.join(__dir__, 'hook_point.ruby_2.rb')
|
344
|
+
else
|
345
|
+
load File.join(__dir__, 'hook_point.ruby_3.rb')
|
346
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
require 'sqreen/graft'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Graft
|
10
|
+
class HookPoint
|
11
|
+
def apply(obj, suffix, *args, &block)
|
12
|
+
raise 'use super' if super?
|
13
|
+
|
14
|
+
obj.send("#{method_name}_without_#{suffix}", *args, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
require 'sqreen/graft'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Graft
|
10
|
+
class HookPoint
|
11
|
+
def apply(obj, suffix, *args, **kwargs, &block)
|
12
|
+
raise 'use super' if super?
|
13
|
+
|
14
|
+
obj.send("#{method_name}_without_#{suffix}", *args, **kwargs, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/lib/sqreen/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqreen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.23.
|
4
|
+
version: 1.23.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sqreen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sqreen-backport
|
@@ -198,7 +198,11 @@ files:
|
|
198
198
|
- lib/sqreen/graft/call.rb
|
199
199
|
- lib/sqreen/graft/callback.rb
|
200
200
|
- lib/sqreen/graft/hook.rb
|
201
|
+
- lib/sqreen/graft/hook.ruby_2.rb
|
202
|
+
- lib/sqreen/graft/hook.ruby_3.rb
|
201
203
|
- lib/sqreen/graft/hook_point.rb
|
204
|
+
- lib/sqreen/graft/hook_point.ruby_2.rb
|
205
|
+
- lib/sqreen/graft/hook_point.ruby_3.rb
|
202
206
|
- lib/sqreen/graft/hook_point_error.rb
|
203
207
|
- lib/sqreen/invalid_signature_exception.rb
|
204
208
|
- lib/sqreen/js.rb
|
@@ -341,7 +345,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
341
345
|
requirements:
|
342
346
|
- - ">="
|
343
347
|
- !ruby/object:Gem::Version
|
344
|
-
version:
|
348
|
+
version: '2.0'
|
345
349
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
346
350
|
requirements:
|
347
351
|
- - ">="
|