sqreen 1.19.1-java → 1.21.0.beta3-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +34 -0
- data/lib/sqreen/actions/block_user.rb +1 -1
- data/lib/sqreen/actions/redirect_ip.rb +1 -1
- data/lib/sqreen/actions/redirect_user.rb +1 -1
- data/lib/sqreen/agent_message.rb +20 -0
- data/lib/sqreen/aggregated_metric.rb +25 -0
- data/lib/sqreen/attack_detected.html +1 -2
- data/lib/sqreen/ca.crt +24 -0
- data/lib/sqreen/condition_evaluator.rb +9 -2
- data/lib/sqreen/conditionable.rb +24 -6
- data/lib/sqreen/configuration.rb +11 -5
- data/lib/sqreen/deferred_logger.rb +50 -14
- data/lib/sqreen/deliveries/batch.rb +12 -2
- data/lib/sqreen/deliveries/simple.rb +4 -0
- data/lib/sqreen/deprecation.rb +38 -0
- data/lib/sqreen/ecosystem.rb +96 -0
- data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
- data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
- data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
- data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
- data/lib/sqreen/ecosystem/loggable.rb +13 -0
- data/lib/sqreen/ecosystem/module_api.rb +30 -0
- data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
- data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
- data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
- data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
- data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
- data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
- data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
- data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
- data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
- data/lib/sqreen/ecosystem/module_registry.rb +44 -0
- data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
- data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
- data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
- data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
- data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
- data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
- data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
- data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
- data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
- data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
- data/lib/sqreen/ecosystem_integration.rb +87 -0
- data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
- data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
- data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
- data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
- data/lib/sqreen/endpoint_testing.rb +184 -0
- data/lib/sqreen/event.rb +7 -5
- data/lib/sqreen/events/attack.rb +23 -18
- data/lib/sqreen/events/remote_exception.rb +0 -22
- data/lib/sqreen/events/request_record.rb +15 -71
- data/lib/sqreen/frameworks/generic.rb +24 -1
- data/lib/sqreen/frameworks/rails.rb +0 -7
- data/lib/sqreen/frameworks/request_recorder.rb +15 -2
- data/lib/sqreen/graft/call.rb +106 -19
- data/lib/sqreen/graft/callback.rb +1 -1
- data/lib/sqreen/graft/hook.rb +212 -100
- data/lib/sqreen/graft/hook_point.rb +18 -11
- data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
- data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
- data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
- data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
- data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
- data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
- data/lib/sqreen/legacy/instrumentation.rb +22 -10
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
- data/lib/sqreen/legacy/waf_redactions.rb +49 -0
- data/lib/sqreen/log.rb +3 -2
- data/lib/sqreen/log/loggable.rb +2 -1
- data/lib/sqreen/logger.rb +24 -0
- data/lib/sqreen/metrics.rb +1 -0
- data/lib/sqreen/metrics/base.rb +3 -0
- data/lib/sqreen/metrics/req_detailed.rb +41 -0
- data/lib/sqreen/metrics_store.rb +33 -12
- data/lib/sqreen/null_logger.rb +22 -0
- data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
- data/lib/sqreen/remote_command.rb +4 -0
- data/lib/sqreen/rules.rb +12 -6
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
- data/lib/sqreen/rules/custom_error_cb.rb +3 -3
- data/lib/sqreen/rules/not_found_cb.rb +2 -0
- data/lib/sqreen/rules/rule_cb.rb +6 -2
- data/lib/sqreen/rules/waf_cb.rb +16 -13
- data/lib/sqreen/runner.rb +138 -16
- data/lib/sqreen/sensitive_data_redactor.rb +19 -31
- data/lib/sqreen/session.rb +53 -43
- data/lib/sqreen/signals/conversions.rb +288 -0
- data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
- data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +35 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +277 -135
- data/lib/sqreen/worker.rb +6 -2
- metadata +86 -10
- data/lib/sqreen/backport.rb +0 -9
- data/lib/sqreen/backport/clock_gettime.rb +0 -74
- data/lib/sqreen/backport/original_name.rb +0 -88
- data/lib/sqreen/encoding_sanitizer.rb +0 -27
data/lib/sqreen/event.rb
CHANGED
@@ -8,17 +8,19 @@
|
|
8
8
|
module Sqreen
|
9
9
|
# Master interface for point in time events (e.g. Attack, RemoteException)
|
10
10
|
class Event
|
11
|
+
# @return [Hash]
|
11
12
|
attr_reader :payload
|
13
|
+
|
14
|
+
# @return [Time]
|
15
|
+
attr_accessor :time # writer used only in tests
|
16
|
+
|
12
17
|
def initialize(payload)
|
13
18
|
@payload = payload
|
14
|
-
|
15
|
-
|
16
|
-
def to_hash
|
17
|
-
payload.to_hash
|
19
|
+
@time = Time.now.utc
|
18
20
|
end
|
19
21
|
|
20
22
|
def to_s
|
21
|
-
"<#{self.class.name}: #{to_hash}>"
|
23
|
+
"<#{self.class.name}: #{payload.to_hash}>"
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/sqreen/events/attack.rb
CHANGED
@@ -11,6 +11,8 @@ module Sqreen
|
|
11
11
|
# Attack
|
12
12
|
# When creating a new attack, it gets automatically pushed to the event's
|
13
13
|
# queue.
|
14
|
+
# XXX: TURNS OUT THIS CLASS IS ACTUALLY NOT USED ANYMORE
|
15
|
+
# Framework.observe is used instead with unstructured attack details
|
14
16
|
class Attack < Event
|
15
17
|
def self.record(payload)
|
16
18
|
attack = Attack.new(payload)
|
@@ -26,11 +28,31 @@ module Sqreen
|
|
26
28
|
payload['rule']['rulespack_id']
|
27
29
|
end
|
28
30
|
|
29
|
-
def
|
31
|
+
def rule_name
|
30
32
|
return nil unless payload['rule']
|
31
33
|
payload['rule']['name']
|
32
34
|
end
|
33
35
|
|
36
|
+
def test?
|
37
|
+
return nil unless payload['rule']
|
38
|
+
payload['rule']['test'] ? true : false
|
39
|
+
end
|
40
|
+
|
41
|
+
def beta?
|
42
|
+
return nil unless payload['rule']
|
43
|
+
payload['rule']['beta'] ? true : false
|
44
|
+
end
|
45
|
+
|
46
|
+
def block?
|
47
|
+
return nil unless payload['rule']
|
48
|
+
payload['rule']['block'] ? true : false
|
49
|
+
end
|
50
|
+
|
51
|
+
def attack_type
|
52
|
+
return nil unless payload['rule']
|
53
|
+
payload['rule']['attack_type']
|
54
|
+
end
|
55
|
+
|
34
56
|
def time
|
35
57
|
return nil unless payload['local']
|
36
58
|
payload['local']['time']
|
@@ -44,22 +66,5 @@ module Sqreen
|
|
44
66
|
def enqueue
|
45
67
|
Sqreen.queue.push(self)
|
46
68
|
end
|
47
|
-
|
48
|
-
def to_hash
|
49
|
-
res = {}
|
50
|
-
rule_p = payload['rule']
|
51
|
-
request_p = payload['request']
|
52
|
-
res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
|
53
|
-
res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
|
54
|
-
res[:test] = rule_p['test'] if rule_p && rule_p['test']
|
55
|
-
res[:infos] = payload['infos'] if payload['infos']
|
56
|
-
res[:time] = time if time
|
57
|
-
res[:client_ip] = request_p[:addr] if request_p && request_p[:addr]
|
58
|
-
res[:request] = request_p if request_p
|
59
|
-
res[:params] = payload['params'] if payload['params']
|
60
|
-
res[:context] = payload['context'] if payload['context']
|
61
|
-
res[:headers] = payload['headers'] if payload['headers']
|
62
|
-
res
|
63
|
-
end
|
64
69
|
end
|
65
70
|
end
|
@@ -30,27 +30,5 @@ module Sqreen
|
|
30
30
|
def klass
|
31
31
|
payload['exception'].class.name
|
32
32
|
end
|
33
|
-
|
34
|
-
def to_hash
|
35
|
-
exception = payload['exception']
|
36
|
-
ev = {
|
37
|
-
:klass => exception.class.name,
|
38
|
-
:message => exception.message,
|
39
|
-
:params => payload['request_params'],
|
40
|
-
:time => payload['time'],
|
41
|
-
:infos => {
|
42
|
-
:client_ip => payload['client_ip'],
|
43
|
-
},
|
44
|
-
:request => payload['request_infos'],
|
45
|
-
:headers => payload['headers'],
|
46
|
-
:rule_name => payload['rule_name'],
|
47
|
-
:rulespack_id => payload['rulespack_id'],
|
48
|
-
}
|
49
|
-
|
50
|
-
ev[:infos].merge!(payload['infos']) if payload['infos']
|
51
|
-
return ev unless exception.backtrace
|
52
|
-
ev[:context] = { :backtrace => exception.backtrace.map(&:to_s) }
|
53
|
-
ev
|
54
|
-
end
|
55
33
|
end
|
56
34
|
end
|
@@ -8,12 +8,15 @@
|
|
8
8
|
require 'json'
|
9
9
|
require 'sqreen/log'
|
10
10
|
require 'sqreen/event'
|
11
|
-
require 'sqreen/encoding_sanitizer'
|
12
11
|
require 'sqreen/sensitive_data_redactor'
|
13
12
|
|
14
13
|
module Sqreen
|
15
14
|
# When a request is deeemed worthy of being sent to the backend
|
16
15
|
class RequestRecord < Sqreen::Event
|
16
|
+
attr_reader :redactor
|
17
|
+
|
18
|
+
# @param [Hash] payload
|
19
|
+
# @param [Sqreen::SensitiveDataRedactor] redactor
|
17
20
|
def initialize(payload, redactor = nil)
|
18
21
|
@redactor = redactor
|
19
22
|
super(payload)
|
@@ -23,74 +26,18 @@ module Sqreen
|
|
23
26
|
(payload && payload[:observed]) || {}
|
24
27
|
end
|
25
28
|
|
26
|
-
def
|
27
|
-
|
28
|
-
if payload[:observed]
|
29
|
-
res[:observed] = payload[:observed].dup
|
30
|
-
rulespack = nil
|
31
|
-
if observed[:attacks]
|
32
|
-
res[:observed][:attacks] = observed[:attacks].map do |att|
|
33
|
-
natt = att.dup
|
34
|
-
rulespack = natt.delete(:rulespack_id) || rulespack
|
35
|
-
natt
|
36
|
-
end
|
37
|
-
end
|
38
|
-
if observed[:sqreen_exceptions]
|
39
|
-
res[:observed][:sqreen_exceptions] = observed[:sqreen_exceptions].map do |exc|
|
40
|
-
nex = exc.dup
|
41
|
-
excp = nex.delete(:exception)
|
42
|
-
if excp
|
43
|
-
nex[:message] = excp.message
|
44
|
-
nex[:klass] = excp.class.name
|
45
|
-
end
|
46
|
-
rulespack = nex.delete(:rulespack_id) || rulespack
|
47
|
-
nex
|
48
|
-
end
|
49
|
-
end
|
50
|
-
res[:rulespack_id] = rulespack unless rulespack.nil?
|
51
|
-
if observed[:observations]
|
52
|
-
res[:observed][:observations] = observed[:observations].map do |cat, key, value, time|
|
53
|
-
{ :category => cat, :key => key, :value => value, :time => time }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
if observed[:sdk]
|
57
|
-
res[:observed][:sdk] = processed_sdk_calls
|
58
|
-
end
|
59
|
-
end
|
60
|
-
res[:local] = payload['local'] if payload['local']
|
61
|
-
if payload['request']
|
62
|
-
res[:request] = payload['request'].dup
|
63
|
-
res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
|
64
|
-
else
|
65
|
-
res[:request] = {}
|
66
|
-
end
|
67
|
-
if payload['response']
|
68
|
-
res[:response] = payload['response'].dup
|
69
|
-
else
|
70
|
-
res[:response] = {}
|
71
|
-
end
|
72
|
-
|
73
|
-
res[:request][:parameters] = payload['params'] if payload['params']
|
74
|
-
res[:request][:headers] = payload['headers'] if payload['headers']
|
75
|
-
|
76
|
-
res = Sqreen::EncodingSanitizer.sanitize(res)
|
29
|
+
def last_identify_args
|
30
|
+
return nil unless observed[:sdk]
|
77
31
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
res[:observed][:attacks] = @redactor.redact_attacks!(res[:observed][:attacks], redacted)
|
82
|
-
end
|
83
|
-
if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions]
|
84
|
-
res[:observed][:sqreen_exceptions] = @redactor.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted)
|
85
|
-
end
|
32
|
+
observed[:sdk].reverse_each do |meth, _time, *args|
|
33
|
+
next unless meth == :identify
|
34
|
+
return args
|
86
35
|
end
|
87
|
-
|
88
|
-
res
|
36
|
+
nil
|
89
37
|
end
|
90
38
|
|
91
|
-
private
|
92
|
-
|
93
39
|
def processed_sdk_calls
|
40
|
+
return [] unless observed[:sdk]
|
94
41
|
auth_keys = last_identify_id
|
95
42
|
|
96
43
|
observed[:sdk].map do |meth, time, *args|
|
@@ -102,6 +49,8 @@ module Sqreen
|
|
102
49
|
end
|
103
50
|
end
|
104
51
|
|
52
|
+
private
|
53
|
+
|
105
54
|
def inject_identifiers(args, meth, auth_keys)
|
106
55
|
return args unless meth == :track && auth_keys
|
107
56
|
|
@@ -118,13 +67,8 @@ module Sqreen
|
|
118
67
|
end
|
119
68
|
|
120
69
|
def last_identify_id
|
121
|
-
|
122
|
-
|
123
|
-
observed[:sdk].reverse_each do |meth, _time, *args|
|
124
|
-
next unless meth == :identify
|
125
|
-
return args.first if args.respond_to? :first
|
126
|
-
end
|
127
|
-
nil
|
70
|
+
args = last_identify_args
|
71
|
+
args.first if args.respond_to? :first
|
128
72
|
end
|
129
73
|
end
|
130
74
|
end
|
@@ -22,8 +22,17 @@ module Sqreen
|
|
22
22
|
include RequestRecorder
|
23
23
|
attr_accessor :sqreen_configuration
|
24
24
|
|
25
|
+
attr_writer :req_start_cb, :req_end_cb
|
26
|
+
|
25
27
|
def initialize
|
26
28
|
clean_request_record
|
29
|
+
|
30
|
+
# for notifying the ecosystem of request boundaries
|
31
|
+
# XXX: this should be refactored. It shouldn't be
|
32
|
+
# the framework doing these notifications to the ecosystem
|
33
|
+
# Probably the rule callback should do it itself
|
34
|
+
@req_start_cb = Proc.new {}
|
35
|
+
@req_end_cb = Proc.new {}
|
27
36
|
end
|
28
37
|
|
29
38
|
# What kind of database is this
|
@@ -209,7 +218,16 @@ module Sqreen
|
|
209
218
|
|
210
219
|
# Should the agent not be starting up?
|
211
220
|
def prevent_startup
|
221
|
+
# SQREEN-880 - prevent Sqreen startup on Sidekiq workers
|
222
|
+
return :sidekiq_cli if defined?(Sidekiq::CLI)
|
223
|
+
return :delayed_job if defined?(Delayed::Command)
|
224
|
+
|
225
|
+
# Prevent Sqreen startup on rake tasks - unless this is a Sqreen test
|
226
|
+
run_in_test = sqreen_configuration.get(:run_in_test)
|
227
|
+
return :rake if !run_in_test && $0.end_with?('rake')
|
228
|
+
|
212
229
|
return :irb if $0 == 'irb'
|
230
|
+
|
213
231
|
return if sqreen_configuration.nil?
|
214
232
|
disable = sqreen_configuration.get(:disable)
|
215
233
|
return :config_disable if disable == true || disable.to_s.to_i == 1
|
@@ -251,8 +269,12 @@ module Sqreen
|
|
251
269
|
# Nota: cleanup should be performed at end of request (see clean_request)
|
252
270
|
def store_request(object)
|
253
271
|
return unless ensure_rack_loaded
|
272
|
+
|
273
|
+
rack_req = Rack::Request.new(object)
|
274
|
+
@req_start_cb.call(rack_req)
|
275
|
+
|
254
276
|
self.remaining_perf_budget = Sqreen.performance_budget
|
255
|
-
SharedStorage.set(:request,
|
277
|
+
SharedStorage.set(:request, rack_req)
|
256
278
|
SharedStorage.set(:xss_params, nil)
|
257
279
|
SharedStorage.set(:whitelisted, nil)
|
258
280
|
SharedStorage.set(:request_overtime, nil)
|
@@ -281,6 +303,7 @@ module Sqreen
|
|
281
303
|
SharedStorage.set(:xss_params, nil)
|
282
304
|
SharedStorage.set(:whitelisted, nil)
|
283
305
|
SharedStorage.set(:request_overtime, nil)
|
306
|
+
@req_end_cb.call
|
284
307
|
end
|
285
308
|
|
286
309
|
def remaining_perf_budget
|
@@ -103,13 +103,6 @@ module Sqreen
|
|
103
103
|
run_in_test = sqreen_configuration.get(:run_in_test)
|
104
104
|
return :rails_test if !run_in_test && (Rails.env.test? || Rails.env.cucumber?)
|
105
105
|
|
106
|
-
# SQREEN-880 - prevent Sqreen startup on Sidekiq workers
|
107
|
-
return :sidekiq_cli if defined?(Sidekiq::CLI)
|
108
|
-
return :delayed_job if defined?(Delayed::Command)
|
109
|
-
|
110
|
-
# Prevent Sqreen startup on rake tasks - unless this is a Sqreen test
|
111
|
-
return :rake if !run_in_test && $0.end_with?('rake')
|
112
|
-
|
113
106
|
return nil unless defined?(Rails::CommandsTasks)
|
114
107
|
return nil if defined?(Rails::Server)
|
115
108
|
return :rails_console if defined?(Rails::Console)
|
@@ -58,12 +58,22 @@ module Sqreen
|
|
58
58
|
Sqreen.log.debug { "close_request_record called. observed_items: #{observed_items}" }
|
59
59
|
|
60
60
|
clean_request_record if observed_items.nil?
|
61
|
-
if only_metric_observation
|
61
|
+
if Sqreen.features['use_signals'] || only_metric_observation
|
62
62
|
push_metrics(observations_queue, queue)
|
63
|
-
return clean_request_record
|
64
63
|
end
|
64
|
+
|
65
|
+
if only_metric_observation
|
66
|
+
clean_request_record
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
# signals require request section to be present
|
71
|
+
payload_requests << 'request'
|
72
|
+
# for signals, response is optional, but the backend team wants them
|
73
|
+
payload_requests << 'response'
|
65
74
|
payload = payload_creator.payload(payload_requests)
|
66
75
|
payload[:observed] = observed_items
|
76
|
+
|
67
77
|
queue.push create_request_record(payload)
|
68
78
|
clean_request_record
|
69
79
|
end
|
@@ -79,10 +89,13 @@ module Sqreen
|
|
79
89
|
@redactor ||= SensitiveDataRedactor.from_config
|
80
90
|
end
|
81
91
|
|
92
|
+
# pushes metric observations to the observations queue
|
93
|
+
# and clears the list for the request record
|
82
94
|
def push_metrics(observations_queue, event_queue)
|
83
95
|
observed_items[:observations].each do |obs|
|
84
96
|
observations_queue.push obs
|
85
97
|
end
|
98
|
+
observed_items[:observations] = []
|
86
99
|
return unless observations_queue.size > MAX_OBS_QUEUE_LENGTH / 2
|
87
100
|
event_queue.push Sqreen::METRICS_EVENT
|
88
101
|
end
|
data/lib/sqreen/graft/call.rb
CHANGED
@@ -27,6 +27,10 @@ module Sqreen
|
|
27
27
|
def raise(value)
|
28
28
|
Flow.raise(value)
|
29
29
|
end
|
30
|
+
|
31
|
+
def noop
|
32
|
+
Flow.noop
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
class Flow
|
@@ -46,12 +50,17 @@ module Sqreen
|
|
46
50
|
def raise(value)
|
47
51
|
new(:raise, value)
|
48
52
|
end
|
53
|
+
|
54
|
+
def noop
|
55
|
+
new(:noop, nil)
|
56
|
+
end
|
49
57
|
end
|
50
58
|
|
51
59
|
def initialize(action, value, brk = false)
|
52
60
|
@action = action
|
53
61
|
@value = value
|
54
62
|
@break = brk
|
63
|
+
@passed_conditions = false
|
55
64
|
end
|
56
65
|
|
57
66
|
def return?
|
@@ -91,60 +100,138 @@ module Sqreen
|
|
91
100
|
def break?
|
92
101
|
@break ? true : false
|
93
102
|
end
|
103
|
+
|
104
|
+
def passed_conditions!
|
105
|
+
@passed_conditions = true
|
106
|
+
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
def passed_conditions?
|
111
|
+
@passed_conditions
|
112
|
+
end
|
94
113
|
end
|
95
114
|
|
115
|
+
class TimerError < StandardError; end
|
116
|
+
|
96
117
|
class Timer
|
97
118
|
def self.read
|
98
119
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
99
120
|
end
|
100
121
|
|
101
|
-
attr_reader :tag
|
122
|
+
attr_reader :tag, :size
|
123
|
+
attr_accessor :conditions_passed
|
102
124
|
|
103
125
|
def initialize(tag, &block)
|
104
126
|
@tag = tag
|
105
|
-
@blips = []
|
106
127
|
@block = block
|
128
|
+
@tally = 0
|
129
|
+
@size = 0
|
107
130
|
end
|
108
131
|
|
109
|
-
def
|
110
|
-
|
132
|
+
def elapsed
|
133
|
+
raise(TimerError, 'Timer#elapsed when paused') if @size.even?
|
134
|
+
|
135
|
+
@tally + Timer.read
|
111
136
|
end
|
112
137
|
|
113
|
-
def
|
114
|
-
|
138
|
+
def duration
|
139
|
+
raise(TimerError, 'Timer#duration when running') if @size.odd?
|
140
|
+
|
141
|
+
@tally
|
115
142
|
end
|
116
143
|
|
117
144
|
def ignore
|
118
|
-
|
145
|
+
raise(TimerError, 'Timer#ignore when paused') if @size.even?
|
146
|
+
|
147
|
+
@size += 1
|
148
|
+
@tally += Timer.read
|
119
149
|
yield(self)
|
120
150
|
ensure
|
121
|
-
@
|
151
|
+
@size += 1
|
152
|
+
@tally -= Timer.read
|
122
153
|
end
|
123
154
|
|
124
|
-
def measure
|
125
|
-
|
155
|
+
def measure(opts = nil)
|
156
|
+
raise(TimerError, 'Timer#measure when running') if @size.odd?
|
157
|
+
|
158
|
+
now = Timer.read
|
159
|
+
|
160
|
+
ignore = opts[:ignore] if opts
|
161
|
+
if ignore
|
162
|
+
ignore.size += 1
|
163
|
+
ignore.tally += now
|
164
|
+
end
|
165
|
+
|
166
|
+
@size += 1
|
167
|
+
@tally -= now
|
168
|
+
|
126
169
|
yield(self)
|
127
170
|
ensure
|
128
|
-
|
171
|
+
now = Timer.read
|
172
|
+
|
173
|
+
if ignore
|
174
|
+
ignore.size += 1
|
175
|
+
ignore.tally -= now
|
176
|
+
end
|
177
|
+
|
178
|
+
@size += 1
|
179
|
+
@tally += now
|
180
|
+
|
129
181
|
@block.call(self) if @block
|
130
|
-
Sqreen::Graft.logger.debug { "#{@tag}: time=%.03fus" % (duration * 1_000_000) }
|
131
182
|
end
|
132
183
|
|
133
|
-
def start
|
134
|
-
|
184
|
+
def start(at = Timer.read)
|
185
|
+
raise(TimerError, 'Timer#start when started') unless @size.even?
|
186
|
+
|
187
|
+
@size += 1
|
188
|
+
@tally -= at
|
189
|
+
|
190
|
+
at
|
191
|
+
end
|
192
|
+
|
193
|
+
def stop(at = Timer.read)
|
194
|
+
raise(TimerError, 'Timer#stop when unstarted') unless @size.odd?
|
195
|
+
|
196
|
+
@size += 1
|
197
|
+
@tally += at
|
198
|
+
|
199
|
+
at
|
135
200
|
end
|
136
201
|
|
137
|
-
def
|
138
|
-
@
|
202
|
+
def started?
|
203
|
+
@size != 0 && @size.odd?
|
139
204
|
end
|
140
205
|
|
141
|
-
def
|
142
|
-
@
|
206
|
+
def stopped?
|
207
|
+
@size != 0 && @size.even?
|
208
|
+
end
|
209
|
+
|
210
|
+
def running?
|
211
|
+
@size.odd?
|
212
|
+
end
|
213
|
+
|
214
|
+
def paused?
|
215
|
+
@size.even?
|
216
|
+
end
|
217
|
+
|
218
|
+
def include_measurements(another_timer)
|
219
|
+
@blips += another_timer.instance_variable_get(:@blips)
|
220
|
+
end
|
221
|
+
|
222
|
+
def start_and_end
|
223
|
+
raise 'Not exactly two measurements recorded' unless size == 2
|
224
|
+
@blips
|
143
225
|
end
|
144
226
|
|
145
227
|
def to_s
|
146
|
-
"#{@tag}: time=%.03fus" % (
|
228
|
+
"#{@tag}: time=%.03fus" % (@tally * 1_000_000)
|
147
229
|
end
|
230
|
+
|
231
|
+
protected
|
232
|
+
|
233
|
+
attr_reader :tally
|
234
|
+
attr_writer :size, :tally
|
148
235
|
end
|
149
236
|
end
|
150
237
|
end
|