sqreen 0.8.11465220943 → 1.0.0.pre1480953244
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.rb +0 -1
- data/lib/sqreen/binding_accessor.rb +61 -49
- data/lib/sqreen/condition_evaluator.rb +17 -12
- data/lib/sqreen/conditionable.rb +2 -1
- data/lib/sqreen/configuration.rb +2 -0
- data/lib/sqreen/deliveries/batch.rb +2 -2
- data/lib/sqreen/events/attack.rb +1 -1
- data/lib/sqreen/frameworks/generic.rb +54 -15
- data/lib/sqreen/frameworks/rails.rb +1 -21
- data/lib/sqreen/frameworks/sinatra.rb +5 -0
- data/lib/sqreen/instrumentation.rb +7 -10
- data/lib/sqreen/log.rb +1 -0
- data/lib/sqreen/metrics/base.rb +4 -0
- data/lib/sqreen/metrics_store.rb +4 -4
- data/lib/sqreen/remote_command.rb +5 -4
- data/lib/sqreen/rules_callbacks.rb +0 -4
- data/lib/sqreen/rules_callbacks/matcher_rule.rb +8 -6
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +55 -11
- data/lib/sqreen/runner.rb +76 -73
- data/lib/sqreen/runtime_infos.rb +3 -2
- data/lib/sqreen/serializer.rb +46 -0
- data/lib/sqreen/session.rb +22 -12
- data/lib/sqreen/version.rb +1 -1
- metadata +6 -14
- data/lib/sqreen/detect.rb +0 -14
- data/lib/sqreen/detect/shell_injection.rb +0 -61
- data/lib/sqreen/detect/sql_injection.rb +0 -115
- data/lib/sqreen/parsers/sql.rb +0 -98
- data/lib/sqreen/parsers/sql_tokenizer.rb +0 -266
- data/lib/sqreen/parsers/unix.rb +0 -110
- data/lib/sqreen/rules_callbacks/shell.rb +0 -33
- data/lib/sqreen/rules_callbacks/sql.rb +0 -41
- data/lib/sqreen/rules_callbacks/system_shell.rb +0 -25
@@ -159,15 +159,13 @@ module Sqreen
|
|
159
159
|
end
|
160
160
|
|
161
161
|
def self.guard_call(method, retval)
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
return r
|
170
|
-
end
|
162
|
+
@sqreen_in_instr ||= nil
|
163
|
+
return retval if @sqreen_in_instr && @sqreen_in_instr.member?(method)
|
164
|
+
@sqreen_in_instr ||= Set.new
|
165
|
+
@sqreen_in_instr.add(method)
|
166
|
+
r = yield
|
167
|
+
@sqreen_in_instr.delete(method)
|
168
|
+
return r
|
171
169
|
rescue Exception => e
|
172
170
|
@sqreen_in_instr.delete(method)
|
173
171
|
raise e
|
@@ -338,7 +336,6 @@ module Sqreen
|
|
338
336
|
saved_meth_name = get_saved_method_name(meth)
|
339
337
|
|
340
338
|
eval "method_kind = nil; class << #{klass}
|
341
|
-
new_method = '#{meth}_modified'.to_sym
|
342
339
|
case
|
343
340
|
when public_method_defined?(#{meth.to_sym.inspect})
|
344
341
|
method_kind = :public
|
data/lib/sqreen/log.rb
CHANGED
data/lib/sqreen/metrics/base.rb
CHANGED
@@ -10,6 +10,10 @@ module Sqreen
|
|
10
10
|
FINISH_KEY = 'finish'.freeze
|
11
11
|
# Base interface for a metric
|
12
12
|
class Base
|
13
|
+
def initialize
|
14
|
+
@sample = nil
|
15
|
+
end
|
16
|
+
|
13
17
|
# Update the current metric with a new observation
|
14
18
|
# @param _at [Time] when was the observation made
|
15
19
|
# @param _key [String] which aggregation key was it made for
|
data/lib/sqreen/metrics_store.rb
CHANGED
@@ -49,15 +49,15 @@ module Sqreen
|
|
49
49
|
at = at.utc
|
50
50
|
metric, period, start = @metrics[name]
|
51
51
|
raise UnregisteredMetric, "Unknown metric #{name}" unless metric
|
52
|
-
next_sample(name, at) if start.nil? || start + period < at
|
52
|
+
next_sample(name, at) if start.nil? || (start + period) < at
|
53
53
|
metric.update(at, key, value)
|
54
54
|
end
|
55
55
|
|
56
56
|
# Drains every metrics and returns the store content
|
57
57
|
# @params at [Time] when is the store emptied
|
58
|
-
def publish(at = Time.now.utc)
|
59
|
-
@metrics.
|
60
|
-
next_sample(name, at)
|
58
|
+
def publish(flush = true, at = Time.now.utc)
|
59
|
+
@metrics.each do |name, (_, period, start)|
|
60
|
+
next_sample(name, at) if flush || !start.nil? && (start + period) < at
|
61
61
|
end
|
62
62
|
out = @store
|
63
63
|
@store = []
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
require "sqreen/log"
|
3
4
|
|
4
5
|
module Sqreen
|
5
6
|
# Execute and sanitize remote commands
|
@@ -20,15 +21,15 @@ module Sqreen
|
|
20
21
|
@uuid = json_desc['uuid']
|
21
22
|
end
|
22
23
|
|
23
|
-
def process(runner)
|
24
|
+
def process(runner, context_infos = {})
|
24
25
|
failing = validate_command(runner)
|
25
26
|
return failing if failing
|
26
27
|
Sqreen.log.debug format('processing command %s', @name)
|
27
|
-
output = runner.send(KNOWN_COMMANDS[@name], *@params)
|
28
|
+
output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
|
28
29
|
format_output(output)
|
29
30
|
end
|
30
31
|
|
31
|
-
def self.process_list(runner, commands)
|
32
|
+
def self.process_list(runner, commands, context_infos = {})
|
32
33
|
res_list = {}
|
33
34
|
|
34
35
|
return res_list unless commands
|
@@ -43,7 +44,7 @@ module Sqreen
|
|
43
44
|
cmd = RemoteCommand.new(cmd_json)
|
44
45
|
Sqreen.log.debug cmd.inspect
|
45
46
|
uuid = cmd.uuid
|
46
|
-
res_list[uuid] = cmd.process(runner)
|
47
|
+
res_list[uuid] = cmd.process(runner, context_infos)
|
47
48
|
end
|
48
49
|
res_list
|
49
50
|
end
|
@@ -11,12 +11,8 @@ require 'sqreen/rules_callbacks/headers_insert'
|
|
11
11
|
|
12
12
|
require 'sqreen/rules_callbacks/inspect_rule'
|
13
13
|
|
14
|
-
require 'sqreen/rules_callbacks/shell'
|
15
|
-
require 'sqreen/rules_callbacks/system_shell'
|
16
14
|
require 'sqreen/rules_callbacks/shell_env'
|
17
15
|
|
18
|
-
require 'sqreen/rules_callbacks/sql'
|
19
|
-
|
20
16
|
require 'sqreen/rules_callbacks/url_matches'
|
21
17
|
require 'sqreen/rules_callbacks/user_agent_matches'
|
22
18
|
require 'sqreen/rules_callbacks/crawler_user_agent_matches'
|
@@ -19,6 +19,7 @@ module Sqreen
|
|
19
19
|
Regexp.compile(value, res)
|
20
20
|
end
|
21
21
|
|
22
|
+
ANYWHERE_OPT = 'anywhere'.freeze
|
22
23
|
def prepare
|
23
24
|
@string = {}
|
24
25
|
@regex_patterns = []
|
@@ -30,10 +31,10 @@ module Sqreen
|
|
30
31
|
end
|
31
32
|
|
32
33
|
@funs = {
|
33
|
-
|
34
|
-
'starts_with' => lambda { |value, str| str.start_with?(value) },
|
35
|
-
'ends_with'
|
36
|
-
'equals'
|
34
|
+
ANYWHERE_OPT => lambda { |value, str| str.include?(value) },
|
35
|
+
'starts_with'.freeze => lambda { |value, str| str.start_with?(value) },
|
36
|
+
'ends_with'.freeze => lambda { |value, str| str.end_with?(value) },
|
37
|
+
'equals'.freeze => lambda { |value, str| str == value },
|
37
38
|
}
|
38
39
|
|
39
40
|
patterns.each do |entry|
|
@@ -41,7 +42,8 @@ module Sqreen
|
|
41
42
|
type = entry['type']
|
42
43
|
val = entry['value']
|
43
44
|
opts = entry['options']
|
44
|
-
opt =
|
45
|
+
opt = ANYWHERE_OPT
|
46
|
+
opt = opts.first.freeze if opts && opts.first && opts.first != ''
|
45
47
|
case_sensitive = entry['case_sensitive'] || false
|
46
48
|
case type
|
47
49
|
when 'string'
|
@@ -49,7 +51,7 @@ module Sqreen
|
|
49
51
|
case_type = :cs
|
50
52
|
else
|
51
53
|
case_type = :ci
|
52
|
-
val
|
54
|
+
val.downcase!
|
53
55
|
end
|
54
56
|
|
55
57
|
unless @funs.keys.include?(opt)
|
@@ -7,35 +7,79 @@ require 'sqreen/rules_callbacks/regexp_rule'
|
|
7
7
|
|
8
8
|
module Sqreen
|
9
9
|
module Rules
|
10
|
-
# look for reflected XSS
|
10
|
+
# look for reflected XSS with erb template engine
|
11
11
|
class ReflectedXSSCB < RegexpRuleCB
|
12
12
|
def pre(_inst, *args, &_block)
|
13
13
|
value = args[0]
|
14
|
-
|
14
|
+
|
15
|
+
return unless value.is_a?(String)
|
16
|
+
|
15
17
|
# If the value is not marked as html_safe, it will be escaped later
|
16
18
|
return unless value.html_safe?
|
17
19
|
|
18
20
|
# Sqreen::log.debug value
|
19
|
-
# Sqreen::log.debug params
|
20
21
|
|
21
22
|
return unless framework.params_include?(value)
|
22
23
|
|
23
24
|
Sqreen.log.debug { format('Found unescaped user param: %s', value) }
|
24
25
|
|
25
|
-
return unless value.is_a?(String)
|
26
|
-
|
27
26
|
saved_value = value.dup
|
28
27
|
# potential XSS! let's escape
|
29
28
|
args[0].replace(CGI.escape_html(value)) if block
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
|
30
|
+
report_dangerous_xss(saved_value)
|
31
|
+
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# The remaining code is only to find out if user entry was an attack,
|
36
|
+
# and record it. Since we don't rely on it to respond to user, it would
|
37
|
+
# be better to do it in background.
|
38
|
+
def report_dangerous_xss(value)
|
39
|
+
found = match_regexp(value)
|
34
40
|
|
35
41
|
return unless found
|
36
|
-
infos = {
|
42
|
+
infos = {
|
43
|
+
:found => found,
|
44
|
+
:payload => value
|
45
|
+
}
|
37
46
|
record_event(infos)
|
38
|
-
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# look for reflected XSS with haml template engine
|
50
|
+
# hook function arguments of
|
51
|
+
# Haml::Buffer.format_script(result, preserve_script, in_tag, preserve_tag,
|
52
|
+
# escape_html, nuke_inner_whitespace,
|
53
|
+
# interpolated, ugly)
|
54
|
+
class ReflectedXSSHamlCB < ReflectedXSSCB
|
55
|
+
def pre(inst, *args, &_block)
|
56
|
+
value = args[0]
|
57
|
+
|
58
|
+
return unless value.is_a?(String)
|
59
|
+
|
60
|
+
# if escape_html is already true, it will be escaped later
|
61
|
+
return if args[4]
|
62
|
+
|
63
|
+
return unless framework.params_include?(value)
|
64
|
+
|
65
|
+
Sqreen.log.debug { format('Found unescaped user param: %s', value) }
|
66
|
+
|
67
|
+
# potential XSS ! Call the same method with the argument
|
68
|
+
# escape_html true
|
69
|
+
if block
|
70
|
+
nargs = args.dup
|
71
|
+
nargs[4] = true
|
72
|
+
return_value = {
|
73
|
+
:status => :skip,
|
74
|
+
# 'method' is an attribut reader in class CB, it's the name of the
|
75
|
+
# hooked method
|
76
|
+
:new_return_value => inst.send(method, *nargs),
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
report_dangerous_xss(value)
|
81
|
+
|
82
|
+
return_value
|
39
83
|
end
|
40
84
|
end
|
41
85
|
end
|
data/lib/sqreen/runner.rb
CHANGED
@@ -2,18 +2,21 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'timeout'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
require 'sqreen/events/attack'
|
7
8
|
|
8
9
|
require 'sqreen/log'
|
9
10
|
|
10
11
|
require 'sqreen/rules'
|
12
|
+
require 'sqreen/session'
|
11
13
|
require 'sqreen/remote_command'
|
12
14
|
require 'sqreen/capped_queue'
|
13
15
|
require 'sqreen/metrics_store'
|
14
16
|
require 'sqreen/deliveries/simple'
|
15
17
|
require 'sqreen/deliveries/batch'
|
16
18
|
require 'sqreen/performance_notifications/metrics'
|
19
|
+
require 'sqreen/instrumentation'
|
17
20
|
|
18
21
|
module Sqreen
|
19
22
|
@features = {}
|
@@ -48,19 +51,18 @@ module Sqreen
|
|
48
51
|
|
49
52
|
# Main running job class for the agent
|
50
53
|
class Runner
|
51
|
-
# At start, heartbeat is every 15 seconds
|
52
|
-
HEARTBEAT_INITIAL_DELAY = 15
|
53
54
|
# During one hour
|
54
55
|
HEARTBEAT_WARMUP = 60 * 60
|
55
|
-
#
|
56
|
+
# Initail delay is 5 minutes
|
56
57
|
HEARTBEAT_MAX_DELAY = 5 * 60
|
57
58
|
|
58
|
-
|
59
|
+
attr_accessor :heartbeat_delay
|
59
60
|
attr_accessor :metrics_engine
|
60
|
-
attr_reader :publish_metrics_delay
|
61
61
|
attr_reader :deliverer
|
62
62
|
attr_reader :session
|
63
63
|
attr_reader :instrumenter
|
64
|
+
attr_accessor :next_command_results
|
65
|
+
attr_accessor :next_metrics
|
64
66
|
|
65
67
|
# we may want to do that in a thread in order to prevent delaying app
|
66
68
|
# startup
|
@@ -69,12 +71,10 @@ module Sqreen
|
|
69
71
|
@logged_out_tried = false
|
70
72
|
@configuration = configuration
|
71
73
|
@framework = framework
|
72
|
-
@heartbeat_delay =
|
73
|
-
@
|
74
|
-
@
|
75
|
-
@
|
76
|
-
@last_post_metrics_request = Time.now
|
77
|
-
@started = Time.now
|
74
|
+
@heartbeat_delay = HEARTBEAT_MAX_DELAY
|
75
|
+
@last_heartbeat_request = Time.now
|
76
|
+
@next_command_results = {}
|
77
|
+
@next_metrics = []
|
78
78
|
|
79
79
|
@token = @configuration.get(:token)
|
80
80
|
@url = @configuration.get(:url)
|
@@ -83,13 +83,37 @@ module Sqreen
|
|
83
83
|
|
84
84
|
register_exit_cb if set_at_exit
|
85
85
|
|
86
|
+
self.metrics_engine = MetricsStore.new
|
87
|
+
@instrumenter = Instrumentation.new(metrics_engine)
|
88
|
+
|
86
89
|
Sqreen.log.warn "using token #{@token}"
|
87
|
-
|
90
|
+
response = create_session(session_class)
|
91
|
+
wanted_features = response.fetch('features', {})
|
92
|
+
conf_initial_features = configuration.get(:initial_features)
|
93
|
+
unless conf_initial_features.nil?
|
94
|
+
begin
|
95
|
+
conf_features = JSON.parse(conf_initial_features)
|
96
|
+
raise 'Invalid Type' unless conf_features.is_a?(Hash)
|
97
|
+
Sqreen.log.debug do
|
98
|
+
"Override initial features with #{conf_features.inspect}"
|
99
|
+
end
|
100
|
+
wanted_features = conf_features
|
101
|
+
rescue
|
102
|
+
Sqreen.log.error do
|
103
|
+
"NOT using Invalid inital features #{conf_initial_features}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
self.features = wanted_features
|
108
|
+
|
88
109
|
# Ensure a deliverer is there unless features have set it first
|
89
110
|
self.deliverer ||= Deliveries::Simple.new(session)
|
90
111
|
|
91
|
-
|
92
|
-
|
112
|
+
context_infos = {}
|
113
|
+
%w(rules pack_id).each do |p|
|
114
|
+
context_infos[p] = response[p] unless response[p].nil?
|
115
|
+
end
|
116
|
+
process_commands(response.fetch('commands', []), context_infos)
|
93
117
|
end
|
94
118
|
|
95
119
|
def create_session(session_class)
|
@@ -112,20 +136,27 @@ module Sqreen
|
|
112
136
|
end
|
113
137
|
end
|
114
138
|
|
115
|
-
def load_rules
|
116
|
-
rules_pack =
|
117
|
-
rulespack_id =
|
118
|
-
|
119
|
-
|
120
|
-
|
139
|
+
def load_rules(context_infos = {})
|
140
|
+
rules_pack = context_infos['rules']
|
141
|
+
rulespack_id = context_infos['pack_id']
|
142
|
+
if rules_pack.nil? || rulespack_id.nil?
|
143
|
+
session_rules = session.rules
|
144
|
+
rules_pack = session_rules['rules']
|
145
|
+
rulespack_id = session_rules['pack_id']
|
146
|
+
end
|
147
|
+
rules = rules_pack.each { |r| r['rulespack_id'] = rulespack_id }
|
148
|
+
Sqreen.log.info { format('retrieved rulespack id: %s', rulespack_id) }
|
149
|
+
Sqreen.log.debug { format('retrieved %d rules', rules.size) }
|
121
150
|
local_rules = Sqreen::Rules.local(@configuration) || []
|
122
151
|
rules += local_rules.
|
123
152
|
select { |rule| rule['enabled'] }.
|
124
153
|
each { |r| r['rulespack_id'] = 'local' }
|
125
|
-
Sqreen.log.debug
|
126
|
-
|
127
|
-
|
128
|
-
|
154
|
+
Sqreen.log.debug do
|
155
|
+
format('rules: %s', rules.
|
156
|
+
sort_by { |r| r['name'] }.
|
157
|
+
map { |r| format('(%s, %s)', r['name'], r.to_json.size) }.
|
158
|
+
join(', '))
|
159
|
+
end
|
129
160
|
[rulespack_id, rules]
|
130
161
|
end
|
131
162
|
|
@@ -138,20 +169,20 @@ module Sqreen
|
|
138
169
|
end
|
139
170
|
end
|
140
171
|
|
141
|
-
def setup_instrumentation
|
172
|
+
def setup_instrumentation(context_infos = {})
|
142
173
|
Sqreen.log.info 'setup instrumentation'
|
143
|
-
rulespack_id, rules = load_rules
|
174
|
+
rulespack_id, rules = load_rules(context_infos)
|
144
175
|
@framework.instrument_when_ready!(instrumenter, rules)
|
145
176
|
rulespack_id.to_s
|
146
177
|
end
|
147
178
|
|
148
|
-
def remove_instrumentation
|
179
|
+
def remove_instrumentation(_context_infos = {})
|
149
180
|
Sqreen.log.debug 'removing instrumentation'
|
150
181
|
instrumenter.remove_all_callbacks
|
151
182
|
true
|
152
183
|
end
|
153
184
|
|
154
|
-
def reload_rules
|
185
|
+
def reload_rules(_context_infos = {})
|
155
186
|
Sqreen.log.debug 'Reloading rules'
|
156
187
|
rulespack_id, rules = load_rules
|
157
188
|
instrumenter.remove_all_callbacks
|
@@ -161,22 +192,21 @@ module Sqreen
|
|
161
192
|
rulespack_id.to_s
|
162
193
|
end
|
163
194
|
|
164
|
-
def process_commands(commands)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
commands = res['commands']
|
169
|
-
end
|
195
|
+
def process_commands(commands, context_infos = {})
|
196
|
+
return if commands.nil? || commands.empty?
|
197
|
+
res = RemoteCommand.process_list(self, commands, context_infos)
|
198
|
+
@next_command_results = res
|
170
199
|
end
|
171
200
|
|
172
201
|
def do_heartbeat
|
173
202
|
@last_heartbeat_request = Time.now
|
174
|
-
res = session.heartbeat
|
175
|
-
|
203
|
+
res = session.heartbeat(next_command_results, next_metrics)
|
204
|
+
next_command_results.clear
|
205
|
+
next_metrics.clear
|
176
206
|
process_commands(res['commands'])
|
177
207
|
end
|
178
208
|
|
179
|
-
def features
|
209
|
+
def features(_context_infos = {})
|
180
210
|
Sqreen.features
|
181
211
|
end
|
182
212
|
|
@@ -184,13 +214,13 @@ module Sqreen
|
|
184
214
|
Sqreen.update_features(features)
|
185
215
|
session.request_compression = features['request_compression'] if session
|
186
216
|
self.performance_metrics_period = features['performance_metrics_period']
|
187
|
-
|
188
|
-
self.
|
217
|
+
hd = features['heartbeat_delay'].to_i
|
218
|
+
self.heartbeat_delay = hd if hd > 0
|
189
219
|
return if features['batch_size'].nil?
|
190
220
|
batch_events(features['batch_size'], features['max_staleness'])
|
191
221
|
end
|
192
222
|
|
193
|
-
def change_features(new_features)
|
223
|
+
def change_features(new_features, _context_infos = {})
|
194
224
|
old = features
|
195
225
|
self.features = new_features
|
196
226
|
{
|
@@ -208,7 +238,7 @@ module Sqreen
|
|
208
238
|
end
|
209
239
|
|
210
240
|
def run_watcher_once
|
211
|
-
event = Timeout.timeout(
|
241
|
+
event = Timeout.timeout(heartbeat_delay) do
|
212
242
|
Sqreen.queue.pop
|
213
243
|
end
|
214
244
|
rescue Timeout::Error
|
@@ -231,8 +261,10 @@ module Sqreen
|
|
231
261
|
@deliverer.tick
|
232
262
|
aggregate_observations
|
233
263
|
t = Time.now
|
234
|
-
|
235
|
-
|
264
|
+
if (@last_heartbeat_request + heartbeat_delay) < t
|
265
|
+
@next_metrics.concat(metrics_engine.publish(false)) if metrics_engine
|
266
|
+
do_heartbeat
|
267
|
+
end
|
236
268
|
end
|
237
269
|
|
238
270
|
def handle_event(event)
|
@@ -249,35 +281,6 @@ module Sqreen
|
|
249
281
|
end
|
250
282
|
end
|
251
283
|
|
252
|
-
def update_heartbeat_delay
|
253
|
-
return unless Time.now - @started > HEARTBEAT_WARMUP
|
254
|
-
return if heartbeat_delay == HEARTBEAT_MAX_DELAY
|
255
|
-
self.heartbeat_delay = HEARTBEAT_MAX_DELAY
|
256
|
-
end
|
257
|
-
|
258
|
-
def update_sleep_delay
|
259
|
-
@sleep_delay = [heartbeat_delay, publish_metrics_delay].min
|
260
|
-
Sqreen.log.debug { format('sleep delay %f', @sleep_delay) }
|
261
|
-
end
|
262
|
-
|
263
|
-
def heartbeat_delay=(x)
|
264
|
-
@heartbeat_delay = x
|
265
|
-
update_sleep_delay
|
266
|
-
x
|
267
|
-
end
|
268
|
-
|
269
|
-
def publish_metrics_delay=(x)
|
270
|
-
@publish_metrics_delay = x
|
271
|
-
update_sleep_delay
|
272
|
-
x
|
273
|
-
end
|
274
|
-
|
275
|
-
def post_metrics
|
276
|
-
return unless metrics_engine
|
277
|
-
@last_post_metrics_request = Time.now
|
278
|
-
session.post_metrics(metrics_engine.publish)
|
279
|
-
end
|
280
|
-
|
281
284
|
# Sinatra is using at_exit to run the application, see:
|
282
285
|
# https://github.com/sinatra/sinatra/blob/cd503e6c590cd48c2c9bb7869522494bfc62cb14/lib/sinatra/main.rb#L25
|
283
286
|
def exit_from_sinatra_startup?
|
@@ -295,7 +298,7 @@ module Sqreen
|
|
295
298
|
@logged_out_tried = true
|
296
299
|
@deliverer.drain if @deliverer
|
297
300
|
aggregate_observations
|
298
|
-
post_metrics
|
301
|
+
session.post_metrics(metrics_engine.publish) if metrics_engine
|
299
302
|
session.logout(retrying)
|
300
303
|
end
|
301
304
|
|