sqreen 1.20.3 → 1.20.4.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/sqreen/actions/block_user.rb +1 -1
- data/lib/sqreen/actions/redirect_ip.rb +1 -1
- data/lib/sqreen/actions/redirect_user.rb +1 -1
- data/lib/sqreen/configuration.rb +1 -1
- data/lib/sqreen/deferred_logger.rb +46 -14
- data/lib/sqreen/deprecation.rb +38 -0
- data/lib/sqreen/frameworks/generic.rb +9 -0
- data/lib/sqreen/frameworks/rails.rb +0 -7
- data/lib/sqreen/graft/call.rb +59 -14
- data/lib/sqreen/graft/hook.rb +229 -108
- data/lib/sqreen/legacy/instrumentation.rb +12 -0
- data/lib/sqreen/log.rb +3 -2
- data/lib/sqreen/logger.rb +20 -0
- data/lib/sqreen/metrics_store.rb +11 -0
- data/lib/sqreen/null_logger.rb +22 -0
- data/lib/sqreen/remote_command.rb +1 -0
- data/lib/sqreen/rules.rb +1 -1
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
- data/lib/sqreen/rules/rule_cb.rb +2 -0
- data/lib/sqreen/runner.rb +28 -2
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +46 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +122 -63
- data/lib/sqreen/worker.rb +6 -2
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18fc090589982cc7e09d74263a3bbb17ae9180f00afd8425c47498a0f8b75e36
|
4
|
+
data.tar.gz: 074c3c9cad84ef1a52e6fd7ce1a4db5431920f59298e5b930206ca9a996141e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afd27c8a52c0c5e21685b9bf6b346a28ca43ff297c529c1976d7197bc132d51a92f2ac52dcb4de150cd8c752c4875b4fdd3baf8e59560a0c1952c4df12585572
|
7
|
+
data.tar.gz: 2e6d09aceaf1dcc351537b0a34e4459e7f1d4659a231cd515e6f01ec42f0515dc40ff89f14adb7094a6971f86fe3983e984bf35f8242b8f047405c164ef0874c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 1.20.4.beta1
|
2
|
+
|
3
|
+
* Add optional dynamic time budget
|
4
|
+
* Add advanced per request metrics
|
5
|
+
* Improve robustness against exception in instrumentation
|
6
|
+
* Improve metric engine thread safety
|
7
|
+
* Restrict deferred logger to final logger severity on agent boot
|
8
|
+
|
1
9
|
## 1.20.3
|
2
10
|
|
3
11
|
* Fix signature check
|
@@ -24,7 +24,7 @@ module Sqreen
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def do_run(identity_params)
|
27
|
-
Sqreen.log.
|
27
|
+
Sqreen.log.debug 'Will request redirect for user with identity ' \
|
28
28
|
"#{identity_params} (action: #{id})."
|
29
29
|
|
30
30
|
e = Sqreen::AttackBlocked.new(
|
data/lib/sqreen/configuration.rb
CHANGED
@@ -57,7 +57,7 @@ module Sqreen
|
|
57
57
|
{ :env => :SQREEN_RULES_SIGNATURE, :name => :rules_verify_signature,
|
58
58
|
:default => true },
|
59
59
|
{ :env => :SQREEN_LOG_LEVEL, :name => :log_level,
|
60
|
-
:default => '
|
60
|
+
:default => 'INFO', :choice => %w[UNKNOWN FATAL ERROR WARN INFO DEBUG] },
|
61
61
|
{ :env => :SQREEN_LOG_LOCATION, :name => :log_location,
|
62
62
|
:default => 'log/sqreen.log' },
|
63
63
|
{ :env => :SQREEN_RUN_IN_TEST, :name => :run_in_test,
|
@@ -9,39 +9,70 @@ require 'sqreen/logger'
|
|
9
9
|
|
10
10
|
module Sqreen
|
11
11
|
class DeferredLogger
|
12
|
-
|
12
|
+
MAX_ENTRIES = 1000
|
13
|
+
|
14
|
+
Entry = Struct.new(:severity, :message)
|
13
15
|
|
14
16
|
def initialize
|
15
17
|
@buffer = StringIO.new
|
16
18
|
@logger = ::Logger.new(@buffer)
|
19
|
+
@entries = []
|
20
|
+
@mutex = Mutex.new
|
17
21
|
end
|
18
22
|
|
19
23
|
def debug?
|
20
24
|
true
|
21
25
|
end
|
22
26
|
|
27
|
+
def info?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def warn?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def error?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def fatal?
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
23
43
|
def debug(msg = nil, &block)
|
24
|
-
|
44
|
+
add(::Logger::DEBUG, msg, &block)
|
25
45
|
end
|
26
46
|
|
27
47
|
def info(msg = nil, &block)
|
28
|
-
|
48
|
+
add(::Logger::INFO, msg, &block)
|
29
49
|
end
|
30
50
|
|
31
51
|
def warn(msg = nil, &block)
|
32
|
-
|
52
|
+
add(::Logger::WARN, msg, &block)
|
33
53
|
end
|
34
54
|
|
35
55
|
def error(msg = nil, &block)
|
36
|
-
|
56
|
+
add(::Logger::ERROR, msg, &block)
|
37
57
|
end
|
38
58
|
|
39
59
|
def fatal(msg = nil, &block)
|
40
|
-
|
60
|
+
add(::Logger::FATAL, msg, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def unknown(msg = nil, &block)
|
64
|
+
add(::Logger::UNKNOWN, msg, &block)
|
41
65
|
end
|
42
66
|
|
43
67
|
def add(severity, msg = nil, &block)
|
44
|
-
|
68
|
+
@mutex.synchronize do
|
69
|
+
@entries.shift if @entries.count >= MAX_ENTRIES
|
70
|
+
mark = @buffer.pos
|
71
|
+
@logger.add(severity, msg, &block)
|
72
|
+
@buffer.seek(mark)
|
73
|
+
@entries << Entry.new(severity, @buffer.read)
|
74
|
+
@buffer.truncate(0)
|
75
|
+
end
|
45
76
|
end
|
46
77
|
|
47
78
|
def formatter=(value)
|
@@ -49,21 +80,22 @@ module Sqreen
|
|
49
80
|
end
|
50
81
|
|
51
82
|
def flush_to(logger)
|
52
|
-
|
83
|
+
@mutex.synchronize do
|
84
|
+
@entries.each do |entry|
|
85
|
+
next if entry.severity < logger.level
|
86
|
+
logger.instance_eval { @logdev }.write(entry.message)
|
87
|
+
end
|
88
|
+
reset
|
89
|
+
end
|
53
90
|
end
|
54
91
|
|
55
92
|
private
|
56
93
|
|
57
|
-
def read
|
58
|
-
@buffer.rewind
|
59
|
-
@buffer.read
|
60
|
-
end
|
61
|
-
|
62
94
|
def reset
|
63
95
|
buffer = StringIO.new
|
64
96
|
logger = ::Logger.new(buffer)
|
65
97
|
logger.formatter = @logger.formatter
|
66
|
-
@buffer, @logger = buffer, logger
|
98
|
+
@buffer, @logger, @entries = buffer, logger, []
|
67
99
|
end
|
68
100
|
end
|
69
101
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# typed: strong
|
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/log/loggable'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Deprecation
|
10
|
+
include Sqreen::Log::Loggable
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def deprecate(method)
|
15
|
+
return unless ENV['SQREEN_DEBUG_DEPRECATION']
|
16
|
+
|
17
|
+
owner = method.owner
|
18
|
+
deprecated = :"_deprecated_#{method.name}"
|
19
|
+
klass = owner.is_a?(Module)
|
20
|
+
target = klass ? owner.to_s : owner.class.to_s
|
21
|
+
|
22
|
+
method.owner.instance_eval do
|
23
|
+
alias_method deprecated, method.name
|
24
|
+
|
25
|
+
define_method(method.name) do |*args, &block|
|
26
|
+
msg = [
|
27
|
+
"deprecation",
|
28
|
+
"target:#{target}",
|
29
|
+
"method:#{method.name}",
|
30
|
+
"caller:#{Kernel.caller_locations[0]}",
|
31
|
+
].join(' ')
|
32
|
+
Sqreen::Deprecation.logger.info(msg)
|
33
|
+
send(deprecated, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -209,7 +209,16 @@ module Sqreen
|
|
209
209
|
|
210
210
|
# Should the agent not be starting up?
|
211
211
|
def prevent_startup
|
212
|
+
# SQREEN-880 - prevent Sqreen startup on Sidekiq workers
|
213
|
+
return :sidekiq_cli if defined?(Sidekiq::CLI)
|
214
|
+
return :delayed_job if defined?(Delayed::Command)
|
215
|
+
|
216
|
+
# Prevent Sqreen startup on rake tasks - unless this is a Sqreen test
|
217
|
+
run_in_test = sqreen_configuration.get(:run_in_test)
|
218
|
+
return :rake if !run_in_test && $0.end_with?('rake')
|
219
|
+
|
212
220
|
return :irb if $0 == 'irb'
|
221
|
+
|
213
222
|
return if sqreen_configuration.nil?
|
214
223
|
disable = sqreen_configuration.get(:disable)
|
215
224
|
return :config_disable if disable == true || disable.to_s.to_i == 1
|
@@ -103,13 +103,6 @@ module Sqreen
|
|
103
103
|
run_in_test = sqreen_configuration.get(:run_in_test)
|
104
104
|
return :rails_test if !run_in_test && (Rails.env.test? || Rails.env.cucumber?)
|
105
105
|
|
106
|
-
# SQREEN-880 - prevent Sqreen startup on Sidekiq workers
|
107
|
-
return :sidekiq_cli if defined?(Sidekiq::CLI)
|
108
|
-
return :delayed_job if defined?(Delayed::Command)
|
109
|
-
|
110
|
-
# Prevent Sqreen startup on rake tasks - unless this is a Sqreen test
|
111
|
-
return :rake if !run_in_test && $0.end_with?('rake')
|
112
|
-
|
113
106
|
return nil unless defined?(Rails::CommandsTasks)
|
114
107
|
return nil if defined?(Rails::Server)
|
115
108
|
return :rails_console if defined?(Rails::Console)
|
data/lib/sqreen/graft/call.rb
CHANGED
@@ -93,62 +93,106 @@ module Sqreen
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
class TimerError < StandardError; end
|
97
|
+
|
96
98
|
class Timer
|
97
99
|
def self.read
|
98
100
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
99
101
|
end
|
100
102
|
|
101
|
-
attr_reader :tag, :size
|
103
|
+
attr_reader :tag, :size
|
102
104
|
|
103
105
|
def initialize(tag, &block)
|
104
106
|
@tag = tag
|
105
107
|
@block = block
|
106
|
-
@
|
108
|
+
@tally = 0
|
107
109
|
@size = 0
|
108
110
|
end
|
109
111
|
|
110
112
|
def elapsed
|
111
|
-
|
113
|
+
raise(TimerError, 'Timer#elapsed when paused') if @size.even?
|
114
|
+
|
115
|
+
@tally + Timer.read
|
116
|
+
end
|
117
|
+
|
118
|
+
def duration
|
119
|
+
raise(TimerError, 'Timer#duration when running') if @size.odd?
|
120
|
+
|
121
|
+
@tally
|
112
122
|
end
|
113
123
|
|
114
124
|
def ignore
|
125
|
+
raise(TimerError, 'Timer#ignore when paused') if @size.even?
|
126
|
+
|
115
127
|
@size += 1
|
116
|
-
@
|
128
|
+
@tally += Timer.read
|
117
129
|
yield(self)
|
118
130
|
ensure
|
119
131
|
@size += 1
|
120
|
-
@
|
132
|
+
@tally -= Timer.read
|
121
133
|
end
|
122
134
|
|
123
135
|
def measure(opts = nil)
|
136
|
+
raise(TimerError, 'Timer#measure when running') if @size.odd?
|
137
|
+
|
124
138
|
now = Timer.read
|
139
|
+
|
125
140
|
ignore = opts[:ignore] if opts
|
126
141
|
if ignore
|
127
142
|
ignore.size += 1
|
128
|
-
ignore.
|
143
|
+
ignore.tally += now
|
129
144
|
end
|
145
|
+
|
130
146
|
@size += 1
|
131
|
-
@
|
147
|
+
@tally -= now
|
148
|
+
|
132
149
|
yield(self)
|
133
150
|
ensure
|
134
151
|
now = Timer.read
|
152
|
+
|
135
153
|
if ignore
|
136
154
|
ignore.size += 1
|
137
|
-
ignore.
|
155
|
+
ignore.tally -= now
|
138
156
|
end
|
157
|
+
|
139
158
|
@size += 1
|
140
|
-
@
|
159
|
+
@tally += now
|
160
|
+
|
141
161
|
@block.call(self) if @block
|
142
162
|
end
|
143
163
|
|
144
|
-
def start
|
164
|
+
def start(at = Timer.read)
|
165
|
+
raise(TimerError, 'Timer#start when started') unless @size.even?
|
166
|
+
|
145
167
|
@size += 1
|
146
|
-
@
|
168
|
+
@tally -= at
|
169
|
+
|
170
|
+
at
|
147
171
|
end
|
148
172
|
|
149
|
-
def stop
|
173
|
+
def stop(at = Timer.read)
|
174
|
+
raise(TimerError, 'Timer#stop when unstarted') unless @size.odd?
|
175
|
+
|
150
176
|
@size += 1
|
151
|
-
@
|
177
|
+
@tally += at
|
178
|
+
|
179
|
+
at
|
180
|
+
end
|
181
|
+
|
182
|
+
def started?
|
183
|
+
@size != 0 && @size.odd?
|
184
|
+
end
|
185
|
+
|
186
|
+
def stopped?
|
187
|
+
@size != 0 && @size.even?
|
188
|
+
end
|
189
|
+
|
190
|
+
def running?
|
191
|
+
@size.odd?
|
192
|
+
end
|
193
|
+
|
194
|
+
def paused?
|
195
|
+
@size.even?
|
152
196
|
end
|
153
197
|
|
154
198
|
def to_s
|
@@ -157,7 +201,8 @@ module Sqreen
|
|
157
201
|
|
158
202
|
protected
|
159
203
|
|
160
|
-
|
204
|
+
attr_reader :tally
|
205
|
+
attr_writer :size, :tally
|
161
206
|
end
|
162
207
|
end
|
163
208
|
end
|
data/lib/sqreen/graft/hook.rb
CHANGED
@@ -21,6 +21,13 @@ module Sqreen
|
|
21
21
|
self[hook_point, strategy].add(&block)
|
22
22
|
end
|
23
23
|
|
24
|
+
def self.ignore
|
25
|
+
Thread.current[:sqreen_hook_entered] = true
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
Thread.current[:sqreen_hook_entered] = false
|
29
|
+
end
|
30
|
+
|
24
31
|
attr_reader :point
|
25
32
|
|
26
33
|
def initialize(hook_point, dependency_test = nil, strategy = :chain)
|
@@ -113,18 +120,25 @@ module Sqreen
|
|
113
120
|
@before = []
|
114
121
|
@after = []
|
115
122
|
@raised = []
|
123
|
+
@ensured = []
|
116
124
|
end
|
117
125
|
|
118
126
|
def self.wrapper(hook)
|
119
127
|
timed_hooks_proc = proc do |t|
|
120
|
-
|
128
|
+
if (request = Thread.current[:sqreen_http_request])
|
129
|
+
request[:timed_hooks] << t if request[:timed_level] >= 1
|
130
|
+
end
|
121
131
|
end
|
122
132
|
timed_callbacks_proc = proc do |t|
|
123
|
-
|
133
|
+
if (request = Thread.current[:sqreen_http_request])
|
134
|
+
request[:timed_callbacks] << t if request[:timed_level] >= 1
|
135
|
+
end
|
124
136
|
end
|
125
137
|
|
126
138
|
Proc.new do |*args, &block|
|
127
|
-
|
139
|
+
request = Thread.current[:sqreen_http_request]
|
140
|
+
|
141
|
+
if Thread.current[:sqreen_hook_entered]
|
128
142
|
if hook.point.super?
|
129
143
|
return super(*args, &block)
|
130
144
|
else
|
@@ -132,60 +146,108 @@ module Sqreen
|
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
149
|
+
if request && request[:time_budget_expended] && (hook.before + hook.after + hook.raised + hook.ensured).none?(&:mandatory)
|
150
|
+
if request[:timed_level] >= 2
|
151
|
+
begin
|
152
|
+
request[:skipped_callbacks].concat(hook.before)
|
153
|
+
|
154
|
+
if hook.point.super?
|
155
|
+
return super(*args, &block)
|
156
|
+
else
|
157
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
158
|
+
end
|
159
|
+
rescue ::Exception # rubocop:disable Lint/RescueException
|
160
|
+
request[:skipped_callbacks].concat(hook.raised)
|
161
|
+
raise
|
162
|
+
else
|
163
|
+
request[:skipped_callbacks].concat(hook.after)
|
164
|
+
ensure
|
165
|
+
request[:skipped_callbacks].concat(hook.ensured)
|
166
|
+
end
|
167
|
+
else
|
168
|
+
if hook.point.super? # rubocop:disable Style/IfInsideElse
|
169
|
+
return super(*args, &block)
|
170
|
+
else
|
171
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
135
176
|
hook_point_super = hook.point.super?
|
136
177
|
logger = Sqreen::Graft.logger
|
137
178
|
logger_debug = Sqreen::Graft.logger.debug?
|
138
179
|
|
139
180
|
Timer.new(hook.point, &timed_hooks_proc).measure do |chrono|
|
140
|
-
|
181
|
+
# budget implies request
|
182
|
+
# TODO: make budget depend on a generic context (currently "request")
|
183
|
+
budget = request[:time_budget] if request
|
184
|
+
if budget
|
185
|
+
budget_threshold = request[:time_budget_threshold]
|
186
|
+
budget_ratio = request[:time_budget_ratio]
|
187
|
+
sqreen_timer = request[:sqreen_timer]
|
188
|
+
request_timer = request[:request_timer]
|
189
|
+
end
|
141
190
|
|
142
|
-
budget = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:time_budget]
|
143
|
-
timer = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timer] if budget
|
144
191
|
hooked_call = HookedCall.new(self, args)
|
145
192
|
|
146
193
|
begin
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
194
|
+
begin
|
195
|
+
sqreen_timer.start if budget
|
196
|
+
Thread.current[:sqreen_hook_entered] = true
|
197
|
+
|
198
|
+
# TODO: make Call have #ball to throw by cb
|
199
|
+
# TODO: can Call be the ball? r = catch(Call.new, &c)
|
200
|
+
# TODO: is catch return value a Call? a #dispatch?
|
201
|
+
# TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
|
202
|
+
# TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
|
203
|
+
# TODO: HookCall x CallbackCollection#each_with_call x Flow
|
204
|
+
# TODO: TimedHookCall TimedCallbackCall
|
205
|
+
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
206
|
+
|
207
|
+
request_elapsed = request_timer.elapsed if budget
|
208
|
+
|
209
|
+
hook.before.each do |c|
|
210
|
+
next if c.ignore && c.ignore.call
|
211
|
+
|
212
|
+
if budget && !c.mandatory
|
213
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
214
|
+
if budget_ratio && !request[:time_budget_expended]
|
215
|
+
fixed_budget = budget_threshold
|
216
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
217
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
218
|
+
else
|
219
|
+
remaining = budget_threshold - sqreen_elapsed
|
220
|
+
end
|
221
|
+
unless remaining > 0
|
222
|
+
request[:skipped_callbacks] << c
|
223
|
+
request[:time_budget_expended] = true
|
224
|
+
next
|
225
|
+
end
|
167
226
|
end
|
168
|
-
end
|
169
227
|
|
170
|
-
|
171
|
-
|
172
|
-
|
228
|
+
flow = catch(Ball.new) do |ball|
|
229
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
230
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
231
|
+
end
|
173
232
|
end
|
174
|
-
end
|
175
233
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
234
|
+
next unless c.flow && flow.is_a?(Flow)
|
235
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
236
|
+
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
237
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
238
|
+
break if flow.break?
|
239
|
+
end unless hook.disabled?
|
240
|
+
rescue StandardError => e
|
241
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
242
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
243
|
+
end
|
182
244
|
|
183
245
|
raise hooked_call.raise if hooked_call.raising
|
184
246
|
return hooked_call.return if hooked_call.returning
|
185
247
|
ensure
|
186
248
|
Thread.current[:sqreen_hook_entered] = false
|
187
|
-
|
188
|
-
end
|
249
|
+
sqreen_timer.stop if budget
|
250
|
+
end unless hook.before.empty?
|
189
251
|
|
190
252
|
begin
|
191
253
|
chrono.ignore do
|
@@ -196,98 +258,157 @@ module Sqreen
|
|
196
258
|
end
|
197
259
|
end
|
198
260
|
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
261
|
+
begin
|
262
|
+
sqreen_timer.start if budget
|
263
|
+
Thread.current[:sqreen_hook_entered] = true
|
264
|
+
hooked_call.raised = e
|
265
|
+
|
266
|
+
logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
|
267
|
+
raise if hook.raised.empty?
|
268
|
+
|
269
|
+
request_elapsed = request_timer.elapsed if budget
|
270
|
+
|
271
|
+
hook.raised.each do |c|
|
272
|
+
next if c.ignore && c.ignore.call
|
273
|
+
|
274
|
+
if budget && !c.mandatory
|
275
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
276
|
+
if budget_ratio && !request[:time_budget_expended]
|
277
|
+
fixed_budget = budget_threshold
|
278
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
279
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
280
|
+
else
|
281
|
+
remaining = budget_threshold - sqreen_elapsed
|
282
|
+
end
|
283
|
+
unless remaining > 0
|
284
|
+
request[:skipped_callbacks] << c
|
285
|
+
request[:time_budget_expended] = true
|
286
|
+
next
|
287
|
+
end
|
214
288
|
end
|
215
|
-
end
|
216
289
|
|
217
|
-
|
218
|
-
|
219
|
-
|
290
|
+
flow = catch(Ball.new) do |ball|
|
291
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
292
|
+
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)
|
293
|
+
end
|
220
294
|
end
|
221
|
-
end
|
222
295
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
296
|
+
next unless c.flow && flow.is_a?(Flow)
|
297
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
298
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
299
|
+
hooked_call.retrying = true if flow.retry?
|
300
|
+
break if flow.break?
|
301
|
+
end unless hook.disabled?
|
302
|
+
rescue StandardError => e
|
303
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
304
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
305
|
+
end
|
229
306
|
|
230
307
|
retry if hooked_call.retrying
|
231
308
|
raise hooked_call.raise if hooked_call.raising
|
232
309
|
return hooked_call.return if hooked_call.returning
|
233
310
|
raise
|
234
311
|
else
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
312
|
+
begin
|
313
|
+
sqreen_timer.start if budget
|
314
|
+
Thread.current[:sqreen_hook_entered] = true
|
315
|
+
|
316
|
+
# TODO: hooked_call.returning should be always false here?
|
317
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
|
318
|
+
|
319
|
+
request_elapsed = request_timer.elapsed if budget
|
320
|
+
|
321
|
+
hook.after.each do |c|
|
322
|
+
next if c.ignore && c.ignore.call
|
323
|
+
|
324
|
+
if budget && !c.mandatory
|
325
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
326
|
+
if budget_ratio && !request[:time_budget_expended]
|
327
|
+
fixed_budget = budget_threshold
|
328
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
329
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
330
|
+
else
|
331
|
+
remaining = budget_threshold - sqreen_elapsed
|
332
|
+
end
|
333
|
+
unless remaining > 0
|
334
|
+
request[:skipped_callbacks] << c
|
335
|
+
request[:time_budget_expended] = true
|
336
|
+
next
|
337
|
+
end
|
246
338
|
end
|
247
|
-
end
|
248
339
|
|
249
|
-
|
250
|
-
|
251
|
-
|
340
|
+
flow = catch(Ball.new) do |ball|
|
341
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
342
|
+
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)
|
343
|
+
end
|
252
344
|
end
|
253
|
-
end
|
254
345
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
346
|
+
next unless c.flow && flow.is_a?(Flow)
|
347
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
348
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
349
|
+
break if flow.break?
|
350
|
+
end unless hook.disabled?
|
351
|
+
rescue StandardError => e
|
352
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
353
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
354
|
+
end
|
260
355
|
|
261
356
|
raise hooked_call.raise if hooked_call.raising
|
262
357
|
return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
263
358
|
ensure
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
359
|
+
begin
|
360
|
+
# TODO: sqreen_timer.start if someone has thrown?
|
361
|
+
# TODO: sqreen_timer.stop at end of rescue+else?
|
362
|
+
# TODO: Thread.current[:sqreen_hook_entered] = true if neither rescue nor else ie thrown?
|
363
|
+
# TODO: Thread.current[:sqreen_hook_entered] = false at end of rescue+else? (risky?)
|
364
|
+
|
365
|
+
# TODO: uniform early bail out? (but don't forget sqreen_hook_entered and sqreen_timer)
|
366
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.ensured.empty?
|
367
|
+
|
368
|
+
# done at either rescue or else
|
369
|
+
# request_elapsed = request_timer.elapsed if budget # && !hook.ensured.empty?
|
370
|
+
|
371
|
+
hook.ensured.each do |c|
|
372
|
+
next if c.ignore && c.ignore.call
|
373
|
+
|
374
|
+
if budget && !c.mandatory
|
375
|
+
sqreen_elapsed = sqreen_timer.elapsed
|
376
|
+
if budget_ratio && !request[:time_budget_expended]
|
377
|
+
fixed_budget = budget_threshold
|
378
|
+
proportional_budget = (request_elapsed - sqreen_elapsed) * budget_ratio
|
379
|
+
remaining = (fixed_budget > proportional_budget ? fixed_budget : proportional_budget) - sqreen_elapsed
|
380
|
+
else
|
381
|
+
remaining = budget_threshold - sqreen_elapsed
|
382
|
+
end
|
383
|
+
unless remaining > 0
|
384
|
+
request[:skipped_callbacks] << c
|
385
|
+
request[:time_budget_expended] = true
|
386
|
+
next
|
387
|
+
end
|
274
388
|
end
|
275
|
-
end
|
276
389
|
|
277
|
-
|
278
|
-
|
279
|
-
|
390
|
+
flow = catch(Ball.new) do |ball|
|
391
|
+
Timer.new(c.name, &timed_callbacks_proc).measure(ignore: chrono) do
|
392
|
+
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)
|
393
|
+
end
|
280
394
|
end
|
281
|
-
end
|
282
395
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
396
|
+
next unless c.flow && flow.is_a?(Flow)
|
397
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
398
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
399
|
+
break if flow.break?
|
400
|
+
end unless hook.ensured.empty? || hook.disabled?
|
401
|
+
|
402
|
+
Thread.current[:sqreen_hook_entered] = false
|
403
|
+
sqreen_timer.stop if budget
|
404
|
+
rescue StandardError => e
|
405
|
+
Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
406
|
+
Sqreen::RemoteException.record(e) if Sqreen.queue
|
407
|
+
end
|
288
408
|
|
289
|
-
|
290
|
-
|
409
|
+
# TODO: should we run the following?
|
410
|
+
# raise hooked_call.raise if hooked_call.raising
|
411
|
+
# return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
291
412
|
end
|
292
413
|
end # chrono
|
293
414
|
end
|