sqreen 1.19.1-java → 1.21.0.beta3-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 +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
@@ -0,0 +1,228 @@
|
|
1
|
+
# typed: ignore
|
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/aggregated_metric'
|
7
|
+
require 'sqreen/log/loggable'
|
8
|
+
require 'sqreen/legacy/waf_redactions'
|
9
|
+
require 'sqreen/kit/string_sanitizer'
|
10
|
+
|
11
|
+
module Sqreen
|
12
|
+
module Legacy
|
13
|
+
# see also Sqreen::Signals::SignalsSubmissionStrategy
|
14
|
+
# usage in Sqreen:Session
|
15
|
+
class OldEventSubmissionStrategy
|
16
|
+
include Sqreen::Log::Loggable
|
17
|
+
|
18
|
+
RETRY_MANY = 301
|
19
|
+
|
20
|
+
def initialize(post_proc)
|
21
|
+
@post_proc = post_proc
|
22
|
+
end
|
23
|
+
|
24
|
+
def post_metrics(metrics)
|
25
|
+
return if metrics.nil? || metrics.empty?
|
26
|
+
payload = { metrics: metrics.map { |m| EventToHash.convert_agg_metric(m) } }
|
27
|
+
post('metrics', payload, {}, RETRY_MANY)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param attack [Sqreen::Attack]
|
31
|
+
def post_attack(attack)
|
32
|
+
post('attack', EventToHash.convert_attack(attack), {}, RETRY_MANY)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Sqreen::RequestRecord] request_record
|
36
|
+
def post_request_record(request_record)
|
37
|
+
rr_hash = EventToHash.convert_request_record(request_record)
|
38
|
+
post('request_record', rr_hash, {}, RETRY_MANY)
|
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
|
+
data = EventToHash.convert_exception(exception)
|
45
|
+
post('sqreen_exception', data, {}, 5)
|
46
|
+
rescue StandardError => e
|
47
|
+
logger.warn(format('Could not post exception (network down? %s) %s',
|
48
|
+
e.inspect,
|
49
|
+
exception.inspect))
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def post_batch(events)
|
54
|
+
batch = events.map do |event|
|
55
|
+
h = case event
|
56
|
+
when AggregatedMetric
|
57
|
+
logger.warn "Aggregated metric event in non-signal mode. Signals disabled at runtime?"
|
58
|
+
next
|
59
|
+
when Sqreen::Kit::Signals::Signal
|
60
|
+
logger.warn "Signal event in non-signal mode"
|
61
|
+
next
|
62
|
+
when Sqreen::Kit::Signals::Trace
|
63
|
+
logger.warn "Trace event in non-signal mode"
|
64
|
+
next
|
65
|
+
when Attack # in practice only found inside req rec
|
66
|
+
EventToHash.convert_attack event
|
67
|
+
when RemoteException
|
68
|
+
EventToHash.convert_exception event
|
69
|
+
when RequestRecord
|
70
|
+
EventToHash.convert_request_record event
|
71
|
+
else
|
72
|
+
logger.warn "Unexpected event type: #{event}"
|
73
|
+
next
|
74
|
+
end
|
75
|
+
h['event_type'] = event_kind(event)
|
76
|
+
h
|
77
|
+
end
|
78
|
+
Sqreen.log.debug do
|
79
|
+
tally = Hash[events.group_by(&:class).map { |k, v| [k, v.count] }]
|
80
|
+
"Doing batch with the following tally of event types: #{tally}"
|
81
|
+
end
|
82
|
+
post('batch', { batch: batch.compact }, {}, RETRY_MANY)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# see +Sqreen::Session.post+
|
88
|
+
def post(*args)
|
89
|
+
@post_proc[*args]
|
90
|
+
end
|
91
|
+
|
92
|
+
def event_kind(event)
|
93
|
+
case event
|
94
|
+
when Sqreen::RemoteException then 'sqreen_exception'
|
95
|
+
when Sqreen::Attack then 'attack'
|
96
|
+
when Sqreen::RequestRecord then 'request_record'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module EventToHash
|
102
|
+
class << self
|
103
|
+
# @param attack [Sqreen::Attack]
|
104
|
+
def convert_attack(attack)
|
105
|
+
payload = attack.payload
|
106
|
+
res = {}
|
107
|
+
rule_p = payload['rule']
|
108
|
+
request_p = payload['request']
|
109
|
+
res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
|
110
|
+
res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
|
111
|
+
res[:test] = rule_p['test'] if rule_p && rule_p['test']
|
112
|
+
res[:infos] = payload['infos'] if payload['infos']
|
113
|
+
res[:time] = attack.time
|
114
|
+
res[:client_ip] = request_p[:addr] if request_p && request_p[:addr]
|
115
|
+
res[:request] = request_p if request_p
|
116
|
+
res[:params] = payload['params'] if payload['params']
|
117
|
+
res[:context] = payload['context'] if payload['context']
|
118
|
+
res[:headers] = payload['headers'] if payload['headers']
|
119
|
+
res
|
120
|
+
end
|
121
|
+
|
122
|
+
# @param [Sqreen::RequestRecord] rr
|
123
|
+
def convert_request_record(rr)
|
124
|
+
res = { :version => '20171208' }
|
125
|
+
payload = rr.payload
|
126
|
+
|
127
|
+
if payload[:observed]
|
128
|
+
res[:observed] = payload[:observed].dup
|
129
|
+
rulespack = nil
|
130
|
+
if rr.observed[:attacks]
|
131
|
+
res[:observed][:attacks] = rr.observed[:attacks].map do |att|
|
132
|
+
natt = att.dup
|
133
|
+
[:attack_type, :block].each { |k| natt.delete(k) } # signals stuff
|
134
|
+
rulespack = natt.delete(:rulespack_id) || rulespack
|
135
|
+
natt
|
136
|
+
end
|
137
|
+
end
|
138
|
+
if rr.observed[:sqreen_exceptions]
|
139
|
+
res[:observed][:sqreen_exceptions] = rr.observed[:sqreen_exceptions].map do |exc|
|
140
|
+
nex = exc.dup
|
141
|
+
excp = nex.delete(:exception)
|
142
|
+
if excp
|
143
|
+
nex[:message] = excp.message
|
144
|
+
nex[:klass] = excp.class.name
|
145
|
+
end
|
146
|
+
rulespack = nex.delete(:rulespack_id) || rulespack
|
147
|
+
nex
|
148
|
+
end
|
149
|
+
end
|
150
|
+
res[:rulespack_id] = rulespack unless rulespack.nil?
|
151
|
+
if rr.observed[:observations]
|
152
|
+
res[:observed][:observations] = rr.observed[:observations].map do |cat, key, value, time|
|
153
|
+
{ :category => cat, :key => key, :value => value, :time => time }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
if rr.observed[:sdk] # rubocop:disable Style/IfUnlessModifier
|
157
|
+
res[:observed][:sdk] = rr.processed_sdk_calls
|
158
|
+
end
|
159
|
+
end
|
160
|
+
res[:local] = payload['local'] if payload['local']
|
161
|
+
if payload['request']
|
162
|
+
res[:request] = payload['request'].dup
|
163
|
+
res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
|
164
|
+
else
|
165
|
+
res[:request] = {}
|
166
|
+
end
|
167
|
+
if payload['response']
|
168
|
+
res[:response] = payload['response'].dup
|
169
|
+
else
|
170
|
+
res[:response] = {}
|
171
|
+
end
|
172
|
+
|
173
|
+
res[:request][:parameters] = payload['params'] if payload['params']
|
174
|
+
res[:request][:headers] = payload['headers'] if payload['headers']
|
175
|
+
|
176
|
+
res = Sqreen::Kit::StringSanitizer.sanitize(res)
|
177
|
+
|
178
|
+
if rr.redactor
|
179
|
+
res[:request], redacted = rr.redactor.redact(res[:request])
|
180
|
+
redacted = redacted.uniq
|
181
|
+
if redacted.any? && res[:observed] && res[:observed][:attacks]
|
182
|
+
res[:observed][:attacks] = WafRedactions.redact_attacks!(res[:observed][:attacks], redacted)
|
183
|
+
end
|
184
|
+
if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions]
|
185
|
+
res[:observed][:sqreen_exceptions] = WafRedactions.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
res
|
190
|
+
end
|
191
|
+
|
192
|
+
# @param exception_evt [Sqreen::RemoteException]
|
193
|
+
def convert_exception(exception_evt)
|
194
|
+
payload = exception_evt.payload
|
195
|
+
exception = payload['exception']
|
196
|
+
ev = {
|
197
|
+
:klass => exception.class.name,
|
198
|
+
:message => exception.message,
|
199
|
+
:params => payload['request_params'],
|
200
|
+
:time => payload['time'],
|
201
|
+
:infos => {
|
202
|
+
:client_ip => payload['client_ip'],
|
203
|
+
},
|
204
|
+
:request => payload['request_infos'],
|
205
|
+
:headers => payload['headers'],
|
206
|
+
:rule_name => payload['rule_name'],
|
207
|
+
:rulespack_id => payload['rulespack_id'],
|
208
|
+
}
|
209
|
+
|
210
|
+
ev[:infos].merge!(payload['infos']) if payload['infos']
|
211
|
+
return ev unless exception.backtrace
|
212
|
+
ev[:context] = { :backtrace => exception.backtrace.map(&:to_s) }
|
213
|
+
ev
|
214
|
+
end
|
215
|
+
|
216
|
+
# @param [Sqreen::AggregatedMetric] agg_metric
|
217
|
+
def convert_agg_metric(agg_metric)
|
218
|
+
{
|
219
|
+
name: agg_metric.name,
|
220
|
+
observation: agg_metric.data,
|
221
|
+
start: agg_metric.start,
|
222
|
+
finish: agg_metric.finish,
|
223
|
+
}
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# typed: ignore
|
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
|
+
module Sqreen
|
7
|
+
module Legacy
|
8
|
+
module WafRedactions
|
9
|
+
class << self
|
10
|
+
def redact_attacks!(attacks, values)
|
11
|
+
return attacks if values.empty?
|
12
|
+
|
13
|
+
values = values.map { |v| v.downcase if v.is_a?(String) }
|
14
|
+
|
15
|
+
attacks.each do |e|
|
16
|
+
next(e) unless e[:infos]
|
17
|
+
next(e) unless e[:infos][:waf_data]
|
18
|
+
|
19
|
+
parsed = JSON.parse(e[:infos][:waf_data])
|
20
|
+
redacted = parsed.each do |w|
|
21
|
+
next unless (filters = w['filter'])
|
22
|
+
|
23
|
+
filters.each do |f|
|
24
|
+
next unless (v = f['resolved_value'])
|
25
|
+
next unless values.include?(v.downcase)
|
26
|
+
|
27
|
+
f['match_status'] = SensitiveDataRedactor::MASK
|
28
|
+
f['resolved_value'] = SensitiveDataRedactor::MASK
|
29
|
+
end
|
30
|
+
end
|
31
|
+
e[:infos][:waf_data] = JSON.dump(redacted)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000022-waf-data-sanitization.md#changes-to-the-agents
|
36
|
+
def redact_exceptions!(exceptions, values)
|
37
|
+
return exceptions if values.empty?
|
38
|
+
|
39
|
+
exceptions.each do |e|
|
40
|
+
next(e) unless e[:infos]
|
41
|
+
next(e) unless e[:infos][:waf]
|
42
|
+
|
43
|
+
e[:infos][:waf].delete(:args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
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
|
-
|
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
|
28
|
+
@logger ||= Sqreen::DeferredLogger.new
|
28
29
|
end
|
29
30
|
end
|
data/lib/sqreen/log/loggable.rb
CHANGED
@@ -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
|
@@ -23,6 +24,6 @@ module Sqreen::Log::Loggable
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def logger
|
26
|
-
@logger ||
|
27
|
+
@logger || singleton_class.logger
|
27
28
|
end
|
28
29
|
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
|
data/lib/sqreen/metrics.rb
CHANGED
data/lib/sqreen/metrics/base.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'sqreen/mono_time'
|
3
|
+
require 'sqreen/metrics/base'
|
4
|
+
begin
|
5
|
+
require 'sq_detailed_metrics'
|
6
|
+
rescue LoadError => _e # rubocop:disable Lint/HandleExceptions
|
7
|
+
end
|
8
|
+
|
9
|
+
module Sqreen
|
10
|
+
module Metric
|
11
|
+
class ReqDetailed < Base
|
12
|
+
attr_reader :num_requests
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
raise 'SqDetailedMetrics unavailable' unless defined?(SqDetailedMetrics)
|
16
|
+
super(opts)
|
17
|
+
@coll = SqDetailedMetrics::RequestCollection.new
|
18
|
+
@start_time = Sqreen.time
|
19
|
+
@num_requests = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [SqDetailedMetrics::Request] value
|
23
|
+
def update(_key, value)
|
24
|
+
@coll << value
|
25
|
+
@num_requests += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def next_sample(time)
|
29
|
+
data = @coll.serialize
|
30
|
+
@num_requests = 0
|
31
|
+
return nil unless data
|
32
|
+
|
33
|
+
{
|
34
|
+
OBSERVATION_KEY => { 'v1' => Base64.strict_encode64(data) },
|
35
|
+
START_KEY => @start_time,
|
36
|
+
FINISH_KEY => (@start_time = time),
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/sqreen/metrics_store.rb
CHANGED
@@ -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/aggregated_metric'
|
6
7
|
require 'sqreen/metrics'
|
7
8
|
require 'sqreen/mono_time'
|
8
9
|
require 'sqreen/metrics_store/unknown_metric'
|
@@ -26,12 +27,16 @@ module Sqreen
|
|
26
27
|
def initialize
|
27
28
|
@store = []
|
28
29
|
@metrics = {} # name => (metric, period, start)
|
30
|
+
@mutex = Mutex.new
|
29
31
|
end
|
30
32
|
|
31
33
|
# Definition contains a name,period and aggregate at least
|
32
34
|
# @param definition [Hash] a metric definition
|
35
|
+
# @param rule [RuleCB] the rule associated with this metric, if any
|
33
36
|
# @param mklass [Object] Override metric object (used in testing)
|
34
|
-
def create_metric(definition, mklass = nil)
|
37
|
+
def create_metric(definition, rule = nil, mklass = nil)
|
38
|
+
@mutex.lock
|
39
|
+
|
35
40
|
name = definition[NAME_KEY]
|
36
41
|
kind = definition[KIND_KEY]
|
37
42
|
klass = valid_metric(kind, name)
|
@@ -43,30 +48,41 @@ module Sqreen
|
|
43
48
|
definition[PERIOD_KEY],
|
44
49
|
nil # Start
|
45
50
|
]
|
51
|
+
metric.name = name
|
52
|
+
metric.rule = rule
|
53
|
+
metric.period = definition[PERIOD_KEY]
|
46
54
|
metric
|
55
|
+
ensure
|
56
|
+
@mutex.unlock
|
47
57
|
end
|
48
58
|
|
49
59
|
def metric?(name)
|
50
60
|
@metrics.key?(name)
|
51
61
|
end
|
52
62
|
|
53
|
-
# @
|
63
|
+
# @param at [Time] when is the store emptied
|
54
64
|
def update(name, at, key, value)
|
65
|
+
@mutex.lock
|
55
66
|
metric, period, start = @metrics[name]
|
56
67
|
raise UnregisteredMetric, "Unknown metric #{name}" unless metric
|
57
68
|
next_sample(name, at) if start.nil? || (start + period) < at
|
58
69
|
metric.update(key, value)
|
70
|
+
ensure
|
71
|
+
@mutex.unlock
|
59
72
|
end
|
60
73
|
|
61
74
|
# Drains every metrics and returns the store content
|
62
|
-
# @
|
75
|
+
# @param at [Time] when is the store emptied
|
63
76
|
def publish(flush = true, at = Sqreen.time)
|
77
|
+
@mutex.lock
|
64
78
|
@metrics.each do |name, (_, period, start)|
|
65
79
|
next_sample(name, at) if flush || !start.nil? && (start + period) < at
|
66
80
|
end
|
67
81
|
out = @store
|
68
82
|
@store = []
|
69
83
|
out
|
84
|
+
ensure
|
85
|
+
@mutex.unlock
|
70
86
|
end
|
71
87
|
|
72
88
|
protected
|
@@ -75,15 +91,20 @@ module Sqreen
|
|
75
91
|
metric = @metrics[name][0]
|
76
92
|
r = metric.next_sample(at)
|
77
93
|
@metrics[name][2] = at # new start
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
94
|
+
return unless r
|
95
|
+
|
96
|
+
r[NAME_KEY] = name
|
97
|
+
obs = r[Metric::OBSERVATION_KEY]
|
98
|
+
return unless obs && (!obs.respond_to?(:empty?) || !obs.empty?)
|
99
|
+
start_of_mono = Time.now.utc - Sqreen.time
|
100
|
+
|
101
|
+
agg = AggregatedMetric.new
|
102
|
+
agg.metric = metric
|
103
|
+
agg.rule = agg.metric.rule
|
104
|
+
agg.start = start_of_mono + r[Metric::START_KEY]
|
105
|
+
agg.finish = start_of_mono + r[Metric::FINISH_KEY]
|
106
|
+
agg.data = obs
|
107
|
+
@store << agg
|
87
108
|
end
|
88
109
|
|
89
110
|
def valid_metric(kind, name)
|