sqreen 1.20.4-java → 1.21.0.beta3-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -24
- data/lib/sqreen/condition_evaluator.rb +6 -5
- data/lib/sqreen/conditionable.rb +24 -6
- data/lib/sqreen/deliveries/batch.rb +8 -1
- data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
- data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
- data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
- data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
- data/lib/sqreen/ecosystem/loggable.rb +13 -0
- data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
- data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
- data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
- data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
- data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
- data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
- data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
- data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
- data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
- data/lib/sqreen/ecosystem/module_api.rb +30 -0
- data/lib/sqreen/ecosystem/module_registry.rb +44 -0
- data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
- data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
- data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
- data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
- data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
- data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
- data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
- data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
- data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
- data/lib/sqreen/ecosystem.rb +96 -0
- data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
- data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
- data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
- data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
- data/lib/sqreen/ecosystem_integration.rb +87 -0
- data/lib/sqreen/frameworks/generic.rb +15 -1
- data/lib/sqreen/graft/call.rb +30 -1
- data/lib/sqreen/graft/hook.rb +88 -78
- data/lib/sqreen/graft/hook_point.rb +17 -10
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +7 -1
- data/lib/sqreen/metrics/req_detailed.rb +41 -0
- data/lib/sqreen/metrics.rb +1 -0
- data/lib/sqreen/remote_command.rb +3 -0
- data/lib/sqreen/rules/rule_cb.rb +2 -2
- data/lib/sqreen/runner.rb +44 -15
- data/lib/sqreen/session.rb +2 -0
- data/lib/sqreen/signals/conversions.rb +6 -1
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +3 -14
- data/lib/sqreen/weave/legacy/instrumentation.rb +145 -94
- metadata +41 -5
data/lib/sqreen/graft/hook.rb
CHANGED
@@ -7,17 +7,21 @@ 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 =
|
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 =
|
24
|
+
def self.add(hook_point, strategy = DEFAULT_STRATEGY, &block)
|
21
25
|
self[hook_point, strategy].add(&block)
|
22
26
|
end
|
23
27
|
|
@@ -30,7 +34,7 @@ module Sqreen
|
|
30
34
|
|
31
35
|
attr_reader :point
|
32
36
|
|
33
|
-
def initialize(hook_point, dependency_test = nil, strategy =
|
37
|
+
def initialize(hook_point, dependency_test = nil, strategy = DEFAULT_STRATEGY)
|
34
38
|
@disabled = false
|
35
39
|
@point = hook_point.is_a?(HookPoint) ? hook_point : HookPoint.new(hook_point, strategy)
|
36
40
|
@before = []
|
@@ -134,6 +138,13 @@ module Sqreen
|
|
134
138
|
request[:timed_callbacks] << t if request[:timed_level] >= 1
|
135
139
|
end
|
136
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
|
137
148
|
|
138
149
|
Proc.new do |*args, &block|
|
139
150
|
request = Thread.current[:sqreen_http_request]
|
@@ -181,18 +192,15 @@ module Sqreen
|
|
181
192
|
# budget implies request
|
182
193
|
# TODO: make budget depend on a generic context (currently "request")
|
183
194
|
budget = request[:time_budget] if request
|
184
|
-
if budget
|
185
|
-
budget_threshold = request[:time_budget_threshold]
|
186
|
-
budget_ratio = request[:time_budget_ratio]
|
195
|
+
if request && (budget || request[:timed_level] >= 1)
|
187
196
|
sqreen_timer = request[:sqreen_timer]
|
188
|
-
request_timer = request[:request_timer]
|
189
197
|
end
|
190
198
|
|
191
199
|
hooked_call = HookedCall.new(self, args)
|
192
200
|
|
193
201
|
begin
|
194
202
|
begin
|
195
|
-
sqreen_timer.start if
|
203
|
+
sqreen_timer.start if sqreen_timer
|
196
204
|
Thread.current[:sqreen_hook_entered] = true
|
197
205
|
|
198
206
|
# TODO: make Call have #ball to throw by cb
|
@@ -204,34 +212,34 @@ module Sqreen
|
|
204
212
|
# TODO: TimedHookCall TimedCallbackCall
|
205
213
|
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
206
214
|
|
207
|
-
request_elapsed = request_timer.elapsed if budget
|
208
|
-
|
209
215
|
hook.before.each do |c|
|
210
216
|
next if c.ignore && c.ignore.call
|
211
217
|
|
212
|
-
if budget && !c.mandatory
|
213
|
-
|
214
|
-
|
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
|
218
|
+
if budget && !c.mandatory && request[:time_budget_expended]
|
219
|
+
request[:skipped_callbacks] << c
|
220
|
+
next
|
226
221
|
end
|
227
222
|
|
223
|
+
remaining = budget - sqreen_timer.elapsed if budget
|
224
|
+
|
225
|
+
timer = nil
|
228
226
|
flow = catch(Ball.new) do |ball|
|
229
|
-
Timer.new(c.name, &timed_callbacks_proc)
|
227
|
+
timer = Timer.new(c.name, &timed_callbacks_proc)
|
228
|
+
timer.measure(ignore: chrono) do
|
230
229
|
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
231
230
|
end
|
232
231
|
end
|
233
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
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
234
241
|
next unless c.flow && flow.is_a?(Flow)
|
242
|
+
conditions_passed_proc[] if flow.passed_conditions?
|
235
243
|
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
236
244
|
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
237
245
|
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
@@ -246,7 +254,7 @@ module Sqreen
|
|
246
254
|
return hooked_call.return if hooked_call.returning
|
247
255
|
ensure
|
248
256
|
Thread.current[:sqreen_hook_entered] = false
|
249
|
-
sqreen_timer.stop if
|
257
|
+
sqreen_timer.stop if sqreen_timer
|
250
258
|
end unless hook.before.empty?
|
251
259
|
|
252
260
|
begin
|
@@ -259,41 +267,41 @@ module Sqreen
|
|
259
267
|
end
|
260
268
|
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
261
269
|
begin
|
262
|
-
sqreen_timer.start if
|
270
|
+
sqreen_timer.start if sqreen_timer
|
263
271
|
Thread.current[:sqreen_hook_entered] = true
|
264
272
|
hooked_call.raised = e
|
265
273
|
|
266
274
|
logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" } if logger_debug
|
267
275
|
raise if hook.raised.empty?
|
268
276
|
|
269
|
-
request_elapsed = request_timer.elapsed if budget
|
270
|
-
|
271
277
|
hook.raised.each do |c|
|
272
278
|
next if c.ignore && c.ignore.call
|
273
279
|
|
274
|
-
if budget && !c.mandatory
|
275
|
-
|
276
|
-
|
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
|
280
|
+
if budget && !c.mandatory && request[:time_budget_expended]
|
281
|
+
request[:skipped_callbacks] << c
|
282
|
+
next
|
288
283
|
end
|
289
284
|
|
285
|
+
remaining = budget - sqreen_timer.elapsed if budget
|
286
|
+
|
287
|
+
timer = nil
|
290
288
|
flow = catch(Ball.new) do |ball|
|
291
|
-
Timer.new(c.name, &timed_callbacks_proc)
|
289
|
+
timer = Timer.new(c.name, &timed_callbacks_proc)
|
290
|
+
timer.measure(ignore: chrono) do
|
292
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)
|
293
292
|
end
|
294
293
|
end
|
295
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
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
296
303
|
next unless c.flow && flow.is_a?(Flow)
|
304
|
+
conditions_passed_proc[] if flow.passed_conditions?
|
297
305
|
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
298
306
|
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
299
307
|
hooked_call.retrying = true if flow.retry?
|
@@ -310,40 +318,40 @@ module Sqreen
|
|
310
318
|
raise
|
311
319
|
else
|
312
320
|
begin
|
313
|
-
sqreen_timer.start if
|
321
|
+
sqreen_timer.start if sqreen_timer
|
314
322
|
Thread.current[:sqreen_hook_entered] = true
|
315
323
|
|
316
324
|
# TODO: hooked_call.returning should be always false here?
|
317
325
|
return hooked_call.returning ? hooked_call.return : hooked_call.returned if hook.after.empty?
|
318
326
|
|
319
|
-
request_elapsed = request_timer.elapsed if budget
|
320
|
-
|
321
327
|
hook.after.each do |c|
|
322
328
|
next if c.ignore && c.ignore.call
|
323
329
|
|
324
|
-
if budget && !c.mandatory
|
325
|
-
|
326
|
-
|
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
|
330
|
+
if budget && !c.mandatory && request[:time_budget_expended]
|
331
|
+
request[:skipped_callbacks] << c
|
332
|
+
next
|
338
333
|
end
|
339
334
|
|
335
|
+
remaining = budget - sqreen_timer.elapsed if budget
|
336
|
+
|
337
|
+
timer = nil
|
340
338
|
flow = catch(Ball.new) do |ball|
|
341
|
-
Timer.new(c.name, &timed_callbacks_proc)
|
339
|
+
timer = Timer.new(c.name, &timed_callbacks_proc)
|
340
|
+
timer.measure(ignore: chrono) do
|
342
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)
|
343
342
|
end
|
344
343
|
end
|
345
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
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
346
353
|
next unless c.flow && flow.is_a?(Flow)
|
354
|
+
conditions_passed_proc[] if flow.passed_conditions?
|
347
355
|
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
348
356
|
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
349
357
|
break if flow.break?
|
@@ -371,36 +379,38 @@ module Sqreen
|
|
371
379
|
hook.ensured.each do |c|
|
372
380
|
next if c.ignore && c.ignore.call
|
373
381
|
|
374
|
-
if budget && !c.mandatory
|
375
|
-
|
376
|
-
|
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
|
382
|
+
if budget && !c.mandatory && request[:time_budget_expended]
|
383
|
+
request[:skipped_callbacks] << c
|
384
|
+
next
|
388
385
|
end
|
389
386
|
|
387
|
+
remaining = budget - sqreen_timer.elapsed if budget
|
388
|
+
|
389
|
+
timer = nil
|
390
390
|
flow = catch(Ball.new) do |ball|
|
391
|
-
Timer.new(c.name, &timed_callbacks_proc)
|
391
|
+
timer = Timer.new(c.name, &timed_callbacks_proc)
|
392
|
+
timer.measure(ignore: chrono) do
|
392
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)
|
393
394
|
end
|
394
395
|
end
|
395
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
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
396
405
|
next unless c.flow && flow.is_a?(Flow)
|
406
|
+
conditions_passed_proc[] if flow.passed_conditions?
|
397
407
|
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
398
408
|
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
399
409
|
break if flow.break?
|
400
410
|
end unless hook.ensured.empty? || hook.disabled?
|
401
411
|
|
402
412
|
Thread.current[:sqreen_hook_entered] = false
|
403
|
-
sqreen_timer.stop if
|
413
|
+
sqreen_timer.stop if sqreen_timer
|
404
414
|
rescue StandardError => e
|
405
415
|
Sqreen::Weave.logger.debug { "exception:#{e.class} message:'#{e.message}' location:\"#{e.backtrace[0]}\"" }
|
406
416
|
Sqreen::RemoteException.record(e) if Sqreen.queue
|
@@ -23,6 +23,8 @@ module Sqreen
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class HookPoint
|
26
|
+
DEFAULT_STRATEGY = Module.respond_to?(:prepend) ? :prepend : :chain
|
27
|
+
|
26
28
|
def self.parse(hook_point)
|
27
29
|
klass_name, separator, method_name = hook_point.split(/(\#|\.)/, 2)
|
28
30
|
|
@@ -36,7 +38,7 @@ module Sqreen
|
|
36
38
|
|
37
39
|
attr_reader :klass_name, :method_kind, :method_name
|
38
40
|
|
39
|
-
def initialize(hook_point, strategy =
|
41
|
+
def initialize(hook_point, strategy = DEFAULT_STRATEGY)
|
40
42
|
@klass_name, @method_kind, @method_name = Sqreen::Graft::HookPoint.parse(hook_point)
|
41
43
|
@strategy = strategy
|
42
44
|
end
|
@@ -177,23 +179,30 @@ module Sqreen
|
|
177
179
|
|
178
180
|
private
|
179
181
|
|
180
|
-
def
|
182
|
+
def hook_spot(key)
|
181
183
|
target = klass_method? ? klass.singleton_class : klass
|
182
184
|
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
185
|
+
raise "Inconsistency detected: #{target} missing from its own ancestors" if mod.is_a?(Array)
|
186
|
+
|
187
|
+
[target, mod]
|
188
|
+
end
|
189
|
+
|
190
|
+
def prepend(key)
|
191
|
+
target, mod = hook_spot(key)
|
192
|
+
|
183
193
|
mod ||= HookSpot.new(key)
|
194
|
+
|
184
195
|
target.instance_eval { prepend(mod) }
|
185
196
|
end
|
186
197
|
|
187
198
|
def prepended?(key)
|
188
|
-
|
189
|
-
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
199
|
+
_, mod = hook_spot(key)
|
190
200
|
|
191
201
|
mod != nil
|
192
202
|
end
|
193
203
|
|
194
204
|
def overridden?(key)
|
195
|
-
|
196
|
-
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
205
|
+
_, mod = hook_spot(key)
|
197
206
|
|
198
207
|
(mod.instance_methods(false) + mod.protected_instance_methods(false) + mod.private_instance_methods(false)).include?(method_name)
|
199
208
|
end
|
@@ -202,8 +211,7 @@ module Sqreen
|
|
202
211
|
hook_point = self
|
203
212
|
method_name = @method_name
|
204
213
|
|
205
|
-
|
206
|
-
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
214
|
+
_, mod = hook_spot(key)
|
207
215
|
|
208
216
|
mod.instance_eval do
|
209
217
|
if hook_point.private_method?
|
@@ -221,8 +229,7 @@ module Sqreen
|
|
221
229
|
def unoverride(key)
|
222
230
|
method_name = @method_name
|
223
231
|
|
224
|
-
|
225
|
-
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
232
|
+
_, mod = hook_spot(key)
|
226
233
|
|
227
234
|
mod.instance_eval { remove_method(method_name) }
|
228
235
|
end
|
@@ -56,6 +56,12 @@ module Sqreen
|
|
56
56
|
when AggregatedMetric
|
57
57
|
logger.warn "Aggregated metric event in non-signal mode. Signals disabled at runtime?"
|
58
58
|
next
|
59
|
+
when Sqreen::Kit::Signals::Signal
|
60
|
+
logger.warn "Signal event in non-signal mode"
|
61
|
+
next
|
62
|
+
when Sqreen::Kit::Signals::Trace
|
63
|
+
logger.warn "Trace event in non-signal mode"
|
64
|
+
next
|
59
65
|
when Attack # in practice only found inside req rec
|
60
66
|
EventToHash.convert_attack event
|
61
67
|
when RemoteException
|
@@ -73,7 +79,7 @@ module Sqreen
|
|
73
79
|
tally = Hash[events.group_by(&:class).map { |k, v| [k, v.count] }]
|
74
80
|
"Doing batch with the following tally of event types: #{tally}"
|
75
81
|
end
|
76
|
-
post('batch', { batch: batch }, {}, RETRY_MANY)
|
82
|
+
post('batch', { batch: batch.compact }, {}, RETRY_MANY)
|
77
83
|
end
|
78
84
|
|
79
85
|
private
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'sqreen/mono_time'
|
3
|
+
require 'sqreen/metrics/base'
|
4
|
+
begin
|
5
|
+
require 'sq_detailed_metrics'
|
6
|
+
rescue LoadError => _e # rubocop:disable Lint/HandleExceptions
|
7
|
+
end
|
8
|
+
|
9
|
+
module Sqreen
|
10
|
+
module Metric
|
11
|
+
class ReqDetailed < Base
|
12
|
+
attr_reader :num_requests
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
raise 'SqDetailedMetrics unavailable' unless defined?(SqDetailedMetrics)
|
16
|
+
super(opts)
|
17
|
+
@coll = SqDetailedMetrics::RequestCollection.new
|
18
|
+
@start_time = Sqreen.time
|
19
|
+
@num_requests = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [SqDetailedMetrics::Request] value
|
23
|
+
def update(_key, value)
|
24
|
+
@coll << value
|
25
|
+
@num_requests += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def next_sample(time)
|
29
|
+
data = @coll.serialize
|
30
|
+
@num_requests = 0
|
31
|
+
return nil unless data
|
32
|
+
|
33
|
+
{
|
34
|
+
OBSERVATION_KEY => { 'v1' => Base64.strict_encode64(data) },
|
35
|
+
START_KEY => @start_time,
|
36
|
+
FINISH_KEY => (@start_time = time),
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/sqreen/metrics.rb
CHANGED
@@ -23,6 +23,7 @@ module Sqreen
|
|
23
23
|
:ips_whitelist => :change_whitelisted_ips,
|
24
24
|
:get_bundle => :upload_bundle,
|
25
25
|
:performance_budget => :change_performance_budget,
|
26
|
+
:tracing_enable => :tracing_enable,
|
26
27
|
}.freeze
|
27
28
|
|
28
29
|
attr_reader :uuid
|
@@ -40,6 +41,8 @@ module Sqreen
|
|
40
41
|
begin
|
41
42
|
output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
|
42
43
|
rescue => e
|
44
|
+
Sqreen.log.warn { "Command failed with #{e}" }
|
45
|
+
Sqreen.log.debug { e.backtrace.map { |x| " #{x}" }.join("\n") }
|
43
46
|
Sqreen::RemoteException.record(e)
|
44
47
|
return { :status => false, :reason => "error: #{e.inspect}" }
|
45
48
|
end
|
data/lib/sqreen/rules/rule_cb.rb
CHANGED
@@ -90,9 +90,9 @@ module Sqreen
|
|
90
90
|
framework.observe(:sqreen_exceptions, payload)
|
91
91
|
end
|
92
92
|
|
93
|
-
# Recommend taking an action (
|
93
|
+
# Recommend taking an action (optionally adding more data/context)
|
94
94
|
#
|
95
|
-
# This will format the requested action and
|
95
|
+
# This will format the requested action and optionally
|
96
96
|
# override it if it should not be taken (should not block for example)
|
97
97
|
def advise_action(action, additional_data = {})
|
98
98
|
return if action.nil? && additional_data.empty?
|
data/lib/sqreen/runner.rb
CHANGED
@@ -14,6 +14,7 @@ require 'sqreen/log'
|
|
14
14
|
require 'sqreen/agent_message'
|
15
15
|
require 'sqreen/rules'
|
16
16
|
require 'sqreen/session'
|
17
|
+
require 'sqreen/version'
|
17
18
|
require 'sqreen/remote_command'
|
18
19
|
require 'sqreen/capped_queue'
|
19
20
|
require 'sqreen/metrics_store'
|
@@ -26,6 +27,7 @@ require 'sqreen/legacy/instrumentation'
|
|
26
27
|
require 'sqreen/call_countable'
|
27
28
|
require 'sqreen/weave/legacy/instrumentation'
|
28
29
|
require 'sqreen/kit/configuration'
|
30
|
+
require 'sqreen/ecosystem_integration'
|
29
31
|
|
30
32
|
module Sqreen
|
31
33
|
@features = {}
|
@@ -52,10 +54,6 @@ module Sqreen
|
|
52
54
|
@queue ||= CappedQueue.new(MAX_QUEUE_LENGTH)
|
53
55
|
end
|
54
56
|
|
55
|
-
def update_queue(queue)
|
56
|
-
@queue = queue
|
57
|
-
end
|
58
|
-
|
59
57
|
def observations_queue
|
60
58
|
@observations_queue ||= CappedQueue.new(MAX_OBS_QUEUE_LENGTH)
|
61
59
|
end
|
@@ -104,8 +102,8 @@ module Sqreen
|
|
104
102
|
# we may want to do that in a thread in order to prevent delaying app
|
105
103
|
# startup
|
106
104
|
# set_at_exit do not place a global at_exit (used for testing)
|
105
|
+
# @param [Sqreen::Frameworks::GenericFramework] framework
|
107
106
|
def initialize(configuration, framework, set_at_exit = true, session_class = Sqreen::Session)
|
108
|
-
Sqreen.update_queue(CappedQueue.new(MAX_QUEUE_LENGTH))
|
109
107
|
@logged_out_tried = false
|
110
108
|
@configuration = configuration
|
111
109
|
@framework = framework
|
@@ -132,6 +130,7 @@ module Sqreen
|
|
132
130
|
Sqreen::Kit::Configuration.ingestion_url = chosen_endpoints.ingestion.url
|
133
131
|
Sqreen::Kit::Configuration.certificate_store = chosen_endpoints.ingestion.ca_store
|
134
132
|
Sqreen::Kit::Configuration.proxy_url = @proxy_url
|
133
|
+
Sqreen::Kit::Configuration.default_source = "sqreen:agent:ruby:#{Sqreen::VERSION}"
|
135
134
|
|
136
135
|
register_exit_cb if set_at_exit
|
137
136
|
|
@@ -142,7 +141,12 @@ module Sqreen
|
|
142
141
|
end
|
143
142
|
|
144
143
|
if @configuration.get(:weave) || needs_weave.call
|
145
|
-
|
144
|
+
# XXX: don't get updated
|
145
|
+
opts = {
|
146
|
+
perf_req_metrics_max_reqs: Sqreen.features['perf_req_metrics_max_reqs'],
|
147
|
+
perf_req_metrics_period: Sqreen.features['perf_req_metrics_period'],
|
148
|
+
}
|
149
|
+
@instrumenter = Sqreen::Weave::Legacy::Instrumentation.new(metrics_engine, opts)
|
146
150
|
else
|
147
151
|
@instrumenter = Sqreen::Legacy::Instrumentation.new(metrics_engine)
|
148
152
|
end
|
@@ -168,6 +172,12 @@ module Sqreen
|
|
168
172
|
end
|
169
173
|
self.features = wanted_features
|
170
174
|
|
175
|
+
@ecosystem_integration = EcosystemIntegration.new(framework,
|
176
|
+
Sqreen.queue,
|
177
|
+
create_binning_metric_proc)
|
178
|
+
framework.req_start_cb = @ecosystem_integration.method(:request_start)
|
179
|
+
framework.req_end_cb = @ecosystem_integration.method(:request_end)
|
180
|
+
|
171
181
|
# Ensure a deliverer is there unless features have set it first
|
172
182
|
self.deliverer ||= Deliveries::Simple.new(session)
|
173
183
|
context_infos = {}
|
@@ -268,6 +278,10 @@ module Sqreen
|
|
268
278
|
rulespack_id, rules = load_rules(context_infos)
|
269
279
|
@framework.instrument_when_ready!(instrumenter, rules)
|
270
280
|
Sqreen.log.info 'Instrumentation set up'
|
281
|
+
|
282
|
+
# XXX: ecosystem instrumentation should likely be deferred
|
283
|
+
# the same way the rest might be
|
284
|
+
@ecosystem_integration.init unless Sqreen.features['disable_ecosystem']
|
271
285
|
rulespack_id.to_s
|
272
286
|
end
|
273
287
|
|
@@ -392,15 +406,8 @@ module Sqreen
|
|
392
406
|
prev = Sqreen::Weave::Budget.current
|
393
407
|
prev = prev.to_h if prev
|
394
408
|
|
395
|
-
budget_s = budget.to_f / 1000 if budget
|
396
|
-
|
397
|
-
feature = features['performance_budget']
|
398
|
-
if feature
|
399
|
-
budget_s = feature['threshold'] if feature.key?('threshold')
|
400
|
-
ratio = feature['ratio'] if feature.key?('ratio')
|
401
|
-
end
|
402
|
-
|
403
|
-
Sqreen::Weave::Budget.update(threshold: budget_s, ratio: ratio)
|
409
|
+
budget_s = budget.to_f / 1000.0 if budget
|
410
|
+
Sqreen::Weave::Budget.update(threshold: budget_s)
|
404
411
|
else
|
405
412
|
prev = Sqreen.performance_budget
|
406
413
|
Sqreen.update_performance_budget(budget)
|
@@ -409,6 +416,13 @@ module Sqreen
|
|
409
416
|
{ :was => prev }
|
410
417
|
end
|
411
418
|
|
419
|
+
# @param [String] tracing_id_prefix
|
420
|
+
# @param [Array<Hash{String=>Object}>] sampling_config
|
421
|
+
def tracing_enable(tracing_id_prefix, sampling_config, _context_infos = {})
|
422
|
+
@ecosystem_integration.handle_tracing_command(tracing_id_prefix, sampling_config)
|
423
|
+
{ status: true }
|
424
|
+
end
|
425
|
+
|
412
426
|
def upload_bundle(_context_infos = {})
|
413
427
|
t = Time.now
|
414
428
|
session.post_bundle(RuntimeInfos.dependencies_signature, RuntimeInfos.dependencies)
|
@@ -541,6 +555,21 @@ module Sqreen
|
|
541
555
|
|
542
556
|
private
|
543
557
|
|
558
|
+
def create_binning_metric_proc
|
559
|
+
lambda do |metric_name|
|
560
|
+
return if @metrics_engine.metric?(metric_name)
|
561
|
+
metrics_engine.create_metric(
|
562
|
+
'name' => metric_name,
|
563
|
+
'kind' => 'Binning',
|
564
|
+
'period' => Sqreen.features['performance_metrics_period'] || 60,
|
565
|
+
'options' => {
|
566
|
+
'base' => Sqreen.features['perf_base'] || PerformanceNotifications::BinnedMetrics::DEFAULT_PERF_BASE,
|
567
|
+
'factor' => Sqreen.features['perf_unit'] || PerformanceNotifications::BinnedMetrics::DEFAULT_PERF_UNIT,
|
568
|
+
},
|
569
|
+
)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
544
573
|
def post_endpoint_testing_msgs(chosen_endpoints)
|
545
574
|
chosen_endpoints.messages.each do |msg|
|
546
575
|
session.post_agent_message(@framework, msg)
|
data/lib/sqreen/session.rb
CHANGED
@@ -249,8 +249,10 @@ module Sqreen
|
|
249
249
|
end
|
250
250
|
Sqreen.log.info 'Login success.'
|
251
251
|
@session_id = res['session_id']
|
252
|
+
|
252
253
|
Kit::Configuration.session_key = @session_id
|
253
254
|
Kit.reset
|
255
|
+
|
254
256
|
Sqreen.log.debug { "received session_id #{@session_id}" }
|
255
257
|
Sqreen.logged_in = true
|
256
258
|
res
|
@@ -118,6 +118,7 @@ module Sqreen
|
|
118
118
|
signals += req_rec.processed_sdk_calls
|
119
119
|
.select { |h| h[:name] == :track }
|
120
120
|
.map { |h| convert_track(h) }
|
121
|
+
signals += (observed[:signals] || [])
|
121
122
|
|
122
123
|
trace = Kit::Signals::Specialized::HttpTrace.new(
|
123
124
|
actor: Kit::Signals::Actor.new(
|
@@ -137,7 +138,7 @@ module Sqreen
|
|
137
138
|
trace
|
138
139
|
end
|
139
140
|
|
140
|
-
# @
|
141
|
+
# @return [Array<Sqreen::Kit::Signals::Signal|Sqreen::Kit::Signals::Trace>]
|
141
142
|
def convert_batch(batch)
|
142
143
|
batch.map do |evt|
|
143
144
|
case evt
|
@@ -147,6 +148,10 @@ module Sqreen
|
|
147
148
|
convert_metric_sample(evt)
|
148
149
|
when RequestRecord
|
149
150
|
convert_req_record(evt)
|
151
|
+
when Sqreen::Kit::Signals::Signal
|
152
|
+
evt
|
153
|
+
when Sqreen::Kit::Signals::Trace
|
154
|
+
evt
|
150
155
|
else
|
151
156
|
raise NotImplementedError, "Unknown type of event in batch: #{evt}"
|
152
157
|
end
|
data/lib/sqreen/version.rb
CHANGED