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