sqreen 1.21.0.beta3-java → 1.21.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -15
  3. data/lib/sqreen/condition_evaluator.rb +5 -6
  4. data/lib/sqreen/conditionable.rb +6 -24
  5. data/lib/sqreen/ecosystem.rb +29 -2
  6. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  7. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  8. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  9. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  10. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  11. data/lib/sqreen/ecosystem/exception_reporting.rb +4 -2
  12. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  13. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  14. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  15. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  16. data/lib/sqreen/ecosystem/module_api/message_producer.rb +9 -3
  17. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  18. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  19. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  20. data/lib/sqreen/ecosystem/module_registry.rb +5 -1
  21. data/lib/sqreen/ecosystem/tracing/modules/client.rb +7 -3
  22. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  23. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  24. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  25. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  26. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  27. data/lib/sqreen/ecosystem_integration.rb +1 -7
  28. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +10 -20
  29. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +4 -8
  30. data/lib/sqreen/graft/call.rb +1 -21
  31. data/lib/sqreen/graft/hook.rb +75 -83
  32. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
  33. data/lib/sqreen/metrics.rb +0 -1
  34. data/lib/sqreen/rules/custom_error_cb.rb +1 -1
  35. data/lib/sqreen/rules/rule_cb.rb +2 -2
  36. data/lib/sqreen/runner.rb +12 -27
  37. data/lib/sqreen/version.rb +1 -1
  38. data/lib/sqreen/weave/budget.rb +14 -3
  39. data/lib/sqreen/weave/legacy/instrumentation.rb +94 -145
  40. metadata +22 -9
  41. data/lib/sqreen/ecosystem/redis/redis_connection.rb +0 -43
  42. data/lib/sqreen/metrics/req_detailed.rb +0 -41
@@ -0,0 +1,56 @@
1
+ require 'sqreen/kit/configuration'
2
+ require 'sqreen/kit/signals/point'
3
+ require 'sqreen/kit/signals/dto_helper'
4
+
5
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/tracing/producer-2020-04-21/schema.cue
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Tracing
10
+ module Signals
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class Sqreen::Ecosystem::Tracing::Signals::TracingProducer < Sqreen::Kit::Signals::Point
17
+ readonly_attrs :payload_schema, :source, :signal_name
18
+
19
+ def initialize(values = {})
20
+ self.payload_schema = Payload::SCHEMA_VERSION
21
+ self.source = Sqreen::Kit::Configuration.default_source
22
+ self.signal_name = 'tracing.producer'
23
+ self.time = values[:time] || Time.now
24
+ super
25
+ end
26
+
27
+ def payload=(payload)
28
+ unless payload.is_a?(Payload)
29
+ raise ArgumentError, "Payload should be a #{Payload}"
30
+ end
31
+ super
32
+ end
33
+
34
+ class Payload
35
+ include Sqreen::Kit::Signals::DtoHelper
36
+
37
+ add_mandatory_attrs :message_type, :host, :tracing_identifier
38
+
39
+ SCHEMA_VERSION = 'tracing/producer-2020-04-21'.freeze
40
+
41
+ # @return [Symbol]
42
+ attr_accessor :message_type
43
+
44
+ # @return [String]
45
+ attr_accessor :host
46
+
47
+ # @return [String]
48
+ attr_accessor :ip
49
+
50
+ # @return [String]
51
+ attr_accessor :topic
52
+
53
+ # @return [String]
54
+ attr_accessor :tracing_identifier
55
+ end
56
+ end
@@ -1,8 +1,6 @@
1
1
  require 'sqreen/log/loggable'
2
- require 'sqreen/metrics_store'
3
2
  require 'sqreen/ecosystem'
4
3
  require 'sqreen/ecosystem/dispatch_table'
5
- require 'sqreen/ecosystem_integration/around_callbacks'
6
4
  require 'sqreen/ecosystem_integration/instrumentation_service'
7
5
  require 'sqreen/ecosystem_integration/request_lifecycle_tracking'
8
6
  require 'sqreen/ecosystem_integration/signal_consumption'
@@ -19,12 +17,9 @@ module Sqreen
19
17
  include Sqreen::Log::Loggable
20
18
 
21
19
  # @param [Sqreen::Framework] framework
22
- # @param [Proc] create_binning_metric
23
- def initialize(framework, queue, create_binning_metric)
20
+ def initialize(framework, queue)
24
21
  @framework = framework
25
22
  @queue = queue
26
- # XXX: created metrics are insulated from feature upgrades
27
- @create_binning_metric = create_binning_metric
28
23
  @request_lifecycle = RequestLifecycleTracking.new
29
24
  @online = false
30
25
  end
@@ -33,7 +28,6 @@ module Sqreen
33
28
  raise 'already initialized' if @online
34
29
 
35
30
  setup_dispatch_table
36
- AroundCallbacks.create_metric = @create_binning_metric
37
31
  Ecosystem.init
38
32
  logger.info 'Ecosystem successfully initialized'
39
33
  @online = true
@@ -1,8 +1,6 @@
1
- require 'sqreen/metrics_store'
2
1
  require 'sqreen/log/loggable'
3
2
  require 'sqreen/events/remote_exception'
4
3
  require 'sqreen/mono_time'
5
- require 'sqreen/graft/call'
6
4
 
7
5
  module Sqreen
8
6
  class EcosystemIntegration
@@ -10,32 +8,27 @@ module Sqreen
10
8
  class << self
11
9
  include Log::Loggable::ClassMethods
12
10
 
13
- # @return [Proc]
14
- attr_accessor :create_metric
15
-
16
11
  # for instrumentation hooks
17
- # instrumentation hooks already handle budgets/metrics
12
+ # instrumentation hooks already handle budgets, so nothing
13
+ # to do in that respect
18
14
  def wrap_instrumentation_hook(module_name, action, callable)
19
- # make tag similar to that of rules
20
- # TODO: move to structured tags to avoid silly string manips
21
- action_for_metric = if %w[pre post failing finally].include?(action)
22
- action
23
- else
24
- 'pre'
25
- end
26
- metric_name = "sq.ecosystem_#{module_name}.#{action_for_metric}"
27
- create_metric.call(metric_name)
15
+ perf_notif_name = "ecosystem_#{module_name}"
28
16
 
29
17
  Proc.new do |*args|
30
18
  begin
19
+ start = Sqreen.time
31
20
  callable.call(*args)
32
21
  rescue ::Exception => e # rubocop:disable Lint/RescueException
33
22
  # 2) rescue exceptions
34
23
  logger.warn { "Error in #{module_name}:#{action}: #{e.message}" }
35
24
  logger.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
36
25
  Sqreen::RemoteException.record(e)
37
- end # end begin
38
- end # end proc
26
+ ensure
27
+ # 3) contribute to performance metrics
28
+ stop = Sqreen.time
29
+ Sqreen::PerformanceNotifications.notify(perf_notif_name, action, start, stop)
30
+ end # end proc
31
+ end # end begin
39
32
  end
40
33
 
41
34
  # XXX: not used yet
@@ -43,8 +36,6 @@ module Sqreen
43
36
  timer_name = "ecosystem:#{module_name}@#{action}"
44
37
  perf_notif_name = "ecosystem_#{module_name}"
45
38
 
46
- # XXX: register metric
47
-
48
39
  Proc.new do |*args|
49
40
  begin
50
41
  req_storage = Thread.current[:sqreen_http_request]
@@ -85,7 +76,6 @@ module Sqreen
85
76
  if timer
86
77
  req_timer.include_measurements(timer) if req_timer
87
78
 
88
- # XXX: PerformanceNotifications is used no more
89
79
  Sqreen::PerformanceNotifications.notify(
90
80
  perf_notif_name, action, *timer.start_and_end
91
81
  )
@@ -12,26 +12,22 @@ module Sqreen
12
12
  hook = Sqreen::Graft::Hook[method].add do
13
13
  if spec[:before]
14
14
  cb = AroundCallbacks.wrap_instrumentation_hook(module_name, 'pre', spec[:before])
15
- tag = "weave,rule=ecosystem_#{module_name}"
16
- before(tag, flow: true, &cb)
15
+ before(nil, flow: true, &cb)
17
16
  end
18
17
 
19
18
  if spec[:after]
20
19
  cb = AroundCallbacks.wrap_instrumentation_hook(module_name, 'post', spec[:after])
21
- tag = "weave,rule=ecosystem_#{module_name}"
22
- after(tag, flow: true, &cb)
20
+ after(nil, flow: true, &cb)
23
21
  end
24
22
 
25
23
  if spec[:raised]
26
24
  cb = AroundCallbacks.wrap_instrumentation_hook(module_name, 'failing', spec[:raised])
27
- tag = "weave,rule=ecosystem_#{module_name}"
28
- raised(tag, flow: true, &cb)
25
+ raised(nil, flow: true, &cb)
29
26
  end
30
27
 
31
28
  if spec[:ensured]
32
29
  cb = AroundCallbacks.wrap_instrumentation_hook(module_name, 'finally', spec[:ensured])
33
- tag = "weave,rule=ecosystem_#{module_name}"
34
- ensured(tag, flow: true, &cb)
30
+ ensured(nil, flow: true, &cb)
35
31
  end
36
32
  end
37
33
  hook.install
@@ -27,10 +27,6 @@ module Sqreen
27
27
  def raise(value)
28
28
  Flow.raise(value)
29
29
  end
30
-
31
- def noop
32
- Flow.noop
33
- end
34
30
  end
35
31
 
36
32
  class Flow
@@ -50,17 +46,12 @@ module Sqreen
50
46
  def raise(value)
51
47
  new(:raise, value)
52
48
  end
53
-
54
- def noop
55
- new(:noop, nil)
56
- end
57
49
  end
58
50
 
59
51
  def initialize(action, value, brk = false)
60
52
  @action = action
61
53
  @value = value
62
54
  @break = brk
63
- @passed_conditions = false
64
55
  end
65
56
 
66
57
  def return?
@@ -100,16 +91,6 @@ module Sqreen
100
91
  def break?
101
92
  @break ? true : false
102
93
  end
103
-
104
- def passed_conditions!
105
- @passed_conditions = true
106
-
107
- self
108
- end
109
-
110
- def passed_conditions?
111
- @passed_conditions
112
- end
113
94
  end
114
95
 
115
96
  class TimerError < StandardError; end
@@ -120,7 +101,6 @@ module Sqreen
120
101
  end
121
102
 
122
103
  attr_reader :tag, :size
123
- attr_accessor :conditions_passed
124
104
 
125
105
  def initialize(tag, &block)
126
106
  @tag = tag
@@ -225,7 +205,7 @@ module Sqreen
225
205
  end
226
206
 
227
207
  def to_s
228
- "#{@tag}: time=%.03fus" % (@tally * 1_000_000)
208
+ "#{@tag}: time=%.03fus" % (duration * 1_000_000)
229
209
  end
230
210
 
231
211
  protected
@@ -7,8 +7,6 @@ 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
12
10
 
13
11
  module Sqreen
14
12
  module Graft
@@ -138,13 +136,6 @@ module Sqreen
138
136
  request[:timed_callbacks] << t if request[:timed_level] >= 1
139
137
  end
140
138
  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
139
 
149
140
  Proc.new do |*args, &block|
150
141
  request = Thread.current[:sqreen_http_request]
@@ -192,15 +183,18 @@ module Sqreen
192
183
  # budget implies request
193
184
  # TODO: make budget depend on a generic context (currently "request")
194
185
  budget = request[:time_budget] if request
195
- if request && (budget || request[:timed_level] >= 1)
186
+ if budget
187
+ budget_threshold = request[:time_budget_threshold]
188
+ budget_ratio = request[:time_budget_ratio]
196
189
  sqreen_timer = request[:sqreen_timer]
190
+ request_timer = request[:request_timer]
197
191
  end
198
192
 
199
193
  hooked_call = HookedCall.new(self, args)
200
194
 
201
195
  begin
202
196
  begin
203
- sqreen_timer.start if sqreen_timer
197
+ sqreen_timer.start if budget
204
198
  Thread.current[:sqreen_hook_entered] = true
205
199
 
206
200
  # TODO: make Call have #ball to throw by cb
@@ -212,34 +206,34 @@ module Sqreen
212
206
  # TODO: TimedHookCall TimedCallbackCall
213
207
  # TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
214
208
 
209
+ request_elapsed = request_timer.elapsed if budget
210
+
215
211
  hook.before.each do |c|
216
212
  next if c.ignore && c.ignore.call
217
213
 
218
- if budget && !c.mandatory && request[:time_budget_expended]
219
- request[:skipped_callbacks] << c
220
- next
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
221
228
  end
222
229
 
223
- remaining = budget - sqreen_timer.elapsed if budget
224
-
225
- timer = nil
226
230
  flow = catch(Ball.new) do |ball|
227
- timer = Timer.new(c.name, &timed_callbacks_proc)
228
- timer.measure(ignore: chrono) do
231
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
229
232
  c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
230
233
  end
231
234
  end
232
235
 
233
- if budget && timer
234
- remaining -= timer.duration
235
- if remaining < 0.0
236
- request[:time_budget_expended]
237
- request[:overtime_cb] = c.name
238
- end
239
- end
240
-
241
236
  next unless c.flow && flow.is_a?(Flow)
242
- conditions_passed_proc[] if flow.passed_conditions?
243
237
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
244
238
  hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
245
239
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
@@ -254,7 +248,7 @@ module Sqreen
254
248
  return hooked_call.return if hooked_call.returning
255
249
  ensure
256
250
  Thread.current[:sqreen_hook_entered] = false
257
- sqreen_timer.stop if sqreen_timer
251
+ sqreen_timer.stop if budget
258
252
  end unless hook.before.empty?
259
253
 
260
254
  begin
@@ -267,41 +261,41 @@ module Sqreen
267
261
  end
268
262
  rescue ::Exception => e # rubocop:disable Lint/RescueException
269
263
  begin
270
- sqreen_timer.start if sqreen_timer
264
+ sqreen_timer.start if budget
271
265
  Thread.current[:sqreen_hook_entered] = true
272
266
  hooked_call.raised = e
273
267
 
274
268
  logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
275
269
  raise if hook.raised.empty?
276
270
 
271
+ request_elapsed = request_timer.elapsed if budget
272
+
277
273
  hook.raised.each do |c|
278
274
  next if c.ignore && c.ignore.call
279
275
 
280
- if budget && !c.mandatory && request[:time_budget_expended]
281
- request[:skipped_callbacks] << c
282
- next
276
+ if budget && !c.mandatory
277
+ sqreen_elapsed = sqreen_timer.elapsed
278
+ if budget_ratio && !request[:time_budget_expended]
279
+ fixed_budget = budget_threshold
280
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
281
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
282
+ else
283
+ remaining = budget_threshold - sqreen_elapsed
284
+ end
285
+ unless remaining > 0
286
+ request[:skipped_callbacks] << c
287
+ request[:time_budget_expended] = true
288
+ next
289
+ end
283
290
  end
284
291
 
285
- remaining = budget - sqreen_timer.elapsed if budget
286
-
287
- timer = nil
288
292
  flow = catch(Ball.new) do |ball|
289
- timer = Timer.new(c.name, &timed_callbacks_proc)
290
- timer.measure(ignore: chrono) do
293
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
291
294
  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
295
  end
293
296
  end
294
297
 
295
- if budget && timer
296
- remaining -= timer.duration
297
- if remaining < 0.0
298
- request[:time_budget_expended]
299
- request[:overtime_cb] = c.name
300
- end
301
- end
302
-
303
298
  next unless c.flow && flow.is_a?(Flow)
304
- conditions_passed_proc[] if flow.passed_conditions?
305
299
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
306
300
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
307
301
  hooked_call.retrying = true if flow.retry?
@@ -318,40 +312,40 @@ module Sqreen
318
312
  raise
319
313
  else
320
314
  begin
321
- sqreen_timer.start if sqreen_timer
315
+ sqreen_timer.start if budget
322
316
  Thread.current[:sqreen_hook_entered] = true
323
317
 
324
318
  # TODO: hooked_call.returning should be always false here?
325
319
  return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
326
320
 
321
+ request_elapsed = request_timer.elapsed if budget
322
+
327
323
  hook.after.each do |c|
328
324
  next if c.ignore && c.ignore.call
329
325
 
330
- if budget && !c.mandatory && request[:time_budget_expended]
331
- request[:skipped_callbacks] << c
332
- next
326
+ if budget && !c.mandatory
327
+ sqreen_elapsed = sqreen_timer.elapsed
328
+ if budget_ratio && !request[:time_budget_expended]
329
+ fixed_budget = budget_threshold
330
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
331
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
332
+ else
333
+ remaining = budget_threshold - sqreen_elapsed
334
+ end
335
+ unless remaining > 0
336
+ request[:skipped_callbacks] << c
337
+ request[:time_budget_expended] = true
338
+ next
339
+ end
333
340
  end
334
341
 
335
- remaining = budget - sqreen_timer.elapsed if budget
336
-
337
- timer = nil
338
342
  flow = catch(Ball.new) do |ball|
339
- timer = Timer.new(c.name, &timed_callbacks_proc)
340
- timer.measure(ignore: chrono) do
343
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
341
344
  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
345
  end
343
346
  end
344
347
 
345
- if budget && timer
346
- remaining -= timer.duration
347
- if remaining < 0.0
348
- request[:time_budget_expended]
349
- request[:overtime_cb] = c.name
350
- end
351
- end
352
-
353
348
  next unless c.flow && flow.is_a?(Flow)
354
- conditions_passed_proc[] if flow.passed_conditions?
355
349
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
356
350
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
357
351
  break if flow.break?
@@ -379,38 +373,36 @@ module Sqreen
379
373
  hook.ensured.each do |c|
380
374
  next if c.ignore && c.ignore.call
381
375
 
382
- if budget && !c.mandatory && request[:time_budget_expended]
383
- request[:skipped_callbacks] << c
384
- next
376
+ if budget && !c.mandatory
377
+ sqreen_elapsed = sqreen_timer.elapsed
378
+ if budget_ratio && !request[:time_budget_expended]
379
+ fixed_budget = budget_threshold
380
+ proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
381
+ remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
382
+ else
383
+ remaining = budget_threshold - sqreen_elapsed
384
+ end
385
+ unless remaining > 0
386
+ request[:skipped_callbacks] << c
387
+ request[:time_budget_expended] = true
388
+ next
389
+ end
385
390
  end
386
391
 
387
- remaining = budget - sqreen_timer.elapsed if budget
388
-
389
- timer = nil
390
392
  flow = catch(Ball.new) do |ball|
391
- timer = Timer.new(c.name, &timed_callbacks_proc)
392
- timer.measure(ignore: chrono) do
393
+ Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
393
394
  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
395
  end
395
396
  end
396
397
 
397
- if budget && timer
398
- remaining -= timer.duration
399
- if remaining < 0.0
400
- request[:time_budget_expended]
401
- request[:overtime_cb] = c.name
402
- end
403
- end
404
-
405
398
  next unless c.flow && flow.is_a?(Flow)
406
- conditions_passed_proc[] if flow.passed_conditions?
407
399
  hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
408
400
  hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
409
401
  break if flow.break?
410
402
  end unless hook.ensured.empty? || hook.disabled?
411
403
 
412
404
  Thread.current[:sqreen_hook_entered] = false
413
- sqreen_timer.stop if sqreen_timer
405
+ sqreen_timer.stop if budget
414
406
  rescue StandardError => e
415
407
  Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
416
408
  Sqreen::RemoteException.record(e) if Sqreen.queue