sqreen 1.19.4 → 1.20.4.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  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/configuration.rb +11 -5
  11. data/lib/sqreen/deferred_logger.rb +50 -14
  12. data/lib/sqreen/deliveries/batch.rb +4 -1
  13. data/lib/sqreen/deliveries/simple.rb +4 -0
  14. data/lib/sqreen/deprecation.rb +38 -0
  15. data/lib/sqreen/endpoint_testing.rb +184 -0
  16. data/lib/sqreen/event.rb +7 -5
  17. data/lib/sqreen/events/attack.rb +23 -18
  18. data/lib/sqreen/events/remote_exception.rb +0 -22
  19. data/lib/sqreen/events/request_record.rb +15 -70
  20. data/lib/sqreen/frameworks/generic.rb +9 -0
  21. data/lib/sqreen/frameworks/rails.rb +0 -7
  22. data/lib/sqreen/frameworks/request_recorder.rb +13 -2
  23. data/lib/sqreen/graft/call.rb +76 -18
  24. data/lib/sqreen/graft/callback.rb +1 -1
  25. data/lib/sqreen/graft/hook.rb +187 -85
  26. data/lib/sqreen/graft/hook_point.rb +1 -1
  27. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  28. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  29. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  30. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  31. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  32. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  33. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  34. data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
  35. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  36. data/lib/sqreen/log.rb +3 -2
  37. data/lib/sqreen/log/loggable.rb +2 -1
  38. data/lib/sqreen/logger.rb +24 -0
  39. data/lib/sqreen/metrics/base.rb +3 -0
  40. data/lib/sqreen/metrics_store.rb +33 -12
  41. data/lib/sqreen/null_logger.rb +22 -0
  42. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  43. data/lib/sqreen/remote_command.rb +1 -0
  44. data/lib/sqreen/rules.rb +5 -3
  45. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  46. data/lib/sqreen/rules/rule_cb.rb +4 -0
  47. data/lib/sqreen/rules/waf_cb.rb +11 -8
  48. data/lib/sqreen/runner.rb +103 -10
  49. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  50. data/lib/sqreen/session.rb +51 -43
  51. data/lib/sqreen/signals/conversions.rb +283 -0
  52. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  53. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  54. data/lib/sqreen/version.rb +1 -1
  55. data/lib/sqreen/weave/budget.rb +46 -0
  56. data/lib/sqreen/weave/legacy/instrumentation.rb +156 -94
  57. data/lib/sqreen/worker.rb +6 -2
  58. metadata +51 -8
  59. data/lib/sqreen/backport.rb +0 -9
  60. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  61. data/lib/sqreen/backport/original_name.rb +0 -88
@@ -0,0 +1,111 @@
1
+ require 'json'
2
+ require 'sqreen/kit/loggable'
3
+ require 'sqreen/kit/signals/specialized/http_trace'
4
+
5
+ module Sqreen
6
+ module Signals
7
+ module HttpTraceRedaction
8
+ class << self
9
+ include Sqreen::Kit::Loggable
10
+
11
+ # @param [Sqreen::Kit::Signals::Specialized::HttpTrace] trace
12
+ # @param [Sqreen::SensitiveDataRedactor] redactor
13
+ def redact_trace!(trace, redactor)
14
+ return unless redactor
15
+ # redact headers (keys unsafe)
16
+ # @type [Sqreen::Kit::Signals::Context::HttpContext]
17
+ http_context = trace.context
18
+
19
+ all_redacted = []
20
+
21
+ # Redact headers; save redacted values
22
+ # headers are encoded as [key, value], not a hash, so
23
+ # they require some transformation
24
+ orig_headers = http_context.headers
25
+ if orig_headers
26
+ headers = orig_headers.map { |(k, v)| { k => v } }
27
+ headers, redacted = redactor.redact(headers)
28
+ http_context.headers = headers.map(&:first)
29
+ all_redacted += redacted
30
+ end
31
+
32
+ # Redact params; save redacted values
33
+ Kit::Signals::Context::HttpContext::PARAMS_ATTRS.each do |attr|
34
+ value = http_context.public_send(attr)
35
+ next unless value
36
+ value, redacted = redactor.redact(value)
37
+ all_redacted += redacted
38
+ http_context.public_send(:"#{attr}=", value)
39
+ end
40
+
41
+ all_redacted = all_redacted.uniq.map(&:downcase)
42
+
43
+ # Redact attacks and exceptions
44
+ # XXX: no redaction for infos in attacks/exceptions except for WAF data
45
+ # Is this the correct behavior?
46
+ redact_attacks!(trace, redactor, all_redacted)
47
+ redact_exceptions!(trace, redactor, all_redacted)
48
+ end
49
+
50
+ private
51
+
52
+ # @param [Sqreen::Kit::Signals::Specialized::HttpTrace] trace
53
+ # @param [Sqreen::SensitiveDataRedactor] redactor
54
+ # Redacts WAF data according to specific rules therefor
55
+ # Redacts infos according to general rules
56
+ def redact_attacks!(trace, redactor, redacted_data)
57
+ trace.data.each do |signal|
58
+ next unless signal.is_a?(Kit::Signals::Specialized::Attack)
59
+ # @type [Sqreen::Kit::Signals::Specialized::Attack::Payload] payload
60
+ payload = signal.payload
61
+ next unless payload.infos
62
+
63
+ if payload.infos[:waf_data]
64
+ redact_waf_attack_data!(payload.infos, redacted_data)
65
+ end
66
+ payload.infos, = redactor.redact(payload.infos)
67
+ end
68
+ end
69
+
70
+ def redact_exceptions!(trace, redactor, redacted_data)
71
+ trace.data.each do |signal|
72
+ next unless signal.is_a?(Kit::Signals::Specialized::SqreenException)
73
+ infos = signal.infos
74
+ next unless infos
75
+
76
+ redact_waf_exception_data!(signal.infos, redacted_data) if signal.infos[:waf]
77
+ signal.infos, = redactor.redact(infos)
78
+ end
79
+ end
80
+
81
+ # @param [Hash] infos from WAF attack
82
+ def redact_waf_attack_data!(infos, redacted_data)
83
+ begin
84
+ parsed = JSON.parse(infos[:waf_data])
85
+ rescue JSON::JSONError => e
86
+ logger.warn("waf_data is not valid json: #{e.message}")
87
+ return
88
+ end
89
+ redacted = parsed.each do |w|
90
+ next unless (filters = w['filter'])
91
+
92
+ filters.each do |f|
93
+ next unless (v = f['resolved_value'])
94
+ next unless redacted_data.include?(v.downcase)
95
+
96
+ f['match_status'] = SensitiveDataRedactor::MASK
97
+ f['resolved_value'] = SensitiveDataRedactor::MASK
98
+ end
99
+ end
100
+ infos[:waf_data] = JSON.dump(redacted)
101
+ end
102
+
103
+ # see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000022-waf-data-sanitization.md#changes-to-the-agents
104
+ def redact_waf_exception_data!(infos, redacted_data)
105
+ return if redacted_data.empty?
106
+ infos[:waf].delete(:args)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,78 @@
1
+ require 'sqreen/aggregated_metric'
2
+ require 'sqreen/kit'
3
+ require 'sqreen/kit/string_sanitizer'
4
+ require 'sqreen/signals/conversions'
5
+ require 'sqreen/log/loggable'
6
+
7
+ module Sqreen
8
+ module Signals
9
+ # see also Sqreen::Legacy::OldEventSubmissionStrategy
10
+ # usage in Sqreen:Session
11
+ class SignalsSubmissionStrategy
12
+ include Sqreen::Log::Loggable
13
+
14
+ # @param [Array<Sqreen::AggregatedMetric>] metrics
15
+ def post_metrics(metrics)
16
+ return if metrics.nil? || metrics.empty?
17
+
18
+ guarded 'Failed to serialize or submit aggregated metrics' do
19
+ batch = metrics.map do |m|
20
+ Conversions.convert_metric_sample(m)
21
+ end
22
+ client.report_batch(batch)
23
+ end
24
+ end
25
+
26
+ # @param _attack [Sqreen::Attack]
27
+ # XXX: unused
28
+ def post_attack(_attack)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ # @param request_record [Sqreen::RequestRecord]
33
+ def post_request_record(request_record)
34
+ guarded 'Failed to serialize or submit request record' do
35
+ trace = Conversions.convert_req_record(request_record)
36
+ append_sanitizing_filter(trace)
37
+ client.report_trace(trace)
38
+ end
39
+ end
40
+
41
+ # Post an exception to Sqreen for analysis
42
+ # @param exception [RemoteException] Exception and context to be sent over
43
+ def post_sqreen_exception(exception)
44
+ guarded 'Failed to serialize or submit exception', false do
45
+ data = Conversions.convert_exception(exception)
46
+ append_sanitizing_filter(data)
47
+ client.report_signal(data)
48
+ end
49
+ end
50
+
51
+ def post_batch(events)
52
+ guarded 'Failed to serialize or submit batch of events' do
53
+ batch = Conversions.convert_batch(events)
54
+ batch.each { |sig_or_trace| append_sanitizing_filter(sig_or_trace) }
55
+ client.report_batch(batch)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def append_sanitizing_filter(sig_or_trace)
62
+ sig_or_trace.append_to_h_filter Kit::StringSanitizer.method(:sanitize)
63
+ end
64
+
65
+ # we don't want exceptions to propagate and kill the worker thread
66
+ def guarded(msg, report = true)
67
+ yield
68
+ rescue StandardError => e
69
+ logger.warn "#{msg}: #{e.message}\n#{e.backtrace.map { |x| " #{x}" }.join("\n")}"
70
+ post_sqreen_exception(RemoteException.new(e)) if report
71
+ end
72
+
73
+ def client
74
+ Sqreen::Kit.auth_signals_client
75
+ end
76
+ end
77
+ end
78
+ 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.19.4'.freeze
7
+ VERSION = '1.20.4.beta1'.freeze
8
8
  end
@@ -0,0 +1,46 @@
1
+ # typed: false
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/log/loggable'
7
+ require 'sqreen/weave'
8
+
9
+ class Sqreen::Weave::Budget
10
+ include Sqreen::Log::Loggable
11
+
12
+ def initialize(threshold, ratio = nil)
13
+ @threshold = threshold
14
+ @ratio = ratio
15
+ end
16
+
17
+ def static?
18
+ threshold && !ratio
19
+ end
20
+
21
+ def dynamic?
22
+ threshold && ratio
23
+ end
24
+
25
+ attr_reader :threshold
26
+ attr_reader :ratio
27
+
28
+ def to_h
29
+ { threshold: threshold, ratio: ratio }
30
+ end
31
+
32
+ class << self
33
+ attr_reader :current
34
+
35
+ def update(opts = nil)
36
+ Sqreen::Weave.logger.info("budget update:#{opts.inspect}")
37
+
38
+ return @current = nil if opts.nil? || opts.empty?
39
+
40
+ threshold = opts[:threshold]
41
+ ratio = opts[:ratio]
42
+
43
+ @current = new(threshold, ratio)
44
+ end
45
+ end
46
+ end
@@ -4,6 +4,7 @@
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
6
  require 'sqreen/weave/legacy'
7
+ require 'sqreen/weave/budget'
7
8
  require 'sqreen/graft/hook_point'
8
9
  require 'sqreen/call_countable'
9
10
  require 'sqreen/rules'
@@ -61,6 +62,27 @@ class Sqreen::Weave::Legacy::Instrumentation
61
62
  'options' => opts[:perf_metric_percent] || { 'base' => 1.3, 'factor' => 1.0 },
62
63
  )
63
64
 
65
+ metrics_engine.create_metric(
66
+ 'name' => 'req.sq.hook.overhead',
67
+ 'period' => 60,
68
+ 'kind' => 'Binning',
69
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
70
+ )
71
+
72
+ metrics_engine.create_metric(
73
+ 'name' => 'sq.hook.overhead',
74
+ 'period' => 60,
75
+ 'kind' => 'Binning',
76
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
77
+ )
78
+
79
+ metrics_engine.create_metric(
80
+ 'name' => 'sq.shrinkwrap',
81
+ 'period' => 60,
82
+ 'kind' => 'Binning',
83
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
84
+ )
85
+
64
86
  Sqreen.thread_cpu_time? && metrics_engine.create_metric(
65
87
  'name' => 'sq_thread_cpu_pct',
66
88
  'period' => opts[:period] || 60,
@@ -104,6 +126,25 @@ class Sqreen::Weave::Legacy::Instrumentation
104
126
  next unless rule_callback
105
127
  ### attach framework to callback
106
128
  rule_callback.framework = framework
129
+ ## create metric
130
+ Sqreen::Weave.logger.debug { "Adding rule metric: #{rule_callback}" }
131
+ [:pre, :post, :failing].each do |whence|
132
+ next unless rule_callback.send(:"#{whence}?")
133
+ metric_name = "sq.#{rule['name']}.#{whence}"
134
+ metrics_engine.create_metric(
135
+ 'name' => metric_name,
136
+ 'period' => 60,
137
+ 'kind' => 'Binning',
138
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
139
+ )
140
+ metric_name = "req.sq.#{rule['name']}.#{whence}"
141
+ metrics_engine.create_metric(
142
+ 'name' => metric_name,
143
+ 'period' => 60,
144
+ 'kind' => 'Binning',
145
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
146
+ )
147
+ end
107
148
  ### install callback, observing priority
108
149
  Sqreen::Weave.logger.debug { "Adding rule callback: #{rule_callback}" }
109
150
  @hooks << add_callback("weave,rule=#{rule['name']}", rule_callback, strategy)
@@ -117,30 +158,43 @@ class Sqreen::Weave::Legacy::Instrumentation
117
158
  end
118
159
 
119
160
  metrics_engine = self.metrics_engine
161
+
120
162
  request_hook = Sqreen::Graft::Hook['Sqreen::ShrinkWrap#call', strategy]
121
163
  @hooks << request_hook
122
164
  request_hook.add do
123
165
  before('wave,meta,request', rank: -100000, mandatory: true) do |_call|
124
166
  next unless Sqreen.instrumentation_ready
125
167
 
126
- uuid = SecureRandom.uuid
127
- now = Sqreen::Graft::Timer.read
168
+ # shrinkwrap_timer = Sqreen::Graft::Timer.new('weave,shrinkwrap')
169
+ # shrinkwrap_timer.start
170
+
171
+ request_timer = Sqreen::Graft::Timer.new("request")
172
+ request_timer.start
173
+ sqreen_timer = Sqreen::Graft::Timer.new("sqreen")
174
+ budget = Sqreen::Weave::Budget.current
175
+ request_budget_threshold = budget.threshold
176
+ request_budget_ratio = budget.ratio
177
+ request_budget_is_dynamic = !request_budget_ratio.nil?
178
+ request_budget = !request_budget_threshold.nil?
179
+ timed_level = (Sqreen.features['perf_level'] || 1).to_i
180
+ Sqreen::Weave.logger.debug { "request budget: #{budget.to_h} timed.level: #{timed_level}" } if Sqreen::Weave.logger.debug?
181
+
128
182
  Thread.current[:sqreen_http_request] = {
129
- uuid: uuid,
130
- start_time: now,
131
- time_budget: Sqreen.performance_budget,
183
+ request_timer: request_timer,
184
+ sqreen_timer: sqreen_timer,
132
185
  time_budget_expended: false,
133
- timer: Sqreen::Graft::Timer.new("request_#{uuid}"),
186
+ time_budget_threshold: request_budget_threshold,
187
+ time_budget_dynamic: request_budget_is_dynamic,
188
+ time_budget_ratio: request_budget_ratio,
189
+ time_budget: request_budget,
134
190
  timed_callbacks: [],
135
191
  timed_hooks: [],
136
- timed_hooks_before: [],
137
- timed_hooks_after: [],
138
- timed_hooks_raised: [],
139
- timed_hooks_ensured: [],
192
+ timed_level: timed_level,
140
193
  skipped_callbacks: [],
194
+ # timed_shrinkwrap: shrinkwrap_timer,
141
195
  }
142
196
 
143
- Sqreen::Weave.logger.debug { "request.uuid: #{uuid}" }
197
+ # shrinkwrap_timer.stop
144
198
  end
145
199
 
146
200
  ensured('weave,meta,request', rank: 100000, mandatory: true) do |_call|
@@ -148,105 +202,110 @@ class Sqreen::Weave::Legacy::Instrumentation
148
202
 
149
203
  next if request.nil?
150
204
 
205
+ # shrinkwrap_timer = request[:timed_shrinkwrap]
206
+ # shrinkwrap_timer.start
207
+
151
208
  Thread.current[:sqreen_http_request] = nil
152
- now = Sqreen::Graft::Timer.read
153
- utc_now = Time.now.utc
154
-
155
- request[:timed_callbacks].each do |timer|
156
- duration = timer.duration
157
- # stop = now
158
- # start = now - duration
159
- timer.tag =~ /weave,rule=(.*)$/ && rule = $1
160
- timer.tag =~ /@before/ && whence = 'pre'
161
- timer.tag =~ /@after/ && whence = 'post'
162
- timer.tag =~ /@raised/ && whence = 'failing'
163
-
164
- next unless rule && whence
165
-
166
- # Sqreen::PerformanceNotifications.notify(rule, whence, start, stop)
167
- # => BinnedMetrics
168
- metric_name = "sq.#{rule}.#{whence}"
169
- unless metrics_engine.metric?(metric_name)
170
- metrics_engine.create_metric(
171
- 'name' => metric_name,
172
- 'period' => 60,
173
- 'kind' => 'Binning',
174
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
175
- )
209
+ request_timer = request[:request_timer]
210
+ now = request_timer.stop
211
+
212
+ if request[:timed_level] >= 1
213
+ request[:timed_callbacks].each do |timer|
214
+ duration = timer.duration
215
+ timer.tag =~ /weave,rule=(.*)$/ && rule = $1
216
+ timer.tag =~ /@before/ && whence = 'pre'
217
+ timer.tag =~ /@after/ && whence = 'post'
218
+ timer.tag =~ /@raised/ && whence = 'failing'
219
+
220
+ next unless rule && whence
221
+
222
+ metric_name = "sq.#{rule}.#{whence}"
223
+ metrics_engine.update(metric_name, now, nil, duration * 1000)
224
+ # Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
176
225
  end
177
- metrics_engine.update(metric_name, now, nil, duration * 1000)
178
- end
179
226
 
180
- metric_name = 'sq.hooks_pre.pre'
181
- duration = request[:timed_hooks_before].sum(&:duration)
182
- unless metrics_engine.metric?(metric_name)
183
- metrics_engine.create_metric(
184
- 'name' => metric_name,
185
- 'period' => 60,
186
- 'kind' => 'Binning',
187
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
188
- )
189
- end
190
- metrics_engine.update(metric_name, now, nil, duration * 1000)
191
-
192
- metric_name = 'sq.hooks_post.post'
193
- duration = request[:timed_hooks_after].sum(&:duration)
194
- unless metrics_engine.metric?(metric_name)
195
- metrics_engine.create_metric(
196
- 'name' => metric_name,
197
- 'period' => 60,
198
- 'kind' => 'Binning',
199
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
200
- )
201
- end
202
- metrics_engine.update(metric_name, now, nil, duration * 1000)
203
-
204
- metric_name = 'sq.hooks_failing.failing'
205
- duration = request[:timed_hooks_raised].sum(&:duration)
206
- unless metrics_engine.metric?(metric_name)
207
- metrics_engine.create_metric(
208
- 'name' => metric_name,
209
- 'period' => 60,
210
- 'kind' => 'Binning',
211
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
212
- )
227
+ request[:timed_hooks].each do |timer|
228
+ duration = timer.duration
229
+ metrics_engine.update('sq.hook.overhead', now, nil, duration * 1000)
230
+ # Sqreen.observations_queue.push(['sq.hook.overhead', nil, duration * 1000, utc_now])
231
+ end
213
232
  end
214
- metrics_engine.update(metric_name, now, nil, duration * 1000)
215
233
 
216
- skipped = request[:skipped_callbacks].map(&:name)
217
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} callback.skipped.size: #{skipped.count} callback.skipped: [#{skipped.join(', ')}]" }
218
- timer = request[:timer]
219
- total = timer.duration
220
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} timer.total: #{'%.03fus' % (total * 1_000_000)} timer.size: #{timer.size}" }
221
- timings = request[:timed_callbacks].map(&:to_s)
222
- total = request[:timed_callbacks].sum(&:duration)
223
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} callback.total: #{'%.03fus' % (total * 1_000_000)} callback.timings: [#{timings.join(', ')}]" }
224
- timings = request[:timed_hooks].map(&:to_s)
225
- total = request[:timed_hooks].sum(&:duration)
226
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} hook.total: #{'%.03fus' % (total * 1_000_000)} hook.timings: [#{timings.join(', ')}]" }
234
+ sqreen_timer = request[:sqreen_timer]
235
+ total = sqreen_timer.duration
236
+ Sqreen::Weave.logger.debug { "request sqreen_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
237
+ total = request_timer.duration
238
+ Sqreen::Weave.logger.debug { "request request_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
239
+
240
+ if request[:timed_level] >= 2
241
+ skipped = request[:skipped_callbacks].map(&:name)
242
+ Sqreen::Weave.logger.debug { "request callback.skipped.count: #{skipped.count}" } if Sqreen::Weave.logger.debug?
243
+ timings = request[:timed_callbacks].map(&:to_s)
244
+ total = request[:timed_callbacks].sum(&:duration)
245
+ Sqreen::Weave.logger.debug { "request callback.total: #{'%.03fus' % (total * 1_000_000)} callback.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
246
+ timings = request[:timed_hooks].map(&:to_s)
247
+ total = request[:timed_hooks].sum(&:duration)
248
+ Sqreen::Weave.logger.debug { "request hook.total: #{'%.03fus' % (total * 1_000_000)} hook.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
249
+ end
227
250
 
228
251
  skipped = request[:skipped_callbacks].map(&:name)
229
252
  skipped_rule_name = skipped.first && skipped.first =~ /weave,rule=(.*)$/ && $1
230
- Sqreen.observations_queue.push(['request_overtime', skipped_rule_name, 1, utc_now]) if skipped_rule_name
253
+ metrics_engine.update('request_overtime', now, skipped_rule_name, 1) if skipped_rule_name
254
+ # Sqreen.observations_queue.push(['request_overtime', skipped_rule_name, 1, utc_now]) if skipped_rule_name
231
255
 
232
- sqreen_request_duration = total
233
- Sqreen.observations_queue.push(['sq', nil, sqreen_request_duration * 1000, utc_now])
256
+ sqreen_request_duration = sqreen_timer.duration
257
+ metrics_engine.update('sq', now, nil, sqreen_request_duration * 1000)
258
+ # Sqreen.observations_queue.push(['sq', nil, sqreen_request_duration * 1000, utc_now])
234
259
 
235
- request_duration = now - request[:start_time]
236
- Sqreen.observations_queue.push(['req', nil, request_duration * 1000, utc_now])
260
+ request_duration = request_timer.duration
261
+ metrics_engine.update('req', now, nil, request_duration * 1000)
262
+ # Sqreen.observations_queue.push(['req', nil, request_duration * 1000, utc_now])
237
263
 
238
264
  sqreen_request_ratio = (sqreen_request_duration * 100.0) / (request_duration - sqreen_request_duration)
239
- Sqreen.observations_queue.push(['pct', nil, sqreen_request_ratio, utc_now])
265
+ metrics_engine.update('pct', now, nil, sqreen_request_ratio)
266
+ # Sqreen.observations_queue.push(['pct', nil, sqreen_request_ratio, utc_now])
267
+ Sqreen::Weave.logger.debug { "request sqreen_timer.ratio: #{'%.03f' % (sqreen_request_ratio / 100.0)}" } if Sqreen::Weave.logger.debug?
268
+
269
+ if request[:timed_level] >= 2
270
+ tallies = Hash.new(0.0)
271
+ request[:timed_callbacks].each do |timer|
272
+ duration = timer.duration
273
+ timer.tag =~ /weave,rule=(.*)$/ && rule = $1
274
+ timer.tag =~ /@before/ && whence = 'pre'
275
+ timer.tag =~ /@after/ && whence = 'post'
276
+ timer.tag =~ /@raised/ && whence = 'failing'
277
+
278
+ next unless rule && whence
279
+
280
+ metric_name = "req.sq.#{rule}.#{whence}"
281
+ tallies[metric_name] += duration
282
+ end
283
+ tallies.each do |metric_name, duration|
284
+ metrics_engine.update(metric_name, now, nil, duration * 1000)
285
+ # Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
286
+ end
287
+
288
+ duration = request[:timed_hooks].sum(&:duration)
289
+ metrics_engine.update('req.sq.hook.overhead', now, nil, duration * 1000)
290
+ # Sqreen.observations_queue.push(['req.sq.hook.overhead', nil, duration * 1000, utc_now])
291
+ end
292
+
293
+ # shrinkwrap_timer.stop
294
+
295
+ # duration = shrinkwrap_timer.duration
296
+ # metrics_engine.update('sq.shrinkwrap', now, nil, duration * 1000)
240
297
  end
241
298
  end.install
242
299
 
243
300
  ### globally declare instrumentation ready
244
301
  Sqreen.instrumentation_ready = true
302
+ Sqreen::Weave.logger.info { "Instrumentation activated" }
245
303
  end
246
304
 
247
305
  # needed by Sqreen::Runner
248
306
  def remove_all_callbacks
249
307
  Sqreen.instrumentation_ready = false
308
+ Sqreen::Weave.logger.info { "Instrumentation deactivated" }
250
309
 
251
310
  loop do
252
311
  hook = @hooks.pop
@@ -263,6 +322,15 @@ class Sqreen::Weave::Legacy::Instrumentation
263
322
  klass = callback.klass
264
323
  method = callback.method
265
324
 
325
+ if (call_count = ENV['SQREEN_DEBUG_CALL_COUNT'])
326
+ call_count = JSON.parse(call_count)
327
+ if callback.respond_to?(:rule_name) && call_count.key?(callback.rule_name)
328
+ count = call_count[callback.rule_name]
329
+ Sqreen::Weave.logger.debug { "override rule: #{callback.rule_name} call_count: #{count.inspect}" }
330
+ callback.instance_eval { @call_count_interval = call_count[callback.rule_name] }
331
+ end
332
+ end
333
+
266
334
  if Sqreen::Graft::HookPoint.new("#{klass}.#{method}").exist?
267
335
  hook_point = "#{klass}.#{method}"
268
336
  elsif Sqreen::Graft::HookPoint.new("#{klass}##{method}").exist?
@@ -285,7 +353,6 @@ class Sqreen::Weave::Legacy::Instrumentation
285
353
  a = call.args
286
354
  r = call.remaining
287
355
 
288
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i}" }
289
356
  begin
290
357
  ret = callback.pre(i, a, r)
291
358
  rescue StandardError => e
@@ -296,7 +363,6 @@ class Sqreen::Weave::Legacy::Instrumentation
296
363
  Sqreen::RemoteException.record(e)
297
364
  end
298
365
  end
299
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i} => return=#{ret.inspect}" }
300
366
 
301
367
  case ret[:status]
302
368
  when :skip, 'skip'
@@ -319,7 +385,6 @@ class Sqreen::Weave::Legacy::Instrumentation
319
385
  a = call.args
320
386
  r = call.remaining
321
387
 
322
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i}" }
323
388
  begin
324
389
  ret = callback.post(v, i, a, r)
325
390
  rescue StandardError => e
@@ -330,7 +395,6 @@ class Sqreen::Weave::Legacy::Instrumentation
330
395
  Sqreen::RemoteException.record(e)
331
396
  end
332
397
  end
333
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i} => return=#{ret.inspect}" }
334
398
 
335
399
  case ret[:status]
336
400
  when :override, 'override'
@@ -351,7 +415,6 @@ class Sqreen::Weave::Legacy::Instrumentation
351
415
  a = call.args
352
416
  r = call.remaining
353
417
 
354
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i}" }
355
418
  begin
356
419
  ret = callback.failing(e, i, a, r)
357
420
  rescue StandardError => e
@@ -362,7 +425,6 @@ class Sqreen::Weave::Legacy::Instrumentation
362
425
  Sqreen::RemoteException.record(e)
363
426
  end
364
427
  end
365
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i} => return=#{ret.inspect}" }
366
428
 
367
429
  throw(b, b.raise(e)) if ret.nil? || !ret.is_a?(Hash)
368
430