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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -24
  3. data/lib/sqreen/condition_evaluator.rb +6 -5
  4. data/lib/sqreen/conditionable.rb +24 -6
  5. data/lib/sqreen/deliveries/batch.rb +8 -1
  6. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  7. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  8. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  9. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  10. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  11. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  12. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  13. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  14. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  15. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  16. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  17. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  18. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  19. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  20. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  21. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  22. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  23. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  24. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  25. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  26. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  27. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  28. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  29. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  30. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  31. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  32. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  33. data/lib/sqreen/ecosystem.rb +96 -0
  34. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  35. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  36. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  37. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  38. data/lib/sqreen/ecosystem_integration.rb +87 -0
  39. data/lib/sqreen/frameworks/generic.rb +15 -1
  40. data/lib/sqreen/graft/call.rb +30 -1
  41. data/lib/sqreen/graft/hook.rb +88 -78
  42. data/lib/sqreen/graft/hook_point.rb +17 -10
  43. data/lib/sqreen/legacy/old_event_submission_strategy.rb +7 -1
  44. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  45. data/lib/sqreen/metrics.rb +1 -0
  46. data/lib/sqreen/remote_command.rb +3 -0
  47. data/lib/sqreen/rules/rule_cb.rb +2 -2
  48. data/lib/sqreen/runner.rb +44 -15
  49. data/lib/sqreen/session.rb +2 -0
  50. data/lib/sqreen/signals/conversions.rb +6 -1
  51. data/lib/sqreen/version.rb +1 -1
  52. data/lib/sqreen/weave/budget.rb +3 -14
  53. data/lib/sqreen/weave/legacy/instrumentation.rb +145 -94
  54. metadata +41 -5
@@ -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 = :chain)
20
+ def self.[](hook_point, strategy = DEFAULT_STRATEGY)
17
21
  @hooks[hook_point] ||= new(hook_point, nil, strategy)
18
22
  end
19
23
 
20
- def self.add(hook_point, strategy = :chain, &block)
24
+ def self.add(hook_point, strategy = DEFAULT_STRATEGY, &block)
21
25
  self[hook_point, strategy].add(&block)
22
26
  end
23
27
 
@@ -30,7 +34,7 @@ module Sqreen
30
34
 
31
35
  attr_reader :point
32
36
 
33
- def initialize(hook_point, dependency_test = nil, strategy = :chain)
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 budget
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
- 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
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).measure(ignore: chrono) do
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 budget
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 budget
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
- 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
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).measure(ignore: chrono) do
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 budget
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
- 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
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).measure(ignore: chrono) do
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
- 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
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).measure(ignore: chrono) do
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 budget
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 = :chain)
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 prepend(key)
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
- target = klass_method? ? klass.singleton_class : klass
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
- target = klass_method? ? klass.singleton_class : klass
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
- target = klass_method? ? klass.singleton_class : klass
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
- target = klass_method? ? klass.singleton_class : klass
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
@@ -7,3 +7,4 @@ require 'sqreen/metrics/collect'
7
7
  require 'sqreen/metrics/average'
8
8
  require 'sqreen/metrics/sum'
9
9
  require 'sqreen/metrics/binning'
10
+ require 'sqreen/metrics/req_detailed'
@@ -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
@@ -90,9 +90,9 @@ module Sqreen
90
90
  framework.observe(:sqreen_exceptions, payload)
91
91
  end
92
92
 
93
- # Recommend taking an action (optionnally adding more data/context)
93
+ # Recommend taking an action (optionally adding more data/context)
94
94
  #
95
- # This will format the requested action and optionnally
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
- @instrumenter = Sqreen::Weave::Legacy::Instrumentation.new(metrics_engine)
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)
@@ -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
- # @param [Array<Sqreen::Kit::Signals::Signal|Sqreen::Kit::Signals::Trace>] batch
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
@@ -4,5 +4,5 @@
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
6
  module Sqreen
7
- VERSION = '1.20.4'.freeze
7
+ VERSION = '1.21.0.beta3'.freeze
8
8
  end