sqreen 1.19.1-java → 1.21.0.beta3-java

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.
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