sqreen 1.23.0 → 1.24.2

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.
@@ -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, kwargs.empty? ? hooked_call.args_passed : hooked_call.args_passed + [kwargs]), 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
+
@@ -20,7 +20,7 @@ module Sqreen
20
20
  keys = args[1].class.authentication_keys
21
21
  ip = framework.client_ip
22
22
  category = 'auto-signup'
23
- data = data.select { |k, _| keys.include?(k) }
23
+ data = data.select { |k, _| keys.map(&:to_s).include?(k.to_s) }
24
24
 
25
25
  if data.empty?
26
26
  Sqreen.log.debug { "#{category} from #{ip} but keys empty" }