sqreen 1.19.1-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 (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/agent_message.rb +20 -0
  7. data/lib/sqreen/aggregated_metric.rb +25 -0
  8. data/lib/sqreen/attack_detected.html +1 -2
  9. data/lib/sqreen/ca.crt +24 -0
  10. data/lib/sqreen/condition_evaluator.rb +9 -2
  11. data/lib/sqreen/conditionable.rb +24 -6
  12. data/lib/sqreen/configuration.rb +11 -5
  13. data/lib/sqreen/deferred_logger.rb +50 -14
  14. data/lib/sqreen/deliveries/batch.rb +12 -2
  15. data/lib/sqreen/deliveries/simple.rb +4 -0
  16. data/lib/sqreen/deprecation.rb +38 -0
  17. data/lib/sqreen/ecosystem.rb +96 -0
  18. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  19. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  20. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  21. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  22. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  23. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  24. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  25. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  26. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  27. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  32. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  33. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  34. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  37. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  38. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  39. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  40. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  41. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  42. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  43. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  44. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  45. data/lib/sqreen/ecosystem_integration.rb +87 -0
  46. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  47. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  48. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  49. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  50. data/lib/sqreen/endpoint_testing.rb +184 -0
  51. data/lib/sqreen/event.rb +7 -5
  52. data/lib/sqreen/events/attack.rb +23 -18
  53. data/lib/sqreen/events/remote_exception.rb +0 -22
  54. data/lib/sqreen/events/request_record.rb +15 -71
  55. data/lib/sqreen/frameworks/generic.rb +24 -1
  56. data/lib/sqreen/frameworks/rails.rb +0 -7
  57. data/lib/sqreen/frameworks/request_recorder.rb +15 -2
  58. data/lib/sqreen/graft/call.rb +106 -19
  59. data/lib/sqreen/graft/callback.rb +1 -1
  60. data/lib/sqreen/graft/hook.rb +212 -100
  61. data/lib/sqreen/graft/hook_point.rb +18 -11
  62. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  63. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  64. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  65. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  66. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  67. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  68. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  69. data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
  70. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  71. data/lib/sqreen/log.rb +3 -2
  72. data/lib/sqreen/log/loggable.rb +2 -1
  73. data/lib/sqreen/logger.rb +24 -0
  74. data/lib/sqreen/metrics.rb +1 -0
  75. data/lib/sqreen/metrics/base.rb +3 -0
  76. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  77. data/lib/sqreen/metrics_store.rb +33 -12
  78. data/lib/sqreen/null_logger.rb +22 -0
  79. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  80. data/lib/sqreen/remote_command.rb +4 -0
  81. data/lib/sqreen/rules.rb +12 -6
  82. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  83. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  84. data/lib/sqreen/rules/not_found_cb.rb +2 -0
  85. data/lib/sqreen/rules/rule_cb.rb +6 -2
  86. data/lib/sqreen/rules/waf_cb.rb +16 -13
  87. data/lib/sqreen/runner.rb +138 -16
  88. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  89. data/lib/sqreen/session.rb +53 -43
  90. data/lib/sqreen/signals/conversions.rb +288 -0
  91. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  92. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  93. data/lib/sqreen/version.rb +1 -1
  94. data/lib/sqreen/weave/budget.rb +35 -0
  95. data/lib/sqreen/weave/legacy/instrumentation.rb +277 -135
  96. data/lib/sqreen/worker.rb +6 -2
  97. metadata +86 -10
  98. data/lib/sqreen/backport.rb +0 -9
  99. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  100. data/lib/sqreen/backport/original_name.rb +0 -88
  101. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -61,7 +61,7 @@ module Sqreen
61
61
  obj.each do |k, v|
62
62
  ck = k.is_a?(String) ? k.downcase : k
63
63
  if @keys.include?(ck)
64
- redacted << v
64
+ redacted += SensitiveDataRedactor.all_strings(v)
65
65
  v = MASK
66
66
  else
67
67
  v, r = redact(v)
@@ -74,39 +74,27 @@ module Sqreen
74
74
  [result, redacted]
75
75
  end
76
76
 
77
- def redact_attacks!(attacks, values)
78
- return attacks if values.empty?
79
-
80
- values = values.map { |v| v.downcase if v.is_a?(String) }
81
-
82
- attacks.each do |e|
83
- next(e) unless e[:infos]
84
- next(e) unless e[:infos][:waf_data]
85
-
86
- parsed = JSON.parse(e[:infos][:waf_data])
87
- redacted = parsed.each do |w|
88
- next unless (filters = w['filter'])
89
-
90
- filters.each do |f|
91
- next unless (v = f['resolved_value'])
92
- next unless values.include?(v.downcase)
77
+ class << self
78
+ def all_strings(v)
79
+ accum = []
80
+ all_strings_impl(v, accum)
81
+ accum
82
+ end
93
83
 
94
- f['match_status'] = MASK
95
- f['resolved_value'] = MASK
84
+ private
85
+
86
+ def all_strings_impl(obj, accum)
87
+ case obj
88
+ when String
89
+ accum << obj
90
+ when Array
91
+ obj.each { |el| all_strings_impl(el, accum) }
92
+ when Hash
93
+ obj.each do |k, v|
94
+ all_strings_impl(k, accum)
95
+ all_strings_impl(v, accum)
96
96
  end
97
97
  end
98
- e[:infos][:waf_data] = JSON.dump(redacted)
99
- end
100
- end
101
-
102
- def redact_exceptions!(exceptions, values)
103
- return exceptions if values.empty?
104
-
105
- exceptions.each do |e|
106
- next(e) unless e[:infos]
107
- next(e) unless e[:infos][:waf]
108
-
109
- e[:infos][:waf].delete(:args)
110
98
  end
111
99
  end
112
100
  end
@@ -11,6 +11,10 @@ require 'sqreen/events/attack'
11
11
  require 'sqreen/events/request_record'
12
12
  require 'sqreen/exception'
13
13
  require 'sqreen/safe_json'
14
+ require 'sqreen/kit'
15
+ require 'sqreen/kit/configuration'
16
+ require 'sqreen/signals/signals_submission_strategy'
17
+ require 'sqreen/legacy/old_event_submission_strategy'
14
18
 
15
19
  require 'net/https'
16
20
  require 'uri'
@@ -41,13 +45,12 @@ module Sqreen
41
45
  RETRY_MANY = 301
42
46
 
43
47
  MUTEX = Mutex.new
44
- METRICS_KEY = 'metrics'.freeze
45
48
 
46
49
  @@path_prefix = '/sqreen/v0/'
47
50
 
48
51
  attr_accessor :request_compression
49
52
 
50
- def initialize(server_url, token, app_name = nil)
53
+ def initialize(server_url, cert_store, token, app_name = nil, proxy_url = nil)
51
54
  @token = token
52
55
  @app_name = app_name
53
56
  @session_id = nil
@@ -59,15 +62,29 @@ module Sqreen
59
62
  uri = parse_uri(server_url)
60
63
  use_ssl = (uri.scheme == 'https')
61
64
 
65
+ proxy_params = []
66
+ if proxy_url
67
+ proxy_uri = parse_uri(proxy_url)
68
+ proxy_params = [proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
69
+ end
70
+
62
71
  @req_nb = 0
63
72
 
64
- @http = Net::HTTP.new(uri.host, uri.port)
73
+ @http = Net::HTTP.new(uri.host, uri.port, *proxy_params)
65
74
  @http.use_ssl = use_ssl
66
- if use_ssl
67
- cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
68
- cert_store = OpenSSL::X509::Store.new
69
- cert_store.add_file cert_file
70
- @http.cert_store = cert_store
75
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY'] # for testing
76
+ @http.cert_store = cert_store if use_ssl
77
+ self.use_signals = false
78
+ end
79
+
80
+ def use_signals=(do_use)
81
+ return if do_use == @use_signals
82
+
83
+ @use_signals = do_use
84
+ if do_use
85
+ @evt_sub_strategy = Sqreen::Signals::SignalsSubmissionStrategy.new
86
+ else
87
+ @evt_sub_strategy = Sqreen::Legacy::OldEventSubmissionStrategy.new(method(:post))
71
88
  end
72
89
  end
73
90
 
@@ -218,10 +235,7 @@ module Sqreen
218
235
  end
219
236
 
220
237
  def login(framework)
221
- headers = {
222
- 'x-api-key' => @token,
223
- 'x-app-name' => @app_name || framework.application_name,
224
- }.reject { |k, v| v == nil }
238
+ headers = prelogin_auth_headers(framework)
225
239
 
226
240
  Sqreen.log.warn "Using app name: #{headers['x-app-name']}"
227
241
 
@@ -235,6 +249,10 @@ module Sqreen
235
249
  end
236
250
  Sqreen.log.info 'Login success.'
237
251
  @session_id = res['session_id']
252
+
253
+ Kit::Configuration.session_key = @session_id
254
+ Kit.reset
255
+
238
256
  Sqreen.log.debug { "received session_id #{@session_id}" }
239
257
  Sqreen.logged_in = true
240
258
  res
@@ -246,20 +264,24 @@ module Sqreen
246
264
 
247
265
  def heartbeat(cmd_res = {}, metrics = [])
248
266
  payload = {}
249
- payload['metrics'] = metrics unless metrics.nil? || metrics.empty?
267
+ unless metrics.nil? || metrics.empty?
268
+ # never reached with signals
269
+ payload['metrics'] = metrics.map do |m|
270
+ Sqreen::Legacy::EventToHash.convert_agg_metric(m)
271
+ end
272
+ end
250
273
  payload['command_results'] = cmd_res unless cmd_res.nil? || cmd_res.empty?
251
274
 
252
275
  post('app-beat', payload.empty? ? nil : payload, {}, RETRY_MANY)
253
276
  end
254
277
 
255
278
  def post_metrics(metrics)
256
- return if metrics.nil? || metrics.empty?
257
- payload = { METRICS_KEY => metrics }
258
- post(METRICS_KEY, payload, {}, RETRY_MANY)
279
+ @evt_sub_strategy.post_metrics(metrics)
259
280
  end
260
281
 
282
+ # XXX never called
261
283
  def post_attack(attack)
262
- post('attack', attack.to_hash, {}, RETRY_MANY)
284
+ @evt_sub_strategy.post_attack(attack)
263
285
  end
264
286
 
265
287
  def post_bundle(bundle_sig, dependencies)
@@ -271,33 +293,22 @@ module Sqreen
271
293
  end
272
294
 
273
295
  def post_request_record(request_record)
274
- post('request_record', request_record.to_hash, {}, RETRY_MANY)
296
+ @evt_sub_strategy.post_request_record(request_record)
275
297
  end
276
298
 
277
299
  # Post an exception to Sqreen for analysis
278
300
  # @param exception [RemoteException] Exception and context to be sent over
279
301
  def post_sqreen_exception(exception)
280
- post('sqreen_exception', exception.to_hash, {}, 5)
281
- rescue StandardError => e
282
- Sqreen.log.warn(format('Could not post exception (network down? %s) %s',
283
- e.inspect,
284
- exception.to_hash.inspect))
285
- nil
302
+ @evt_sub_strategy.post_sqreen_exception(exception)
286
303
  end
287
304
 
288
- BATCH_KEY = 'batch'.freeze
289
- EVENT_TYPE_KEY = 'event_type'.freeze
290
305
  def post_batch(events)
291
- batch = events.map do |event|
292
- h = event.to_hash
293
- h[EVENT_TYPE_KEY] = event_kind(event)
294
- h
295
- end
296
- Sqreen.log.debug do
297
- tally = Hash[events.group_by(&:class).map{ |k,v| [k, v.count] }]
298
- "Doing batch with the following tally of event types: #{tally}"
299
- end
300
- post(BATCH_KEY, { BATCH_KEY => batch }, {}, RETRY_MANY)
306
+ @evt_sub_strategy.post_batch(events)
307
+ end
308
+
309
+ def post_agent_message(framework, agent_message)
310
+ headers = prelogin_auth_headers(framework)
311
+ post('app_agent_message', agent_message.to_h, headers, 0)
301
312
  end
302
313
 
303
314
  # Perform agent logout
@@ -314,14 +325,13 @@ module Sqreen
314
325
  disconnect
315
326
  end
316
327
 
317
- protected
328
+ private
318
329
 
319
- def event_kind(event)
320
- case event
321
- when Sqreen::RemoteException then 'sqreen_exception'
322
- when Sqreen::Attack then 'attack'
323
- when Sqreen::RequestRecord then 'request_record'
324
- end
330
+ def prelogin_auth_headers(framework)
331
+ {
332
+ 'x-api-key' => @token,
333
+ 'x-app-name' => @app_name || framework.application_name,
334
+ }.reject { |_k, v| v == nil }
325
335
  end
326
336
  end
327
337
  end
@@ -0,0 +1,288 @@
1
+ require 'sqreen/version'
2
+ require 'sqreen/rules/rule_cb'
3
+ require 'sqreen/metrics/base'
4
+ require 'sqreen/metrics/binning'
5
+ require 'sqreen/signals/http_trace_redaction'
6
+ require 'sqreen/kit/signals/signal_attributes'
7
+ require 'sqreen/kit/signals/specialized/aggregated_metric'
8
+ require 'sqreen/kit/signals/specialized/attack'
9
+ require 'sqreen/kit/signals/specialized/binning_metric'
10
+ require 'sqreen/kit/signals/specialized/sqreen_exception'
11
+ require 'sqreen/kit/signals/specialized/http_trace'
12
+ require 'sqreen/kit/signals/specialized/sdk_track_call'
13
+
14
+ module Sqreen
15
+ module Signals
16
+ module Conversions # rubocop:disable Metrics/ModuleLength
17
+ class << self
18
+ # @param [Sqreen::AggregatedMetric] agg
19
+ # @return [Sqreen::Kit::Signals::Metric]
20
+ def convert_metric_sample(agg)
21
+ attrs = {
22
+ signal_name: "sq.agent.metric.#{agg.name}",
23
+ source: if agg.rule
24
+ "sqreen:rules:#{agg.rule.rulespack_id}:#{agg.rule.rule_name}"
25
+ else
26
+ agent_gen_source
27
+ end,
28
+ time: agg.finish,
29
+ }
30
+
31
+ if agg.metric.is_a?(Sqreen::Metric::Binning)
32
+ conv_binning_metric(agg, attrs)
33
+ else
34
+ conv_generic_metric(agg, attrs)
35
+ end
36
+ end
37
+
38
+ # @param [Sqreen::Attack] attack
39
+ # XXX: not used because we don't use Sqreen::Attack
40
+ def convert_attack(attack)
41
+ # no need to set actor/context as we only include them in request records/traces
42
+ Kit::Signals::Specialized::Attack.new(
43
+ signal_name: "sq.agent.attack.#{attack.attack_type}",
44
+ source: "sqreen:rule:#{attack.rulespack_id}:#{attack.rule_name}",
45
+ time: attack.time,
46
+ location: Kit::Signals::Location.new(stack_trace: attack.backtrace),
47
+ payload: Kit::Signals::Specialized::Attack::Payload.new(
48
+ test: attack.test?,
49
+ block: attack.block?,
50
+ infos: attack.infos
51
+ )
52
+ )
53
+ end
54
+
55
+ # see Sqreen::Rules::RuleCB.record_event
56
+ def convert_unstructured_attack(payload)
57
+ Kit::Signals::Specialized::Attack.new(
58
+ signal_name: "sq.agent.attack.#{payload[:attack_type]}",
59
+ source: "sqreen:rule:#{payload[:rulespack_id]}:#{payload[:rule_name]}",
60
+ time: payload[:time],
61
+ location: (Kit::Signals::Location.new(stack_trace: payload[:backtrace]) if payload[:backtrace]),
62
+ payload: Kit::Signals::Specialized::Attack::Payload.new(
63
+ test: payload[:test],
64
+ block: payload[:block],
65
+ infos: payload[:infos]
66
+ )
67
+ )
68
+ end
69
+
70
+ # @param [Sqreen::RemoteException] exception
71
+ # @return [Sqreen::Kit::Signals::Specialized::SqreenException]
72
+ def convert_exception(exception)
73
+ payload = exception.payload
74
+
75
+ infos = payload['client_ip'] ? { client_ip: payload['client_ip'] } : {}
76
+ infos.merge!(payload['infos'] || {})
77
+
78
+ Kit::Signals::Specialized::SqreenException.new(
79
+ source: if payload['rule_name']
80
+ "sqreen:rule:#{payload['rulespack_id']}:#{payload['rule_name']}"
81
+ else
82
+ agent_gen_source
83
+ end,
84
+ time: exception.time,
85
+ ruby_exception: payload['exception'],
86
+ infos: infos
87
+ )
88
+ end
89
+
90
+ # see Sqreen::Rules::RuleCB.record_exception
91
+ # @param [Hash] payload
92
+ # @return [Sqreen::Kit::Signals::Specialized::SqreenException]
93
+ def convert_unstructured_exception(payload)
94
+ Kit::Signals::Specialized::SqreenException.new(
95
+ source: "sqreen:rule:#{payload[:rulespack_id]}:#{payload[:rule_name]}",
96
+ time: payload[:time],
97
+ ruby_exception: payload[:exception],
98
+ infos: payload[:infos]
99
+ )
100
+ end
101
+
102
+ # @param [Sqreen::RequestRecord] req_rec
103
+ # @return [Sqreen::Kit::Signals::Specialized::HttpTrace]
104
+ def convert_req_record(req_rec)
105
+ payload = req_rec.payload
106
+
107
+ request_p = payload['request']
108
+ id_args = req_rec.last_identify_args
109
+ identifiers = id_args[0] if id_args
110
+ traits = id_args[1] if id_args
111
+
112
+ observed = payload[:observed] || {}
113
+ signals = []
114
+ signals += (observed[:attacks] || [])
115
+ .map { |att| convert_unstructured_attack(att) }
116
+ signals += (observed[:sqreen_exceptions] || [])
117
+ .map { |sq_exc| convert_unstructured_exception(sq_exc) }
118
+ signals += req_rec.processed_sdk_calls
119
+ .select { |h| h[:name] == :track }
120
+ .map { |h| convert_track(h) }
121
+ signals += (observed[:signals] || [])
122
+
123
+ trace = Kit::Signals::Specialized::HttpTrace.new(
124
+ actor: Kit::Signals::Actor.new(
125
+ ip_addresses: [request_p[:client_ip]].compact,
126
+ user_agent: request_p[:user_agent],
127
+ identifiers: identifiers,
128
+ traits: traits,
129
+ ),
130
+ location_infra: location_infra,
131
+ context: convert_request(request_p,
132
+ payload['response'],
133
+ payload['headers'],
134
+ payload['params']),
135
+ data: signals
136
+ )
137
+ HttpTraceRedaction.redact_trace!(trace, req_rec.redactor)
138
+ trace
139
+ end
140
+
141
+ # @return [Array<Sqreen::Kit::Signals::Signal|Sqreen::Kit::Signals::Trace>]
142
+ def convert_batch(batch)
143
+ batch.map do |evt|
144
+ case evt
145
+ when RemoteException
146
+ convert_exception(evt)
147
+ when AggregatedMetric
148
+ convert_metric_sample(evt)
149
+ when RequestRecord
150
+ convert_req_record(evt)
151
+ when Sqreen::Kit::Signals::Signal
152
+ evt
153
+ when Sqreen::Kit::Signals::Trace
154
+ evt
155
+ else
156
+ raise NotImplementedError, "Unknown type of event in batch: #{evt}"
157
+ end
158
+ end
159
+ end
160
+
161
+ private
162
+
163
+ def agent_gen_source
164
+ "sqreen:agent:ruby:#{Sqreen::VERSION}"
165
+ end
166
+
167
+ def location_infra
168
+ @location_infra ||= begin
169
+ Kit::Signals::LocationInfra.new(
170
+ agent_version: Sqreen::VERSION,
171
+ os_type: RuntimeInfos.os[:os_type],
172
+ hostname: RuntimeInfos.hostname,
173
+ runtime_type: RuntimeInfos.runtime[:runtime_type],
174
+ runtime_version: RuntimeInfos.runtime[:runtime_version],
175
+ libsqreen_version: RuntimeInfos.libsqreen_version,
176
+ )
177
+ end
178
+ end
179
+
180
+ # see Sqreen::RequestRecord.processed_sdk_calls
181
+ def convert_track(call_info)
182
+ options = call_info[:args][1] || {}
183
+ Kit::Signals::Specialized::SdkTrackCall.new(
184
+ signal_name: "sq.sdk.#{call_info[:args][0]}",
185
+ time: call_info[:time],
186
+ payload: Kit::Signals::Specialized::SdkTrackCall::Payload.new(
187
+ properties: options[:properties],
188
+ user_identifiers: options[:user_identifiers]
189
+ )
190
+ )
191
+ end
192
+
193
+ # @param [Hash] req_payload
194
+ # @param [Hash] headers_payload
195
+ # @param [Hash] params_payload
196
+ # see the PayloadCreator abomination for reference
197
+ # TODO: do not convert from the old payload to the new payload
198
+ # Have an intermediate object that gets the data from the framework.
199
+ # (Or convert directly from the framework, but this needs to be
200
+ # done during the request, not just before event is transmitted)
201
+ def convert_request(req_payload, resp_payload, headers_payload, params_payload)
202
+ req_payload ||= {}
203
+ headers_payload ||= {}
204
+ resp_payload ||= {}
205
+ params_payload ||= {}
206
+
207
+ other = params_payload['other']
208
+ other = merge_hash_append(other, params_payload['rack'])
209
+ other = merge_hash_append(other, params_payload['grape_params'])
210
+ other = merge_hash_append(other, params_payload['rack_routing'])
211
+
212
+ Sqreen::Kit::Signals::Context::HttpContext.new(
213
+ {
214
+ rid: req_payload[:rid],
215
+ headers: headers_payload,
216
+ user_agent: req_payload[:user_agent],
217
+ scheme: req_payload[:scheme],
218
+ verb: req_payload[:verb],
219
+ host: req_payload[:host],
220
+ port: req_payload[:port],
221
+ remote_ip: req_payload[:remote_ip],
222
+ remote_port: req_payload[:remote_port] || 0,
223
+ path: req_payload[:path],
224
+ referer: req_payload[:referer],
225
+ params_query: params_payload['query'],
226
+ params_form: params_payload['form'],
227
+ params_other: other,
228
+ # endpoint, is_reveal_replayed not set
229
+ status: resp_payload[:status],
230
+ content_length: resp_payload[:content_length],
231
+ content_type: resp_payload[:content_type],
232
+ }
233
+ )
234
+ end
235
+
236
+ def merge_hash_append(hash1, hash2)
237
+ return nil if hash1.nil? && hash2.nil?
238
+ return hash1 if hash2.nil? || hash2.empty?
239
+ return hash2 if hash1.nil? || hash1.empty?
240
+
241
+ pairs = (hash1.keys + hash2.keys).map do |key|
242
+ values1 = hash1[key]
243
+ values2 = hash2[key]
244
+ values = [values1, values2].compact
245
+ values = values.first if values.size == 1
246
+ [key, values]
247
+ end
248
+ Hash[pairs]
249
+ end
250
+
251
+ # @param [Sqreen::AggregatedMetric] agg
252
+ # @param [Hash] attrs
253
+ def conv_generic_metric(agg, attrs)
254
+ attrs[:payload] = Kit::Signals::Specialized::AggregatedMetric::Payload.new(
255
+ kind: metric_kind(agg.metric),
256
+ capture_interval_s: agg.metric.period,
257
+ date_started: agg.start,
258
+ date_ended: agg.finish,
259
+ values: agg.data
260
+ )
261
+
262
+ Kit::Signals::Specialized::AggregatedMetric.new(attrs)
263
+ end
264
+
265
+ # @param [Sqreen::AggregatedMetric] agg
266
+ # @param [Hash] attrs
267
+ def conv_binning_metric(agg, attrs)
268
+ attrs[:payload] = Kit::Signals::Specialized::BinningMetric::Payload.new(
269
+ capture_interval_s: agg.metric.period,
270
+ date_started: agg.start,
271
+ date_ended: agg.finish,
272
+ base: agg.data['b'],
273
+ unit: agg.data['u'],
274
+ max: agg.data['v']['max'],
275
+ bins: agg.data['v'].reject { |k, _v| k == 'max' }
276
+ )
277
+
278
+ Kit::Signals::Specialized::BinningMetric.new(attrs)
279
+ end
280
+
281
+ # @param [Sqreen::Metric::Base] metric
282
+ def metric_kind(metric)
283
+ metric.class.name.sub(/.*::/, '').sub(/Metric$/, '')
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end