sqreen 1.15.0-java → 1.15.5-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.
- 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
|