sqreen 1.19.1-java → 1.21.0.beta3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -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/agent_message.rb +20 -0
  7. data/lib/sqreen/aggregated_metric.rb +25 -0
  8. data/lib/sqreen/attack_detected.html +1 -2
  9. data/lib/sqreen/ca.crt +24 -0
  10. data/lib/sqreen/condition_evaluator.rb +9 -2
  11. data/lib/sqreen/conditionable.rb +24 -6
  12. data/lib/sqreen/configuration.rb +11 -5
  13. data/lib/sqreen/deferred_logger.rb +50 -14
  14. data/lib/sqreen/deliveries/batch.rb +12 -2
  15. data/lib/sqreen/deliveries/simple.rb +4 -0
  16. data/lib/sqreen/deprecation.rb +38 -0
  17. data/lib/sqreen/ecosystem.rb +96 -0
  18. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  19. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  20. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  21. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  22. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  23. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  24. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  25. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  26. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  27. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  32. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  33. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  34. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  37. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  38. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  39. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  40. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  41. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  42. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  43. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  44. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  45. data/lib/sqreen/ecosystem_integration.rb +87 -0
  46. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  47. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  48. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  49. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  50. data/lib/sqreen/endpoint_testing.rb +184 -0
  51. data/lib/sqreen/event.rb +7 -5
  52. data/lib/sqreen/events/attack.rb +23 -18
  53. data/lib/sqreen/events/remote_exception.rb +0 -22
  54. data/lib/sqreen/events/request_record.rb +15 -71
  55. data/lib/sqreen/frameworks/generic.rb +24 -1
  56. data/lib/sqreen/frameworks/rails.rb +0 -7
  57. data/lib/sqreen/frameworks/request_recorder.rb +15 -2
  58. data/lib/sqreen/graft/call.rb +106 -19
  59. data/lib/sqreen/graft/callback.rb +1 -1
  60. data/lib/sqreen/graft/hook.rb +212 -100
  61. data/lib/sqreen/graft/hook_point.rb +18 -11
  62. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  63. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  64. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  65. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  66. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  67. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  68. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  69. data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
  70. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  71. data/lib/sqreen/log.rb +3 -2
  72. data/lib/sqreen/log/loggable.rb +2 -1
  73. data/lib/sqreen/logger.rb +24 -0
  74. data/lib/sqreen/metrics.rb +1 -0
  75. data/lib/sqreen/metrics/base.rb +3 -0
  76. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  77. data/lib/sqreen/metrics_store.rb +33 -12
  78. data/lib/sqreen/null_logger.rb +22 -0
  79. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  80. data/lib/sqreen/remote_command.rb +4 -0
  81. data/lib/sqreen/rules.rb +12 -6
  82. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  83. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  84. data/lib/sqreen/rules/not_found_cb.rb +2 -0
  85. data/lib/sqreen/rules/rule_cb.rb +6 -2
  86. data/lib/sqreen/rules/waf_cb.rb +16 -13
  87. data/lib/sqreen/runner.rb +138 -16
  88. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  89. data/lib/sqreen/session.rb +53 -43
  90. data/lib/sqreen/signals/conversions.rb +288 -0
  91. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  92. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  93. data/lib/sqreen/version.rb +1 -1
  94. data/lib/sqreen/weave/budget.rb +35 -0
  95. data/lib/sqreen/weave/legacy/instrumentation.rb +277 -135
  96. data/lib/sqreen/worker.rb +6 -2
  97. metadata +86 -10
  98. data/lib/sqreen/backport.rb +0 -9
  99. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  100. data/lib/sqreen/backport/original_name.rb +0 -88
  101. 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
@@ -7,23 +7,34 @@ require 'sqreen/graft'
7
7
  require 'sqreen/graft/call'
8
8
  require 'sqreen/graft/callback'
9
9
  require 'sqreen/graft/hook_point'
10
+ require 'sqreen/weave'
11
+ require 'sqreen/runner' # Sqreen.queue
10
12
 
11
13
  module Sqreen
12
14
  module Graft
13
15
  class Hook
16
+ DEFAULT_STRATEGY = Sqreen::Graft::HookPoint::DEFAULT_STRATEGY
17
+
14
18
  @hooks = {}
15
19
 
16
- def self.[](hook_point, strategy = :chain)
20
+ def self.[](hook_point, strategy = DEFAULT_STRATEGY)
17
21
  @hooks[hook_point] ||= new(hook_point, nil, strategy)
18
22
  end
19
23
 
20
- def self.add(hook_point, strategy = :chain, &block)
24
+ def self.add(hook_point, strategy = DEFAULT_STRATEGY, &block)
21
25
  self[hook_point, strategy].add(&block)
22
26
  end
23
27
 
28
+ def self.ignore
29
+ Thread.current[:sqreen_hook_entered] = true
30
+ yield
31
+ ensure
32
+ Thread.current[:sqreen_hook_entered] = false
33
+ end
34
+
24
35
  attr_reader :point
25
36
 
26
- def initialize(hook_point, dependency_test = nil, strategy = :chain)
37
+ def initialize(hook_point, dependency_test = nil, strategy = DEFAULT_STRATEGY)
27
38
  @disabled = false
28
39
  @point = hook_point.is_a?(HookPoint) ? hook_point : HookPoint.new(hook_point, strategy)
29
40
  @before = []
@@ -46,27 +57,31 @@ module Sqreen
46
57
  end
47
58
 
48
59
  def before(tag = nil, opts = {}, &block)
49
- return @before.sort_by(&:rank) if block.nil?
60
+ return @before if block.nil?
50
61
 
51
62
  @before << Callback.new(callback_name(:before, tag), opts, &block)
63
+ @before.sort_by!(&:rank)
52
64
  end
53
65
 
54
66
  def after(tag = nil, opts = {}, &block)
55
- return @after.sort_by(&:rank) if block.nil?
67
+ return @after if block.nil?
56
68
 
57
69
  @after << Callback.new(callback_name(:after, tag), opts, &block)
70
+ @after.sort_by!(&:rank)
58
71
  end
59
72
 
60
73
  def raised(tag = nil, opts = {}, &block)
61
- return @raised.sort_by(&:rank) if block.nil?
74
+ return @raised if block.nil?
62
75
 
63
76
  @raised << Callback.new(callback_name(:raised, tag), opts, &block)
77
+ @raised.sort_by!(&:rank)
64
78
  end
65
79
 
66
80
  def ensured(tag = nil, opts = {}, &block)
67
- return @ensured.sort_by(&:rank) if block.nil?
81
+ return @ensured if block.nil?
68
82
 
69
83
  @ensured << Callback.new(callback_name(:ensured, tag), opts, &block)
84
+ @ensured.sort_by!(&:rank)
70
85
  end
71
86
 
72
87
  def depends_on(&block)
@@ -109,11 +124,32 @@ module Sqreen
109
124
  @before = []
110
125
  @after = []
111
126
  @raised = []
127
+ @ensured = []
112
128
  end
113
129
 
114
130
  def self.wrapper(hook)
131
+ timed_hooks_proc = proc do |t|
132
+ if (request = Thread.current[:sqreen_http_request])
133
+ request[:timed_hooks] << t if request[:timed_level] >= 1
134
+ end
135
+ end
136
+ timed_callbacks_proc = proc do |t|
137
+ if (request = Thread.current[:sqreen_http_request])
138
+ request[:timed_callbacks] << t if request[:timed_level] >= 1
139
+ end
140
+ end
141
+ # very hacky, but the non-local control flow with throw-catch
142
+ # makes the solution non-obvious. needs to be revisited
143
+ conditions_passed_proc = proc do
144
+ if (request = Thread.current[:sqreen_http_request])
145
+ request[:timed_callbacks].last.conditions_passed = true
146
+ end
147
+ end
148
+
115
149
  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]
150
+ request = Thread.current[:sqreen_http_request]
151
+
152
+ if Thread.current[:sqreen_hook_entered]
117
153
  if hook.point.super?
118
154
  return super(*args, &block)
119
155
  else
@@ -121,113 +157,159 @@ module Sqreen
121
157
  end
122
158
  end
123
159
 
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}" }
160
+ if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
161
+ if request[:timed_level] >= 2
162
+ begin
163
+ request[:skipped_callbacks].concat(hook.before)
164
+
165
+ if hook.point.super?
166
+ return super(*args, &block)
167
+ else
168
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
169
+ end
170
+ rescue ::Exception # rubocop:disable Lint/RescueException
171
+ request[:skipped_callbacks].concat(hook.raised)
172
+ raise
173
+ else
174
+ request[:skipped_callbacks].concat(hook.after)
175
+ ensure
176
+ request[:skipped_callbacks].concat(hook.ensured)
177
+ end
178
+ else
179
+ if hook.point.super? # rubocop:disable Style/IfInsideElse
180
+ return super(*args, &block)
181
+ else
182
+ return hook.point.apply(self, 'sqreen_hook', *args, &block)
183
+ end
184
+ end
185
+ end
186
+
187
+ hook_point_super = hook.point.super?
188
+ logger = Sqreen::Graft.logger
189
+ logger_debug = Sqreen::Graft.logger.debug?
190
+
191
+ Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
192
+ # budget implies request
193
+ # TODO: make budget depend on a generic context (currently "request")
194
+ budget = request[:time_budget] if request
195
+ if request && (budget || request[:timed_level] >= 1)
196
+ sqreen_timer = request[:sqreen_timer]
197
+ end
128
198
 
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
199
  hooked_call = HookedCall.new(self, args)
132
200
 
133
201
  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|
202
+ begin
203
+ sqreen_timer.start if sqreen_timer
204
+ Thread.current[:sqreen_hook_entered] = true
205
+
206
+ # TODO: make Call have #ball to throw by cb
207
+ # TODO: can Call be the ball? r = catch(Call.new, &c)
208
+ # TODO: is catch return value a Call? a #dispatch?
209
+ # TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
210
+ # TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
211
+ # TODO: HookCall x CallbackCollection#each_with_call x Flow
212
+ # TODO: TimedHookCall TimedCallbackCall
213
+ # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
214
+
149
215
  hook.before.each do |c|
150
216
  next if c.ignore && c.ignore.call
151
217
 
152
- if timer && !c.mandatory
153
- remaining = budget - timer.elapsed
154
- 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
156
- next
157
- end
218
+ if budget && !c.mandatory && request[:time_budget_expended]
219
+ request[:skipped_callbacks] << c
220
+ next
158
221
  end
159
222
 
223
+ remaining = budget - sqreen_timer.elapsed if budget
224
+
225
+ timer = nil
160
226
  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
227
+ timer = Timer.new(c.name, &timed_callbacks_proc)
228
+ timer.measure(ignore: chrono) do
229
+ c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
230
+ end
231
+ end
232
+
233
+ if budget && timer
234
+ remaining -= timer.duration
235
+ if remaining < 0.0
236
+ request[:time_budget_expended]
237
+ request[:overtime_cb] = c.name
167
238
  end
168
239
  end
169
240
 
170
241
  next unless c.flow && flow.is_a?(Flow)
242
+ conditions_passed_proc[] if flow.passed_conditions?
171
243
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
172
244
  hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
173
245
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
174
246
  break if flow.break?
175
247
  end unless hook.disabled?
248
+ rescue StandardError => e
249
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
250
+ Sqreen::RemoteException.record(e) if Sqreen.queue
176
251
  end
177
252
 
178
253
  raise hooked_call.raise if hooked_call.raising
179
254
  return hooked_call.return if hooked_call.returning
180
255
  ensure
181
256
  Thread.current[:sqreen_hook_entered] = false
182
- timer.stop if timer
183
- end
257
+ sqreen_timer.stop if sqreen_timer
258
+ end unless hook.before.empty?
184
259
 
185
260
  begin
186
261
  chrono.ignore do
187
- if hook.point.super?
262
+ if hook_point_super
188
263
  hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
189
264
  else
190
265
  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
266
  end
192
267
  end
193
268
  rescue ::Exception => e # rubocop:disable Lint/RescueException
194
- timer.start if timer
195
- Thread.current[:sqreen_hook_entered] = true
196
- hooked_call.raised = e
269
+ begin
270
+ sqreen_timer.start if sqreen_timer
271
+ Thread.current[:sqreen_hook_entered] = true
272
+ hooked_call.raised = e
197
273
 
198
- Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" }
199
- raise if hook.raised.empty?
274
+ logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
275
+ raise if hook.raised.empty?
200
276
 
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
277
  hook.raised.each do |c|
205
278
  next if c.ignore && c.ignore.call
206
279
 
207
- if timer && !c.mandatory
208
- remaining = budget - timer.elapsed
209
- 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
211
- next
212
- end
280
+ if budget && !c.mandatory && request[:time_budget_expended]
281
+ request[:skipped_callbacks] << c
282
+ next
213
283
  end
214
284
 
285
+ remaining = budget - sqreen_timer.elapsed if budget
286
+
287
+ timer = nil
215
288
  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
289
+ timer = Timer.new(c.name, &timed_callbacks_proc)
290
+ timer.measure(ignore: chrono) do
291
+ 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)
292
+ end
293
+ end
294
+
295
+ if budget && timer
296
+ remaining -= timer.duration
297
+ if remaining < 0.0
298
+ request[:time_budget_expended]
299
+ request[:overtime_cb] = c.name
222
300
  end
223
301
  end
224
302
 
225
303
  next unless c.flow && flow.is_a?(Flow)
304
+ conditions_passed_proc[] if flow.passed_conditions?
226
305
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
227
306
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
228
307
  hooked_call.retrying = true if flow.retry?
229
308
  break if flow.break?
230
309
  end unless hook.disabled?
310
+ rescue StandardError => e
311
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
312
+ Sqreen::RemoteException.record(e) if Sqreen.queue
231
313
  end
232
314
 
233
315
  retry if hooked_call.retrying
@@ -235,78 +317,108 @@ module Sqreen
235
317
  return hooked_call.return if hooked_call.returning
236
318
  raise
237
319
  else
238
- timer.start if timer
239
- Thread.current[:sqreen_hook_entered] = true
320
+ begin
321
+ sqreen_timer.start if sqreen_timer
322
+ Thread.current[:sqreen_hook_entered] = true
323
+
324
+ # TODO: hooked_call.returning should be always false here?
325
+ return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
240
326
 
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
327
  hook.after.each do |c|
245
328
  next if c.ignore && c.ignore.call
246
329
 
247
- if timer && !c.mandatory
248
- remaining = budget - timer.elapsed
249
- 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
251
- next
252
- end
330
+ if budget && !c.mandatory && request[:time_budget_expended]
331
+ request[:skipped_callbacks] << c
332
+ next
253
333
  end
254
334
 
335
+ remaining = budget - sqreen_timer.elapsed if budget
336
+
337
+ timer = nil
255
338
  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
339
+ timer = Timer.new(c.name, &timed_callbacks_proc)
340
+ timer.measure(ignore: chrono) do
341
+ 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)
342
+ end
343
+ end
344
+
345
+ if budget && timer
346
+ remaining -= timer.duration
347
+ if remaining < 0.0
348
+ request[:time_budget_expended]
349
+ request[:overtime_cb] = c.name
262
350
  end
263
351
  end
264
352
 
265
353
  next unless c.flow && flow.is_a?(Flow)
354
+ conditions_passed_proc[] if flow.passed_conditions?
266
355
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
267
356
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
268
357
  break if flow.break?
269
358
  end unless hook.disabled?
359
+ rescue StandardError => e
360
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
361
+ Sqreen::RemoteException.record(e) if Sqreen.queue
270
362
  end
271
363
 
272
364
  raise hooked_call.raise if hooked_call.raising
273
365
  return hooked_call.returning ? hooked_call.return : hooked_call.returned
274
366
  ensure
275
- # TODO: timer.start if someone has thrown?
367
+ begin
368
+ # TODO: sqreen_timer.start if someone has thrown?
369
+ # TODO: sqreen_timer.stop at end of rescue+else?
370
+ # TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
371
+ # TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
372
+
373
+ # TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
374
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
375
+
376
+ # done at either rescue or else
377
+ # request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
276
378
 
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
379
  hook.ensured.each do |c|
281
380
  next if c.ignore && c.ignore.call
282
381
 
283
- if timer && !c.mandatory
284
- remaining = budget - timer.elapsed
285
- 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
287
- next
288
- end
382
+ if budget && !c.mandatory && request[:time_budget_expended]
383
+ request[:skipped_callbacks] << c
384
+ next
289
385
  end
290
386
 
387
+ remaining = budget - sqreen_timer.elapsed if budget
388
+
389
+ timer = nil
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 = Timer.new(c.name, &timed_callbacks_proc)
392
+ timer.measure(ignore: chrono) do
393
+ 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)
394
+ end
395
+ end
396
+
397
+ if budget && timer
398
+ remaining -= timer.duration
399
+ if remaining < 0.0
400
+ request[:time_budget_expended]
401
+ request[:overtime_cb] = c.name
298
402
  end
299
403
  end
300
404
 
301
405
  next unless c.flow && flow.is_a?(Flow)
406
+ conditions_passed_proc[] if flow.passed_conditions?
302
407
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
303
408
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
304
409
  break if flow.break?
305
- end unless hook.disabled?
410
+ end unless hook.ensured.empty? || hook.disabled?
411
+
412
+ Thread.current[:sqreen_hook_entered] = false
413
+ sqreen_timer.stop if sqreen_timer
414
+ rescue StandardError => e
415
+ Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
416
+ Sqreen::RemoteException.record(e) if Sqreen.queue
306
417
  end
307
418
 
308
- Thread.current[:sqreen_hook_entered] = false
309
- timer.stop if timer
419
+ # TODO: should we run the following?
420
+ # raise hooked_call.raise if hooked_call.raising
421
+ # return hooked_call.returning ? hooked_call.return : hooked_call.returned
310
422
  end
311
423
  end # chrono
312
424
  end