sqreen 1.15.0-java → 1.15.5-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqreen/actions.rb +114 -43
- data/lib/sqreen/callback_tree.rb +16 -3
- data/lib/sqreen/callbacks.rb +7 -34
- data/lib/sqreen/capped_queue.rb +5 -1
- data/lib/sqreen/configuration.rb +4 -0
- data/lib/sqreen/deliveries/batch.rb +7 -4
- data/lib/sqreen/event.rb +4 -0
- data/lib/sqreen/events/request_record.rb +40 -7
- data/lib/sqreen/frameworks/generic.rb +0 -2
- data/lib/sqreen/frameworks/request_recorder.rb +14 -1
- data/lib/sqreen/instrumentation.rb +57 -33
- data/lib/sqreen/js/mini_racer_adapter.rb +46 -8
- data/lib/sqreen/metrics/average.rb +1 -1
- data/lib/sqreen/metrics/base.rb +4 -2
- data/lib/sqreen/metrics/binning.rb +3 -2
- data/lib/sqreen/metrics/collect.rb +1 -1
- data/lib/sqreen/metrics/sum.rb +1 -1
- data/lib/sqreen/metrics_store.rb +10 -5
- data/lib/sqreen/mono_time.rb +18 -0
- data/lib/sqreen/performance_notifications.rb +13 -38
- data/lib/sqreen/performance_notifications/binned_metrics.rb +12 -14
- data/lib/sqreen/performance_notifications/log.rb +6 -1
- data/lib/sqreen/performance_notifications/log_performance.rb +3 -1
- data/lib/sqreen/performance_notifications/metrics.rb +6 -3
- data/lib/sqreen/performance_notifications/newrelic.rb +6 -2
- data/lib/sqreen/remote_command.rb +26 -0
- data/lib/sqreen/rule_attributes.rb +1 -0
- data/lib/sqreen/rule_callback.rb +38 -0
- data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +3 -2
- data/lib/sqreen/rules_callbacks/blacklist_ips.rb +1 -1
- data/lib/sqreen/rules_callbacks/run_block_user_actions.rb +1 -1
- data/lib/sqreen/rules_callbacks/run_req_start_actions.rb +8 -2
- data/lib/sqreen/runner.rb +11 -8
- data/lib/sqreen/sdk.rb +7 -1
- data/lib/sqreen/session.rb +4 -0
- data/lib/sqreen/trie.rb +274 -0
- data/lib/sqreen/version.rb +1 -1
- metadata +4 -2
@@ -246,7 +246,6 @@ module Sqreen
|
|
246
246
|
return unless ensure_rack_loaded
|
247
247
|
self.remaining_perf_budget = Sqreen.performance_budget
|
248
248
|
SharedStorage.set(:request, Rack::Request.new(object))
|
249
|
-
SharedStorage.inc(:stored_requests)
|
250
249
|
SharedStorage.set(:xss_params, nil)
|
251
250
|
SharedStorage.set(:whitelisted, nil)
|
252
251
|
SharedStorage.set(:request_overtime, nil)
|
@@ -259,7 +258,6 @@ module Sqreen
|
|
259
258
|
|
260
259
|
# Cleanup request context
|
261
260
|
def clean_request
|
262
|
-
return unless SharedStorage.dec(:stored_requests) <= 0
|
263
261
|
payload_creator = Sqreen::PayloadCreator.new(self)
|
264
262
|
close_request_record(Sqreen.queue, Sqreen.observations_queue, payload_creator)
|
265
263
|
self.remaining_perf_budget = nil
|
@@ -5,6 +5,8 @@ require 'sqreen/shared_storage'
|
|
5
5
|
require 'sqreen/events/request_record'
|
6
6
|
require 'sqreen/performance_notifications/log_performance'
|
7
7
|
require 'sqreen/performance_notifications/newrelic'
|
8
|
+
require 'sqreen/log'
|
9
|
+
require 'sqreen/runner'
|
8
10
|
|
9
11
|
module Sqreen
|
10
12
|
# Store event/observations that happened in this request
|
@@ -47,6 +49,8 @@ module Sqreen
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def close_request_record(queue, observations_queue, payload_creator)
|
52
|
+
Sqreen.log.debug { "close_request_record called. observed_items: #{observed_items}" }
|
53
|
+
|
50
54
|
clean_request_record if observed_items.nil?
|
51
55
|
if only_metric_observation
|
52
56
|
push_metrics(observations_queue, queue)
|
@@ -54,12 +58,21 @@ module Sqreen
|
|
54
58
|
end
|
55
59
|
payload = payload_creator.payload(payload_requests)
|
56
60
|
payload[:observed] = observed_items
|
57
|
-
queue.push
|
61
|
+
queue.push create_request_record(payload)
|
58
62
|
clean_request_record
|
59
63
|
end
|
60
64
|
|
61
65
|
protected
|
62
66
|
|
67
|
+
def create_request_record(payload)
|
68
|
+
RequestRecord.new(payload, redactor)
|
69
|
+
end
|
70
|
+
|
71
|
+
def redactor
|
72
|
+
return nil unless Sqreen.config_get(:strip_sensitive_data)
|
73
|
+
@redactor ||= SensitiveDataRedactor.from_config
|
74
|
+
end
|
75
|
+
|
63
76
|
def push_metrics(observations_queue, event_queue)
|
64
77
|
observed_items[:observations].each do |obs|
|
65
78
|
observations_queue.push obs
|
@@ -12,6 +12,7 @@ require 'sqreen/shared_storage'
|
|
12
12
|
require 'sqreen/rules_callbacks/record_request_context'
|
13
13
|
require 'sqreen/rules_callbacks/run_req_start_actions'
|
14
14
|
require 'sqreen/rules_callbacks/run_block_user_actions'
|
15
|
+
require 'sqreen/mono_time'
|
15
16
|
require 'set'
|
16
17
|
|
17
18
|
# How to override a class method:
|
@@ -37,6 +38,11 @@ require 'set'
|
|
37
38
|
module Sqreen
|
38
39
|
class Instrumentation
|
39
40
|
OVERTIME_METRIC = 'request_overtime'.freeze
|
41
|
+
|
42
|
+
PRE_CB = 'pre'.freeze
|
43
|
+
POST_CB = 'post'.freeze
|
44
|
+
FAILING_CB = 'failing'.freeze
|
45
|
+
|
40
46
|
MGMT_COST = 0.000025
|
41
47
|
@@override_semaphore = Mutex.new
|
42
48
|
@@overriden_singleton_methods = false
|
@@ -64,7 +70,7 @@ module Sqreen
|
|
64
70
|
@@overriden_methods
|
65
71
|
end
|
66
72
|
def self.callback_wrapper_pre(callbacks, framework, budget, _klass, method, instance, args, &block)
|
67
|
-
all_start = Sqreen
|
73
|
+
all_start = Sqreen.time
|
68
74
|
#Instrumentation.guard_call(method, []) do
|
69
75
|
returns = []
|
70
76
|
callbacks.each do |cb|
|
@@ -76,9 +82,9 @@ module Sqreen
|
|
76
82
|
end
|
77
83
|
Sqreen.log.debug { "running pre cb #{cb}" }
|
78
84
|
begin
|
79
|
-
start = Sqreen
|
85
|
+
start = Sqreen.time
|
80
86
|
res = cb.pre(instance, args, budget, &block)
|
81
|
-
stop = Sqreen
|
87
|
+
stop = Sqreen.time
|
82
88
|
# The first few pre callbacks could not have a request & hence a budget just yet so we try harder to find it
|
83
89
|
budget = framework.remaining_perf_budget if framework && !budget && Sqreen.performance_budget
|
84
90
|
if budget
|
@@ -95,6 +101,7 @@ module Sqreen
|
|
95
101
|
res[:rule_name] = rule
|
96
102
|
end
|
97
103
|
returns << res
|
104
|
+
break if res.is_a?(Hash) && res[:skip_rem_cbs]
|
98
105
|
rescue StandardError => e
|
99
106
|
Sqreen.log.warn { "we catch an exception: #{e.inspect}" }
|
100
107
|
Sqreen.log.debug e.backtrace
|
@@ -105,21 +112,21 @@ module Sqreen
|
|
105
112
|
end
|
106
113
|
next
|
107
114
|
end
|
108
|
-
Sqreen::PerformanceNotifications.notify(
|
115
|
+
Sqreen::PerformanceNotifications.notify(rule || cb.class.name, PRE_CB, start, stop)
|
109
116
|
end
|
110
|
-
all_stop = Sqreen
|
117
|
+
all_stop = Sqreen.time
|
111
118
|
framework.remaining_perf_budget = budget - (all_stop - all_start) - MGMT_COST * callbacks.size if framework && budget
|
112
|
-
Sqreen::PerformanceNotifications.notify('
|
119
|
+
Sqreen::PerformanceNotifications.notify('hooks_pre', PRE_CB, all_start, all_stop)
|
113
120
|
returns
|
114
121
|
#end
|
115
122
|
rescue StandardError => e
|
116
|
-
Sqreen.log.warn { "we
|
123
|
+
Sqreen.log.warn { "we caught an exception between cbs: #{e.inspect}" }
|
117
124
|
Sqreen::RemoteException.record(e)
|
118
125
|
[]
|
119
126
|
end
|
120
127
|
|
121
128
|
def self.callback_wrapper_post(callbacks, framework, budget, _klass, method, return_val, instance, args, &block)
|
122
|
-
all_start = Sqreen
|
129
|
+
all_start = Sqreen.time
|
123
130
|
#Instrumentation.guard_call(method, []) do
|
124
131
|
returns = []
|
125
132
|
callbacks.reverse_each do |cb|
|
@@ -130,9 +137,9 @@ module Sqreen
|
|
130
137
|
end
|
131
138
|
Sqreen.log.debug { "running post cb #{cb}" }
|
132
139
|
begin
|
133
|
-
start = Sqreen
|
140
|
+
start = Sqreen.time
|
134
141
|
res = cb.post(return_val, instance, args, budget, &block)
|
135
|
-
stop = Sqreen
|
142
|
+
stop = Sqreen.time
|
136
143
|
if budget
|
137
144
|
budget -= (stop - start)
|
138
145
|
cb.overtime! if budget <= 0.0
|
@@ -157,23 +164,23 @@ module Sqreen
|
|
157
164
|
end
|
158
165
|
next
|
159
166
|
end
|
160
|
-
Sqreen::PerformanceNotifications.notify(
|
167
|
+
Sqreen::PerformanceNotifications.notify(rule || cb.class.name, POST_CB, start, stop)
|
161
168
|
end
|
162
|
-
all_stop = Sqreen
|
169
|
+
all_stop = Sqreen.time
|
163
170
|
if framework && budget && framework.remaining_perf_budget
|
164
171
|
framework.remaining_perf_budget = budget - (all_stop - all_start) - MGMT_COST * callbacks.size
|
165
172
|
end
|
166
|
-
Sqreen::PerformanceNotifications.notify('
|
173
|
+
Sqreen::PerformanceNotifications.notify('hooks_post', POST_CB, all_start, all_stop)
|
167
174
|
returns
|
168
175
|
#end
|
169
176
|
rescue StandardError => e
|
170
|
-
Sqreen.log.warn { "we
|
177
|
+
Sqreen.log.warn { "we caught an exception between cbs: #{e.inspect}" }
|
171
178
|
Sqreen::RemoteException.record(e)
|
172
179
|
[]
|
173
180
|
end
|
174
181
|
|
175
182
|
def self.callback_wrapper_failing(callbacks, framework, budget, exception, _klass, method, instance, args, &block)
|
176
|
-
all_start = Sqreen
|
183
|
+
all_start = Sqreen.time
|
177
184
|
#Instrumentation.guard_call(method, []) do
|
178
185
|
returns = []
|
179
186
|
callbacks.each do |cb|
|
@@ -184,9 +191,9 @@ module Sqreen
|
|
184
191
|
end
|
185
192
|
Sqreen.log.debug { "running failing cb #{cb}" }
|
186
193
|
begin
|
187
|
-
start = Sqreen
|
194
|
+
start = Sqreen.time
|
188
195
|
res = cb.failing(exception, instance, args, budget, &block)
|
189
|
-
stop = Sqreen
|
196
|
+
stop = Sqreen.time
|
190
197
|
if budget
|
191
198
|
budget -= (stop - start)
|
192
199
|
cb.overtime! if budget <= 0.0
|
@@ -211,17 +218,17 @@ module Sqreen
|
|
211
218
|
end
|
212
219
|
next
|
213
220
|
end
|
214
|
-
Sqreen::PerformanceNotifications.notify(
|
221
|
+
Sqreen::PerformanceNotifications.notify(rule || cb.class.name, FAILING_CB, start, stop)
|
215
222
|
end
|
216
|
-
all_stop = Sqreen
|
223
|
+
all_stop = Sqreen.time
|
217
224
|
if framework && budget && framework.remaining_perf_budget
|
218
225
|
framework.remaining_perf_budget = budget - (all_stop - all_start) - MGMT_COST * callbacks.size
|
219
226
|
end
|
220
|
-
Sqreen::PerformanceNotifications.notify('
|
227
|
+
Sqreen::PerformanceNotifications.notify('hooks_failing', FAILING_CB, all_start, all_stop)
|
221
228
|
returns
|
222
229
|
# end
|
223
230
|
rescue StandardError => e
|
224
|
-
Sqreen.log.warn "we
|
231
|
+
Sqreen.log.warn "we caught an exception between cbs: #{e.inspect}"
|
225
232
|
Sqreen::RemoteException.record(e)
|
226
233
|
[]
|
227
234
|
end
|
@@ -245,11 +252,8 @@ module Sqreen
|
|
245
252
|
|
246
253
|
def self.define_callback_method(meth, original_meth, klass_name)
|
247
254
|
@sqreen_multi_instr ||= nil
|
248
|
-
proc do |*args, &block|
|
249
|
-
record_req_hp = @@record_request_hookpoints.include?([klass_name, meth]) &&
|
250
|
-
Sqreen::PerformanceNotifications.listen_for?
|
251
|
-
Sqreen::PerformanceNotifications::BinnedMetrics.start_request if record_req_hp
|
252
255
|
|
256
|
+
proc do |*args, &block|
|
253
257
|
budget = nil
|
254
258
|
skip_call = Thread.current[:sqreen_in_use]
|
255
259
|
begin
|
@@ -385,16 +389,28 @@ module Sqreen
|
|
385
389
|
end
|
386
390
|
result
|
387
391
|
ensure
|
388
|
-
if record_req_hp
|
389
|
-
Sqreen::PerformanceNotifications.instrument('Callbacks/hooks_reporting/pre') do
|
390
|
-
Sqreen::PerformanceNotifications::LogPerformance.next_request
|
391
|
-
Sqreen::PerformanceNotifications::NewRelic.next_request
|
392
|
-
Sqreen::PerformanceNotifications::BinnedMetrics.finish_request
|
393
|
-
end
|
394
|
-
end
|
395
392
|
Thread.current[:sqreen_in_use] = false
|
396
393
|
end
|
397
394
|
end
|
395
|
+
end # end of proc
|
396
|
+
end
|
397
|
+
|
398
|
+
def self.request_hookpoint_method(original_meth)
|
399
|
+
proc do |*args, &block|
|
400
|
+
has_notifications = Sqreen::PerformanceNotifications.listen_for?
|
401
|
+
Sqreen::PerformanceNotifications::BinnedMetrics.start_request if has_notifications
|
402
|
+
|
403
|
+
begin
|
404
|
+
send(original_meth, *args, &block)
|
405
|
+
ensure
|
406
|
+
if has_notifications
|
407
|
+
Sqreen::PerformanceNotifications.instrument('next_req_notifs', PRE_CB) do
|
408
|
+
Sqreen::PerformanceNotifications::LogPerformance.next_request
|
409
|
+
Sqreen::PerformanceNotifications::NewRelic.next_request
|
410
|
+
Sqreen::PerformanceNotifications::BinnedMetrics.finish_request
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
398
414
|
end
|
399
415
|
end
|
400
416
|
|
@@ -476,6 +492,12 @@ module Sqreen
|
|
476
492
|
|
477
493
|
define_method(new_method, p)
|
478
494
|
|
495
|
+
if @@record_request_hookpoints.include?([klass_name, meth])
|
496
|
+
p = Instrumentation.request_hookpoint_method(new_method)
|
497
|
+
new_method = "#{new_method}_req_hp_wrapper"
|
498
|
+
define_method(new_method, p)
|
499
|
+
end
|
500
|
+
|
479
501
|
if public_method_defined?(meth)
|
480
502
|
method_kind = :public
|
481
503
|
elsif protected_method_defined?(meth)
|
@@ -568,6 +590,8 @@ module Sqreen
|
|
568
590
|
method = cb.method
|
569
591
|
key = [klass, method]
|
570
592
|
|
593
|
+
@@record_request_hookpoints << key if cb.is_a?(Sqreen::Rules::RecordRequestContext)
|
594
|
+
|
571
595
|
already_overriden = @@overriden_methods.include? key
|
572
596
|
|
573
597
|
if !already_overriden
|
@@ -609,7 +633,6 @@ module Sqreen
|
|
609
633
|
|
610
634
|
@@registered_callbacks.add(cb)
|
611
635
|
@@unovertimable_hookpoints << key unless cb.overtimeable
|
612
|
-
@@record_request_hookpoints << key if cb.is_a?(Sqreen::Rules::RecordRequestContext)
|
613
636
|
@@instrumented_pid = Process.pid
|
614
637
|
end
|
615
638
|
end
|
@@ -710,6 +733,7 @@ module Sqreen
|
|
710
733
|
add_callback(rcb)
|
711
734
|
end
|
712
735
|
|
736
|
+
# add hardcoded callbacks, observing priority
|
713
737
|
hardcoded_callbacks(framework).each { |cb| add_callback(cb) }
|
714
738
|
|
715
739
|
Sqreen.instrumentation_ready = true
|
@@ -82,13 +82,22 @@ module Sqreen
|
|
82
82
|
|
83
83
|
def run_js_cb(cb_name, budget, arguments)
|
84
84
|
@pool.with_context do |ctx|
|
85
|
+
if ctx.code_failed?(@code_id)
|
86
|
+
Sqreen.log.debug do
|
87
|
+
"Skipping execution of callback #{cb_name} (code md5 #{@code_id})" \
|
88
|
+
" due to prev failure of definition evaluation"
|
89
|
+
end
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
|
85
93
|
ctx.add_code(@code_id, @code) unless ctx.has_code?(@code_id)
|
86
94
|
|
87
95
|
begin
|
88
|
-
json_args =
|
96
|
+
json_args = convert_arguments(arguments)
|
89
97
|
ctx.eval_unsafe(
|
90
|
-
|
98
|
+
"sqreen_data['#{@code_id}']['#{cb_name}'].apply(this, #{json_args})", nil, budget)
|
91
99
|
rescue @module::ScriptTerminatedError
|
100
|
+
Sqreen.log.debug "ScriptTerminatedError/#{cb_name}"
|
92
101
|
nil
|
93
102
|
end
|
94
103
|
end
|
@@ -100,9 +109,31 @@ module Sqreen
|
|
100
109
|
|
101
110
|
private
|
102
111
|
|
103
|
-
def
|
104
|
-
|
112
|
+
def convert_arguments(args)
|
113
|
+
JSON.generate(args)
|
114
|
+
rescue JSON::GeneratorError, Encoding::UndefinedConversionError
|
115
|
+
fixed_args = fixup_bad_encoding(args)
|
116
|
+
JSON.generate(fixed_args)
|
117
|
+
end
|
118
|
+
|
119
|
+
def fixup_bad_encoding(arg, max_depth = 100)
|
120
|
+
return nil if max_depth <= 0
|
121
|
+
|
122
|
+
if arg.is_a?(Array)
|
123
|
+
return arg.map { |it| fixup_bad_encoding(it, max_depth - 1) }
|
124
|
+
end
|
125
|
+
|
126
|
+
if arg.is_a?(Hash)
|
127
|
+
return Hash[
|
128
|
+
arg.map do |k, v|
|
129
|
+
[fixup_bad_encoding(k, max_depth - 1),
|
130
|
+
fixup_bad_encoding(v, max_depth - 1)]
|
131
|
+
end
|
132
|
+
]
|
133
|
+
end
|
134
|
+
|
105
135
|
return arg unless arg.is_a?(String)
|
136
|
+
|
106
137
|
unless arg.valid_encoding?
|
107
138
|
return arg.dup.force_encoding(Encoding::ISO_8859_1)
|
108
139
|
end
|
@@ -127,13 +158,20 @@ module Sqreen
|
|
127
158
|
@code_ids.include?(code_id)
|
128
159
|
end
|
129
160
|
|
161
|
+
def code_failed?(code_id)
|
162
|
+
return false unless @failed_code_ids
|
163
|
+
@failed_code_ids.include?(code_id)
|
164
|
+
end
|
165
|
+
|
130
166
|
def add_code(code_id, code)
|
167
|
+
eval_unsafe "(function() { #{code} })()"
|
168
|
+
transf_global_funcs code_id
|
131
169
|
@code_ids ||= Set.new
|
132
|
-
# if it fails, we don't try again
|
133
170
|
@code_ids << code_id
|
134
|
-
|
135
|
-
|
136
|
-
|
171
|
+
rescue
|
172
|
+
@failed_code_ids ||= Set.new
|
173
|
+
@failed_code_ids << code_id
|
174
|
+
raise
|
137
175
|
end
|
138
176
|
|
139
177
|
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
data/lib/sqreen/metrics/base.rb
CHANGED
@@ -18,12 +18,12 @@ module Sqreen
|
|
18
18
|
# @param _at [Time] when was the observation made
|
19
19
|
# @param _key [String] which aggregation key was it made for
|
20
20
|
# @param _value [Object] The observation
|
21
|
-
def update(
|
21
|
+
def update(_key, _value)
|
22
22
|
raise Sqreen::Exception, 'No current sample' unless @sample
|
23
23
|
end
|
24
24
|
|
25
25
|
# create a new empty sample and publish the last one
|
26
|
-
# @param time [
|
26
|
+
# @param time [Float] Time of start of new sample/end of the last one
|
27
27
|
def next_sample(time)
|
28
28
|
finalize_sample(time) unless @sample.nil?
|
29
29
|
current_sample = @sample
|
@@ -33,10 +33,12 @@ module Sqreen
|
|
33
33
|
|
34
34
|
protected
|
35
35
|
|
36
|
+
# @param time [Float]
|
36
37
|
def new_sample(time)
|
37
38
|
@sample = { OBSERVATION_KEY => {}, START_KEY => time }
|
38
39
|
end
|
39
40
|
|
41
|
+
# @param time [Float]
|
40
42
|
def finalize_sample(time)
|
41
43
|
@sample[FINISH_KEY] = time
|
42
44
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# Copyright (c) 2018 Sqreen. All Rights Reserved.
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
|
+
require 'sqreen/mono_time'
|
4
5
|
require 'sqreen/metrics/base'
|
5
6
|
|
6
7
|
module Sqreen
|
@@ -20,10 +21,10 @@ module Sqreen
|
|
20
21
|
log_factor = Math.log(@factor)
|
21
22
|
@inv_log_base = 1 / log_base
|
22
23
|
@add_parcel = - log_factor / log_base
|
23
|
-
new_sample(
|
24
|
+
new_sample(Sqreen.time)
|
24
25
|
end
|
25
26
|
|
26
|
-
def update(
|
27
|
+
def update(_key, x)
|
27
28
|
h = @sample[OBSERVATION_KEY]
|
28
29
|
bin = bin_no(x)
|
29
30
|
h[bin] += 1
|