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