sqreen 1.20.1-java → 1.20.4-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 (38) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +25 -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/attack_detected.html +1 -2
  7. data/lib/sqreen/condition_evaluator.rb +8 -2
  8. data/lib/sqreen/configuration.rb +1 -1
  9. data/lib/sqreen/deferred_logger.rb +50 -14
  10. data/lib/sqreen/deprecation.rb +38 -0
  11. data/lib/sqreen/events/request_record.rb +0 -1
  12. data/lib/sqreen/frameworks/generic.rb +9 -0
  13. data/lib/sqreen/frameworks/rails.rb +0 -7
  14. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  15. data/lib/sqreen/graft/call.rb +76 -18
  16. data/lib/sqreen/graft/callback.rb +1 -1
  17. data/lib/sqreen/graft/hook.rb +187 -85
  18. data/lib/sqreen/graft/hook_point.rb +1 -1
  19. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  20. data/lib/sqreen/legacy/old_event_submission_strategy.rb +2 -1
  21. data/lib/sqreen/log.rb +3 -2
  22. data/lib/sqreen/log/loggable.rb +1 -0
  23. data/lib/sqreen/logger.rb +24 -0
  24. data/lib/sqreen/metrics_store.rb +11 -0
  25. data/lib/sqreen/null_logger.rb +22 -0
  26. data/lib/sqreen/remote_command.rb +1 -0
  27. data/lib/sqreen/rules.rb +8 -4
  28. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  29. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  30. data/lib/sqreen/rules/rule_cb.rb +2 -0
  31. data/lib/sqreen/rules/waf_cb.rb +3 -3
  32. data/lib/sqreen/runner.rb +28 -2
  33. data/lib/sqreen/version.rb +1 -1
  34. data/lib/sqreen/weave/budget.rb +46 -0
  35. data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
  36. data/lib/sqreen/worker.rb +6 -2
  37. metadata +7 -6
  38. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -6,6 +6,7 @@
6
6
  require 'sqreen/aggregated_metric'
7
7
  require 'sqreen/log/loggable'
8
8
  require 'sqreen/legacy/waf_redactions'
9
+ require 'sqreen/kit/string_sanitizer'
9
10
 
10
11
  module Sqreen
11
12
  module Legacy
@@ -166,7 +167,7 @@ module Sqreen
166
167
  res[:request][:parameters] = payload['params'] if payload['params']
167
168
  res[:request][:headers] = payload['headers'] if payload['headers']
168
169
 
169
- res = Sqreen::EncodingSanitizer.sanitize(res)
170
+ res = Sqreen::Kit::StringSanitizer.sanitize(res)
170
171
 
171
172
  if rr.redactor
172
173
  res[:request], redacted = rr.redactor.redact(res[:request])
data/lib/sqreen/log.rb CHANGED
@@ -14,16 +14,17 @@ require 'sqreen/deferred_logger'
14
14
 
15
15
  module Sqreen
16
16
  def self.log_init
17
+ deferred_logger = @logger
17
18
  @logger = Sqreen::Logger.new(
18
19
  Sqreen.config_get(:log_level).to_s.upcase,
19
20
  Sqreen.config_get(:log_location)
20
21
  )
21
- Sqreen::DeferredLogger.instance.flush_to(@logger.instance_eval { @logger })
22
+ deferred_logger.flush_to(@logger.instance_eval { @logger })
22
23
  rescue => e
23
24
  warn "Sqreen logger exception: #{e}"
24
25
  end
25
26
 
26
27
  def self::log
27
- @logger || Sqreen::DeferredLogger.instance
28
+ @logger ||= Sqreen::DeferredLogger.new
28
29
  end
29
30
  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 'logger'
7
+ require 'sqreen/log'
7
8
 
8
9
  module Sqreen; end
9
10
  module Sqreen::Log; end
data/lib/sqreen/logger.rb CHANGED
@@ -28,6 +28,26 @@ module Sqreen
28
28
  create_error_logger
29
29
  end
30
30
 
31
+ def debug?
32
+ @logger.debug?
33
+ end
34
+
35
+ def info?
36
+ @logger.info?
37
+ end
38
+
39
+ def warn?
40
+ @logger.warn?
41
+ end
42
+
43
+ def error?
44
+ @logger.error?
45
+ end
46
+
47
+ def fatal?
48
+ @logger.fatal?
49
+ end
50
+
31
51
  def debug(msg = nil, &block)
32
52
  @logger.debug(msg, &block)
33
53
  end
@@ -45,6 +65,10 @@ module Sqreen
45
65
  @logger.error(msg, &block)
46
66
  end
47
67
 
68
+ def unknown(msg = nil, &block)
69
+ @logger.unknown(msg, &block)
70
+ end
71
+
48
72
  def add(severity, msg = nil, &block)
49
73
  send(SEVERITY_TO_METHOD[severity], msg, &block)
50
74
  end
@@ -27,6 +27,7 @@ module Sqreen
27
27
  def initialize
28
28
  @store = []
29
29
  @metrics = {} # name => (metric, period, start)
30
+ @mutex = Mutex.new
30
31
  end
31
32
 
32
33
  # Definition contains a name,period and aggregate at least
@@ -34,6 +35,8 @@ module Sqreen
34
35
  # @param rule [RuleCB] the rule associated with this metric, if any
35
36
  # @param mklass [Object] Override metric object (used in testing)
36
37
  def create_metric(definition, rule = nil, mklass = nil)
38
+ @mutex.lock
39
+
37
40
  name = definition[NAME_KEY]
38
41
  kind = definition[KIND_KEY]
39
42
  klass = valid_metric(kind, name)
@@ -49,6 +52,8 @@ module Sqreen
49
52
  metric.rule = rule
50
53
  metric.period = definition[PERIOD_KEY]
51
54
  metric
55
+ ensure
56
+ @mutex.unlock
52
57
  end
53
58
 
54
59
  def metric?(name)
@@ -57,21 +62,27 @@ module Sqreen
57
62
 
58
63
  # @param at [Time] when is the store emptied
59
64
  def update(name, at, key, value)
65
+ @mutex.lock
60
66
  metric, period, start = @metrics[name]
61
67
  raise UnregisteredMetric, "Unknown metric #{name}" unless metric
62
68
  next_sample(name, at) if start.nil? || (start + period) < at
63
69
  metric.update(key, value)
70
+ ensure
71
+ @mutex.unlock
64
72
  end
65
73
 
66
74
  # Drains every metrics and returns the store content
67
75
  # @param at [Time] when is the store emptied
68
76
  def publish(flush = true, at = Sqreen.time)
77
+ @mutex.lock
69
78
  @metrics.each do |name, (_, period, start)|
70
79
  next_sample(name, at) if flush || !start.nil? && (start + period) < at
71
80
  end
72
81
  out = @store
73
82
  @store = []
74
83
  out
84
+ ensure
85
+ @mutex.unlock
75
86
  end
76
87
 
77
88
  protected
@@ -9,6 +9,26 @@ module Sqreen
9
9
  class NullLogger
10
10
  include Singleton
11
11
 
12
+ def debug?
13
+ false
14
+ end
15
+
16
+ def info?
17
+ false
18
+ end
19
+
20
+ def warn?
21
+ false
22
+ end
23
+
24
+ def error?
25
+ false
26
+ end
27
+
28
+ def fatal?
29
+ false
30
+ end
31
+
12
32
  def debug(_msg = nil); end
13
33
 
14
34
  def info(_msg = nil); end
@@ -19,6 +39,8 @@ module Sqreen
19
39
 
20
40
  def fatal(_msg = nil); end
21
41
 
42
+ def unknown(_msg = nil); end
43
+
22
44
  def add(_severity, _msg = nil); end
23
45
 
24
46
  def formatter=(_); end
@@ -18,6 +18,7 @@ module Sqreen
18
18
  :features_get => :features,
19
19
  :features_change => :change_features,
20
20
  :force_logout => :shutdown,
21
+ :force_restart => :restart,
21
22
  :paths_whitelist => :change_whitelisted_paths,
22
23
  :ips_whitelist => :change_whitelisted_ips,
23
24
  :get_bundle => :upload_bundle,
data/lib/sqreen/rules.rb CHANGED
@@ -114,15 +114,19 @@ module Sqreen
114
114
  Sqreen.log.warn('No JavaScript engine is available. ' \
115
115
  'JavaScript callbacks will be ignored')
116
116
  end
117
- Sqreen.log.info("Ignoring JS callback #{rule_name}")
117
+ Sqreen.log.debug("Ignoring JS callback #{rule_name}")
118
118
  return nil
119
119
  end
120
120
 
121
121
  cb_class = ExecJSCB if js
122
122
 
123
- if cbname && Rules.const_defined?(cbname)
124
- # Only load callbacks from sqreen
125
- cb_class = Rules.const_get(cbname)
123
+ if cbname
124
+ cb_class = if cbname.include?('::')
125
+ # Only load callbacks from sqreen
126
+ Rules.walk_const_get(cbname) if cbname.start_with?('::Sqreen::', 'Sqreen::')
127
+ else
128
+ Rules.const_get(cbname) if Rules.const_defined?(cbname) # rubocop:disable Style/IfInsideElse
129
+ end
126
130
  end
127
131
 
128
132
  if cb_class.nil?
@@ -33,7 +33,7 @@ module Sqreen
33
33
  private
34
34
 
35
35
  def insert_values(ranges)
36
- Sqreen.log.info 'no ips given for IP blacklisting' if ranges.empty?
36
+ Sqreen.log.debug 'no ips given for IP blacklisting' if ranges.empty?
37
37
 
38
38
  ranges.map { |r| Prefix.from_str(r, r) }.each do |prefix|
39
39
  trie_for(prefix).insert prefix
@@ -50,7 +50,7 @@ module Sqreen
50
50
  begin
51
51
  ipa = IPAddr.new(rip)
52
52
  rescue StandardError
53
- Sqreen.log.info "invalid IP address given by framework: #{rip}"
53
+ Sqreen.log.debug "invalid IP address given by framework: #{rip}"
54
54
  return nil
55
55
  end
56
56
 
@@ -55,12 +55,12 @@ module Sqreen
55
55
  end
56
56
 
57
57
  def respond_page
58
- page = open(File.join(File.dirname(__FILE__), '../attack_detected.html'))
58
+ @page ||= File.read(File.join(File.dirname(__FILE__), '../attack_detected.html'))
59
59
  headers = {
60
60
  'Content-Type' => 'text/html',
61
- 'Content-Length' => page.size.to_s,
61
+ 'Content-Length' => @page.size.to_s,
62
62
  }
63
- [@status_code, headers, page]
63
+ [@status_code, headers, [@page]]
64
64
  end
65
65
  end
66
66
  end
@@ -3,6 +3,7 @@
3
3
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
+ require 'sqreen/deprecation'
6
7
  require 'sqreen/framework_cb'
7
8
  require 'sqreen/context'
8
9
  require 'sqreen/conditionable'
@@ -109,6 +110,7 @@ module Sqreen
109
110
  )
110
111
  true
111
112
  end
113
+ Sqreen::Deprecation.deprecate(instance_method(:overtime!))
112
114
  end
113
115
  end
114
116
  end
@@ -11,7 +11,7 @@ require 'sqreen/safe_json'
11
11
  require 'sqreen/exception'
12
12
  require 'sqreen/util/capper'
13
13
  require 'sqreen/dependency/libsqreen'
14
- require 'sqreen/encoding_sanitizer'
14
+ require 'sqreen/kit/string_sanitizer'
15
15
 
16
16
  module Sqreen
17
17
  module Rules
@@ -60,7 +60,7 @@ module Sqreen
60
60
  end
61
61
 
62
62
  # 0 for using defaults (PW_RUN_TIMEOUT)
63
- @max_run_budget_us = (@data['values'].fetch('budget_in_ms', 0) * 1000).to_i
63
+ @max_run_budget_us = (@data['values'].fetch('max_budget_ms', 0) * 1000).to_i
64
64
  @max_run_budget_us = INFINITE_BUDGET_US if @max_run_budget_us >= INFINITE_BUDGET_US
65
65
 
66
66
  Sqreen.log.debug { "Max WAF run budget for #{@waf_rule_name} set to #{@max_run_budget_us} us" }
@@ -82,7 +82,7 @@ module Sqreen
82
82
  waf_args = binding_accessors.each_with_object({}) do |(e, b), h|
83
83
  h[e] = capper.call(b.resolve(*env))
84
84
  end
85
- waf_args = Sqreen::EncodingSanitizer.sanitize(waf_args)
85
+ waf_args = Sqreen::Kit::StringSanitizer.sanitize(waf_args)
86
86
 
87
87
  if budget
88
88
  rem_budget_s = budget - (Sqreen.time - start)
data/lib/sqreen/runner.rb CHANGED
@@ -387,8 +387,25 @@ module Sqreen
387
387
 
388
388
  def change_performance_budget(budget, _context_infos = {})
389
389
  return false unless budget.nil? || budget.to_f > 0
390
- prev = Sqreen.performance_budget
391
- Sqreen.update_performance_budget(budget)
390
+
391
+ if @configuration.get(:weave)
392
+ prev = Sqreen::Weave::Budget.current
393
+ prev = prev.to_h if prev
394
+
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)
404
+ else
405
+ prev = Sqreen.performance_budget
406
+ Sqreen.update_performance_budget(budget)
407
+ end
408
+
392
409
  { :was => prev }
393
410
  end
394
411
 
@@ -478,6 +495,15 @@ module Sqreen
478
495
  logout
479
496
  end
480
497
 
498
+ def restart(_context_infos = {})
499
+ shutdown
500
+ heartbeat_delay = @heartbeat_delay
501
+ Thread.new do
502
+ sleep(2 * heartbeat_delay)
503
+ Sqreen::Worker.start(Sqreen.framework)
504
+ end
505
+ end
506
+
481
507
  def logout(retrying = true)
482
508
  return unless session
483
509
  Sqreen.log.debug("Logging out")
@@ -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.1'.freeze
7
+ VERSION = '1.20.4'.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,10 +4,13 @@
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'
8
+ require 'sqreen/graft/hook'
7
9
  require 'sqreen/graft/hook_point'
8
10
  require 'sqreen/call_countable'
9
11
  require 'sqreen/rules'
10
12
  require 'sqreen/rules/record_request_context'
13
+ require 'sqreen/sqreen_signed_verifier'
11
14
 
12
15
  class Sqreen::Weave::Legacy::Instrumentation
13
16
  attr_accessor :metrics_engine
@@ -60,6 +63,27 @@ class Sqreen::Weave::Legacy::Instrumentation
60
63
  'options' => opts[:perf_metric_percent] || { 'base' => 1.3, 'factor' => 1.0 },
61
64
  )
62
65
 
66
+ metrics_engine.create_metric(
67
+ 'name' => 'req.sq.hook.overhead',
68
+ 'period' => 60,
69
+ 'kind' => 'Binning',
70
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
71
+ )
72
+
73
+ metrics_engine.create_metric(
74
+ 'name' => 'sq.hook.overhead',
75
+ 'period' => 60,
76
+ 'kind' => 'Binning',
77
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
78
+ )
79
+
80
+ metrics_engine.create_metric(
81
+ 'name' => 'sq.shrinkwrap',
82
+ 'period' => 60,
83
+ 'kind' => 'Binning',
84
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
85
+ )
86
+
63
87
  Sqreen.thread_cpu_time? && metrics_engine.create_metric(
64
88
  'name' => 'sq_thread_cpu_pct',
65
89
  'period' => opts[:period] || 60,
@@ -84,6 +108,15 @@ class Sqreen::Weave::Legacy::Instrumentation
84
108
 
85
109
  ### set up rule signature verifier
86
110
  verifier = nil
111
+ if Sqreen.features['rules_signature'] &&
112
+ Sqreen.config_get(:rules_verify_signature) == true &&
113
+ !defined?(::JRUBY_VERSION)
114
+ verifier = Sqreen::SqreenSignedVerifier.new
115
+ Sqreen::Weave.logger.debug('Rules signature enabled')
116
+ else
117
+ Sqreen::Weave.logger.debug('Rules signature disabled')
118
+ end
119
+
87
120
  ### force clean instrumentation callback list
88
121
  @hooks = []
89
122
  ### for each rule description
@@ -94,6 +127,25 @@ class Sqreen::Weave::Legacy::Instrumentation
94
127
  next unless rule_callback
95
128
  ### attach framework to callback
96
129
  rule_callback.framework = framework
130
+ ## create metric
131
+ Sqreen::Weave.logger.debug { "Adding rule metric: #{rule_callback}" }
132
+ [:pre, :post, :failing].each do |whence|
133
+ next unless rule_callback.send(:"#{whence}?")
134
+ metric_name = "sq.#{rule['name']}.#{whence}"
135
+ metrics_engine.create_metric(
136
+ 'name' => metric_name,
137
+ 'period' => 60,
138
+ 'kind' => 'Binning',
139
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
140
+ )
141
+ metric_name = "req.sq.#{rule['name']}.#{whence}"
142
+ metrics_engine.create_metric(
143
+ 'name' => metric_name,
144
+ 'period' => 60,
145
+ 'kind' => 'Binning',
146
+ 'options' => { 'base' => 2.0, 'factor' => 0.1 },
147
+ )
148
+ end
97
149
  ### install callback, observing priority
98
150
  Sqreen::Weave.logger.debug { "Adding rule callback: #{rule_callback}" }
99
151
  @hooks << add_callback("weave,rule=#{rule['name']}", rule_callback, strategy)
@@ -107,30 +159,43 @@ class Sqreen::Weave::Legacy::Instrumentation
107
159
  end
108
160
 
109
161
  metrics_engine = self.metrics_engine
162
+
110
163
  request_hook = Sqreen::Graft::Hook['Sqreen::ShrinkWrap#call', strategy]
111
164
  @hooks << request_hook
112
165
  request_hook.add do
113
166
  before('wave,meta,request', rank: -100000, mandatory: true) do |_call|
114
167
  next unless Sqreen.instrumentation_ready
115
168
 
116
- uuid = SecureRandom.uuid
117
- now = Sqreen::Graft::Timer.read
169
+ # shrinkwrap_timer = Sqreen::Graft::Timer.new('weave,shrinkwrap')
170
+ # shrinkwrap_timer.start
171
+
172
+ request_timer = Sqreen::Graft::Timer.new("request")
173
+ request_timer.start
174
+ sqreen_timer = Sqreen::Graft::Timer.new("sqreen")
175
+ budget = Sqreen::Weave::Budget.current
176
+ request_budget_threshold = budget.threshold if budget
177
+ request_budget_ratio = budget.ratio if budget
178
+ request_budget_is_dynamic = !request_budget_ratio.nil?
179
+ request_budget = !request_budget_threshold.nil?
180
+ timed_level = (Sqreen.features['perf_level'] || 1).to_i
181
+ Sqreen::Weave.logger.debug { "request budget: #{budget.to_h} timed.level: #{timed_level}" } if Sqreen::Weave.logger.debug?
182
+
118
183
  Thread.current[:sqreen_http_request] = {
119
- uuid: uuid,
120
- start_time: now,
121
- time_budget: Sqreen.performance_budget,
184
+ request_timer: request_timer,
185
+ sqreen_timer: sqreen_timer,
122
186
  time_budget_expended: false,
123
- timer: Sqreen::Graft::Timer.new("request_#{uuid}"),
187
+ time_budget_threshold: request_budget_threshold,
188
+ time_budget_dynamic: request_budget_is_dynamic,
189
+ time_budget_ratio: request_budget_ratio,
190
+ time_budget: request_budget,
124
191
  timed_callbacks: [],
125
192
  timed_hooks: [],
126
- timed_hooks_before: [],
127
- timed_hooks_after: [],
128
- timed_hooks_raised: [],
129
- timed_hooks_ensured: [],
193
+ timed_level: timed_level,
130
194
  skipped_callbacks: [],
195
+ # timed_shrinkwrap: shrinkwrap_timer,
131
196
  }
132
197
 
133
- Sqreen::Weave.logger.debug { "request.uuid: #{uuid}" }
198
+ # shrinkwrap_timer.stop
134
199
  end
135
200
 
136
201
  ensured('weave,meta,request', rank: 100000, mandatory: true) do |_call|
@@ -138,105 +203,118 @@ class Sqreen::Weave::Legacy::Instrumentation
138
203
 
139
204
  next if request.nil?
140
205
 
206
+ # shrinkwrap_timer = request[:timed_shrinkwrap]
207
+ # shrinkwrap_timer.start
208
+
141
209
  Thread.current[:sqreen_http_request] = nil
142
- now = Sqreen::Graft::Timer.read
143
- utc_now = Time.now.utc
144
-
145
- request[:timed_callbacks].each do |timer|
146
- duration = timer.duration
147
- # stop = now
148
- # start = now - duration
149
- timer.tag =~ /weave,rule=(.*)$/ && rule = $1
150
- timer.tag =~ /@before/ && whence = 'pre'
151
- timer.tag =~ /@after/ && whence = 'post'
152
- timer.tag =~ /@raised/ && whence = 'failing'
153
-
154
- next unless rule && whence
155
-
156
- # Sqreen::PerformanceNotifications.notify(rule, whence, start, stop)
157
- # => BinnedMetrics
158
- metric_name = "sq.#{rule}.#{whence}"
159
- unless metrics_engine.metric?(metric_name)
160
- metrics_engine.create_metric(
161
- 'name' => metric_name,
162
- 'period' => 60,
163
- 'kind' => 'Binning',
164
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
165
- )
210
+ request_timer = request[:request_timer]
211
+ now = request_timer.stop
212
+
213
+ if request[:timed_level] >= 1
214
+ request[:timed_callbacks].each do |timer|
215
+ duration = timer.duration
216
+
217
+ timer.tag =~ /weave,rule=(.*)$/ && rule = $1
218
+ next unless rule
219
+
220
+ whence = case timer.tag
221
+ when /@before/ then 'pre'
222
+ when /@after/ then 'post'
223
+ when /@raised/ then 'failing'
224
+ end
225
+ next unless whence
226
+
227
+ metric_name = "sq.#{rule}.#{whence}"
228
+ metrics_engine.update(metric_name, now, nil, duration * 1000)
229
+ # Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
166
230
  end
167
- metrics_engine.update(metric_name, now, nil, duration * 1000)
168
- end
169
231
 
170
- metric_name = 'sq.hooks_pre.pre'
171
- duration = request[:timed_hooks_before].sum(&:duration)
172
- unless metrics_engine.metric?(metric_name)
173
- metrics_engine.create_metric(
174
- 'name' => metric_name,
175
- 'period' => 60,
176
- 'kind' => 'Binning',
177
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
178
- )
179
- end
180
- metrics_engine.update(metric_name, now, nil, duration * 1000)
181
-
182
- metric_name = 'sq.hooks_post.post'
183
- duration = request[:timed_hooks_after].sum(&:duration)
184
- unless metrics_engine.metric?(metric_name)
185
- metrics_engine.create_metric(
186
- 'name' => metric_name,
187
- 'period' => 60,
188
- 'kind' => 'Binning',
189
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
190
- )
191
- end
192
- metrics_engine.update(metric_name, now, nil, duration * 1000)
193
-
194
- metric_name = 'sq.hooks_failing.failing'
195
- duration = request[:timed_hooks_raised].sum(&:duration)
196
- unless metrics_engine.metric?(metric_name)
197
- metrics_engine.create_metric(
198
- 'name' => metric_name,
199
- 'period' => 60,
200
- 'kind' => 'Binning',
201
- 'options' => { 'base' => 2.0, 'factor' => 0.1 },
202
- )
232
+ request[:timed_hooks].each do |timer|
233
+ duration = timer.duration
234
+ metrics_engine.update('sq.hook.overhead', now, nil, duration * 1000)
235
+ # Sqreen.observations_queue.push(['sq.hook.overhead', nil, duration * 1000, utc_now])
236
+ end
203
237
  end
204
- metrics_engine.update(metric_name, now, nil, duration * 1000)
205
238
 
206
- skipped = request[:skipped_callbacks].map(&:name)
207
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} callback.skipped.size: #{skipped.count} callback.skipped: [#{skipped.join(', ')}]" }
208
- timer = request[:timer]
209
- total = timer.duration
210
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} timer.total: #{'%.03fus' % (total * 1_000_000)} timer.size: #{timer.size}" }
211
- timings = request[:timed_callbacks].map(&:to_s)
212
- total = request[:timed_callbacks].sum(&:duration)
213
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} callback.total: #{'%.03fus' % (total * 1_000_000)} callback.timings: [#{timings.join(', ')}]" }
214
- timings = request[:timed_hooks].map(&:to_s)
215
- total = request[:timed_hooks].sum(&:duration)
216
- Sqreen::Weave.logger.debug { "request:#{request[:uuid]} hook.total: #{'%.03fus' % (total * 1_000_000)} hook.timings: [#{timings.join(', ')}]" }
239
+ sqreen_timer = request[:sqreen_timer]
240
+ total = sqreen_timer.duration
241
+ Sqreen::Weave.logger.debug { "request sqreen_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
242
+ total = request_timer.duration
243
+ Sqreen::Weave.logger.debug { "request request_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
244
+
245
+ if request[:timed_level] >= 2
246
+ skipped = request[:skipped_callbacks].map(&:name)
247
+ Sqreen::Weave.logger.debug { "request callback.skipped.count: #{skipped.count}" } if Sqreen::Weave.logger.debug?
248
+ timings = request[:timed_callbacks].map(&:to_s)
249
+ total = request[:timed_callbacks].sum(&:duration)
250
+ Sqreen::Weave.logger.debug { "request callback.total: #{'%.03fus' % (total * 1_000_000)} callback.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
251
+ timings = request[:timed_hooks].map(&:to_s)
252
+ total = request[:timed_hooks].sum(&:duration)
253
+ Sqreen::Weave.logger.debug { "request hook.total: #{'%.03fus' % (total * 1_000_000)} hook.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
254
+ end
217
255
 
218
256
  skipped = request[:skipped_callbacks].map(&:name)
219
257
  skipped_rule_name = skipped.first && skipped.first =~ /weave,rule=(.*)$/ && $1
220
- Sqreen.observations_queue.push(['request_overtime', skipped_rule_name, 1, utc_now]) if skipped_rule_name
258
+ metrics_engine.update('request_overtime', now, skipped_rule_name, 1) if skipped_rule_name
259
+ # Sqreen.observations_queue.push(['request_overtime', skipped_rule_name, 1, utc_now]) if skipped_rule_name
221
260
 
222
- sqreen_request_duration = total
223
- Sqreen.observations_queue.push(['sq', nil, sqreen_request_duration * 1000, utc_now])
261
+ sqreen_request_duration = sqreen_timer.duration
262
+ metrics_engine.update('sq', now, nil, sqreen_request_duration * 1000)
263
+ # Sqreen.observations_queue.push(['sq', nil, sqreen_request_duration * 1000, utc_now])
224
264
 
225
- request_duration = now - request[:start_time]
226
- Sqreen.observations_queue.push(['req', nil, request_duration * 1000, utc_now])
265
+ request_duration = request_timer.duration
266
+ metrics_engine.update('req', now, nil, request_duration * 1000)
267
+ # Sqreen.observations_queue.push(['req', nil, request_duration * 1000, utc_now])
227
268
 
228
269
  sqreen_request_ratio = (sqreen_request_duration * 100.0) / (request_duration - sqreen_request_duration)
229
- Sqreen.observations_queue.push(['pct', nil, sqreen_request_ratio, utc_now])
270
+ metrics_engine.update('pct', now, nil, sqreen_request_ratio)
271
+ # Sqreen.observations_queue.push(['pct', nil, sqreen_request_ratio, utc_now])
272
+ Sqreen::Weave.logger.debug { "request sqreen_timer.ratio: #{'%.03f' % (sqreen_request_ratio / 100.0)}" } if Sqreen::Weave.logger.debug?
273
+
274
+ if request[:timed_level] >= 2
275
+ tallies = Hash.new(0.0)
276
+ request[:timed_callbacks].each do |timer|
277
+ duration = timer.duration
278
+
279
+ timer.tag =~ /weave,rule=(.*)$/ && rule = $1
280
+ next unless rule
281
+
282
+ whence = case timer.tag
283
+ when /@before/ then 'pre'
284
+ when /@after/ then 'post'
285
+ when /@raised/ then 'failing'
286
+ end
287
+ next unless whence
288
+
289
+ metric_name = "req.sq.#{rule}.#{whence}"
290
+ tallies[metric_name] += duration
291
+ end
292
+ tallies.each do |metric_name, duration|
293
+ metrics_engine.update(metric_name, now, nil, duration * 1000)
294
+ # Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
295
+ end
296
+
297
+ duration = request[:timed_hooks].sum(&:duration)
298
+ metrics_engine.update('req.sq.hook.overhead', now, nil, duration * 1000)
299
+ # Sqreen.observations_queue.push(['req.sq.hook.overhead', nil, duration * 1000, utc_now])
300
+ end
301
+
302
+ # shrinkwrap_timer.stop
303
+
304
+ # duration = shrinkwrap_timer.duration
305
+ # metrics_engine.update('sq.shrinkwrap', now, nil, duration * 1000)
230
306
  end
231
307
  end.install
232
308
 
233
309
  ### globally declare instrumentation ready
234
310
  Sqreen.instrumentation_ready = true
311
+ Sqreen::Weave.logger.info { "Instrumentation activated" }
235
312
  end
236
313
 
237
314
  # needed by Sqreen::Runner
238
315
  def remove_all_callbacks
239
316
  Sqreen.instrumentation_ready = false
317
+ Sqreen::Weave.logger.info { "Instrumentation deactivated" }
240
318
 
241
319
  loop do
242
320
  hook = @hooks.pop
@@ -253,6 +331,15 @@ class Sqreen::Weave::Legacy::Instrumentation
253
331
  klass = callback.klass
254
332
  method = callback.method
255
333
 
334
+ if (call_count = ENV['SQREEN_DEBUG_CALL_COUNT'])
335
+ call_count = JSON.parse(call_count)
336
+ if callback.respond_to?(:rule_name) && call_count.key?(callback.rule_name)
337
+ count = call_count[callback.rule_name]
338
+ Sqreen::Weave.logger.debug { "override rule: #{callback.rule_name} call_count: #{count.inspect}" }
339
+ callback.instance_eval { @call_count_interval = call_count[callback.rule_name] }
340
+ end
341
+ end
342
+
256
343
  if Sqreen::Graft::HookPoint.new("#{klass}.#{method}").exist?
257
344
  hook_point = "#{klass}.#{method}"
258
345
  elsif Sqreen::Graft::HookPoint.new("#{klass}##{method}").exist?
@@ -275,7 +362,6 @@ class Sqreen::Weave::Legacy::Instrumentation
275
362
  a = call.args
276
363
  r = call.remaining
277
364
 
278
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i}" }
279
365
  begin
280
366
  ret = callback.pre(i, a, r)
281
367
  rescue StandardError => e
@@ -286,17 +372,26 @@ class Sqreen::Weave::Legacy::Instrumentation
286
372
  Sqreen::RemoteException.record(e)
287
373
  end
288
374
  end
289
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i} => return=#{ret.inspect}" }
290
375
 
291
- case ret[:status]
292
- when :skip, 'skip'
293
- throw(b, b.return(ret[:new_return_value]).break!) if ret.key?(:new_return_value)
294
- when :modify_args, 'modify_args'
295
- throw(b, b.args(ret[:args]))
296
- when :raise, 'raise'
297
- throw(b, b.raise(ret[:exception])) if ret.key?(:exception)
298
- throw(b, b.raise(Sqreen::AttackBlocked.new("Sqreen blocked a security threat (type: #{callback.rule_name}). No action is required.")))
299
- end unless ret.nil? || !ret.is_a?(Hash)
376
+ next if ret.nil? || !ret.is_a?(Hash)
377
+
378
+ throw_val =
379
+ case ret[:status]
380
+ when :skip, 'skip'
381
+ b.return(ret[:new_return_value]).break! if ret.key?(:new_return_value)
382
+ when :modify_args, 'modify_args'
383
+ b.args(ret[:args])
384
+ when :raise, 'raise'
385
+ if ret.key?(:exception)
386
+ b.raise(ret[:exception])
387
+ else
388
+ b.raise(Sqreen::AttackBlocked.new("Sqreen blocked a security threat (type: #{callback.rule_name}). No action is required."))
389
+ end
390
+ end
391
+
392
+ next unless throw_val
393
+ throw_val.break! if ret[:skip_rem_cbs]
394
+ throw(b, throw_val)
300
395
  end
301
396
  end
302
397
 
@@ -309,7 +404,6 @@ class Sqreen::Weave::Legacy::Instrumentation
309
404
  a = call.args
310
405
  r = call.remaining
311
406
 
312
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i}" }
313
407
  begin
314
408
  ret = callback.post(v, i, a, r)
315
409
  rescue StandardError => e
@@ -320,7 +414,6 @@ class Sqreen::Weave::Legacy::Instrumentation
320
414
  Sqreen::RemoteException.record(e)
321
415
  end
322
416
  end
323
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i} => return=#{ret.inspect}" }
324
417
 
325
418
  case ret[:status]
326
419
  when :override, 'override'
@@ -341,7 +434,6 @@ class Sqreen::Weave::Legacy::Instrumentation
341
434
  a = call.args
342
435
  r = call.remaining
343
436
 
344
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i}" }
345
437
  begin
346
438
  ret = callback.failing(e, i, a, r)
347
439
  rescue StandardError => e
@@ -352,7 +444,6 @@ class Sqreen::Weave::Legacy::Instrumentation
352
444
  Sqreen::RemoteException.record(e)
353
445
  end
354
446
  end
355
- Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i} => return=#{ret.inspect}" }
356
447
 
357
448
  throw(b, b.raise(e)) if ret.nil? || !ret.is_a?(Hash)
358
449