rookout 0.1.0 → 0.1.56
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rookout/atfork.rb +73 -0
- data/lib/rookout/augs/actions/action_run_processor.rb +4 -3
- data/lib/rookout/augs/aug.rb +33 -91
- data/lib/rookout/augs/aug_factory.rb +94 -27
- data/lib/rookout/augs/aug_rate_limiter.rb +50 -47
- data/lib/rookout/augs/augs_manager.rb +3 -1
- data/lib/rookout/augs/conditions/condition.rb +4 -2
- data/lib/rookout/augs/limits_manager.rb +32 -0
- data/lib/rookout/augs/locations/location.rb +75 -1
- data/lib/rookout/augs/locations/location_exception_handler.rb +22 -0
- data/lib/rookout/augs/locations/location_file_line.rb +21 -5
- data/lib/rookout/com_ws/agent_com_ws.rb +97 -58
- data/lib/rookout/com_ws/backoff.rb +5 -10
- data/lib/rookout/com_ws/command_handler.rb +1 -1
- data/lib/rookout/com_ws/envelope_wrapper.rb +68 -0
- data/lib/rookout/com_ws/git.rb +1 -1
- data/lib/rookout/com_ws/information.rb +95 -4
- data/lib/rookout/com_ws/output.rb +69 -21
- data/lib/rookout/com_ws/pinger.rb +41 -0
- data/lib/rookout/com_ws/websocket_client.rb +173 -0
- data/lib/rookout/commit.rb +3 -0
- data/lib/rookout/config.rb +94 -18
- data/lib/rookout/exceptions.rb +147 -12
- data/lib/rookout/interface.rb +95 -32
- data/lib/rookout/logger.rb +39 -10
- data/lib/rookout/processor/namespace_serializer.rb +2 -2
- data/lib/rookout/processor/namespace_serializer2.rb +331 -0
- data/lib/rookout/processor/namespaces/container_namespace.rb +5 -0
- data/lib/rookout/processor/namespaces/frame_namespace.rb +20 -17
- data/lib/rookout/processor/namespaces/namespace.rb +3 -2
- data/lib/rookout/processor/namespaces/noop_namespace.rb +4 -8
- data/lib/rookout/processor/namespaces/ruby_object_namespace.rb +39 -22
- data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +15 -12
- data/lib/rookout/processor/namespaces/ruby_utils_namespace.rb +0 -4
- data/lib/rookout/processor/namespaces/stack_namespace.rb +6 -4
- data/lib/rookout/processor/namespaces/traceback_namespace.rb +13 -9
- data/lib/rookout/processor/operations/set_operation.rb +6 -1
- data/lib/rookout/processor/paths/arithmetic_path.rb +5 -3
- data/lib/rookout/processor/paths/canopy/actions.rb +5 -1
- data/lib/rookout/processor/paths/canopy/consts.rb +6 -4
- data/lib/rookout/processor/paths/canopy/maps.rb +286 -286
- data/lib/rookout/processor/paths/canopy/markers.rb +35 -4
- data/lib/rookout/processor/processor_factory.rb +0 -2
- data/lib/rookout/processor/rook_error.rb +6 -1
- data/lib/rookout/protobuf/controller_info_pb.rb +1 -0
- data/lib/rookout/protobuf/messages_pb.rb +54 -0
- data/lib/rookout/protobuf/variant2_pb.rb +42 -0
- data/lib/rookout/protobuf/variant_pb.rb +22 -0
- data/lib/rookout/rookout_singleton.rb +23 -5
- data/lib/rookout/sanitizer.rb +22 -0
- data/lib/rookout/services/position.rb +92 -75
- data/lib/rookout/services/tracer.rb +30 -16
- data/lib/rookout/start.rb +12 -0
- data/lib/rookout/trigger_services.rb +2 -2
- data/lib/rookout/user_warnings.rb +2 -0
- data/lib/rookout/utils.rb +34 -0
- data/lib/rookout/version.rb +1 -2
- data/lib/rookout.rb +4 -0
- metadata +77 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8fa5b3d059bebfddb806d412ee19edc5680ace455a7e69d947533d91fb68a74
|
4
|
+
data.tar.gz: eac042dc2b354ce73a66220b6ae7623be14824e540fc306b6b84a2fc9c5b304d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28c4a962c4478dfeda21ad68e3eceb88f1bb0596a6eb885d741ab483b7ca00e34ee4827d84095b60827c46b8bd2f0adab662fc718cd0ed32fe3ac1feb6a511f1
|
7
|
+
data.tar.gz: 6f56418601b7e1fc343f6699fa9fd605860751cacec89368382c1e38fa5ab265af9a9c5ff7e7947bce8d65151365dbee01e2dfb4f4960458243345bd30aabccd
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Rookout
|
2
|
+
class ForkManager
|
3
|
+
require "singleton"
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@active = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def activate!
|
11
|
+
@active = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def disable!
|
15
|
+
@active = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def active?
|
19
|
+
@active
|
20
|
+
end
|
21
|
+
|
22
|
+
def fork_hook original_fork
|
23
|
+
if block_given?
|
24
|
+
original_fork.call do
|
25
|
+
post_fork_child if active?
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
else
|
29
|
+
res = original_fork.call
|
30
|
+
post_fork_child if active? && !res
|
31
|
+
res
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def post_fork_child
|
36
|
+
require_relative "rookout_singleton"
|
37
|
+
require_relative "interface"
|
38
|
+
|
39
|
+
RookoutSingleton.instance.post_fork_clean
|
40
|
+
Interface.instance.stop
|
41
|
+
Interface.instance.start post_fork: true
|
42
|
+
|
43
|
+
# Disable fork handler in child process
|
44
|
+
disable!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
alias _rookout_original_fork fork
|
50
|
+
|
51
|
+
def self.fork &block
|
52
|
+
Rookout::ForkManager.instance.fork_hook method(:_rookout_original_fork), &block
|
53
|
+
end
|
54
|
+
|
55
|
+
def fork &block
|
56
|
+
Rookout::ForkManager.instance.fork_hook method(:_rookout_original_fork), &block
|
57
|
+
end
|
58
|
+
|
59
|
+
module Kernel
|
60
|
+
alias _rookout_original_fork fork
|
61
|
+
|
62
|
+
def self.fork &block
|
63
|
+
Rookout::ForkManager.instance.fork_hook method(:_rookout_original_fork), &block
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module Process
|
68
|
+
alias _rookout_original_fork fork
|
69
|
+
|
70
|
+
def self.fork &block
|
71
|
+
Rookout::ForkManager.instance.fork_hook method(:_rookout_original_fork), &block
|
72
|
+
end
|
73
|
+
end
|
@@ -5,6 +5,7 @@ module Rookout
|
|
5
5
|
module Actions
|
6
6
|
class ActionRunProcessor < Action
|
7
7
|
def initialize arguments, processor_factory
|
8
|
+
super()
|
8
9
|
@processor = processor_factory.create_processor arguments["operations"]
|
9
10
|
|
10
11
|
post_operations = arguments["post_operations"]
|
@@ -15,12 +16,12 @@ module Rookout
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
|
-
def execute aug_id, report_id, namespace,
|
19
|
+
def execute aug_id, report_id, namespace, output
|
19
20
|
@processor.process namespace
|
20
|
-
|
21
|
+
output.send_user_message aug_id, report_id, namespace.read_attribute("store")
|
21
22
|
return unless @post_processor
|
22
23
|
|
23
|
-
|
24
|
+
output.flush_message
|
24
25
|
@post_processor.process namespace
|
25
26
|
end
|
26
27
|
end
|
data/lib/rookout/augs/aug.rb
CHANGED
@@ -1,121 +1,63 @@
|
|
1
|
-
require_relative "../logger"
|
2
|
-
require_relative "../user_warnings"
|
3
|
-
require_relative "../processor/rook_error"
|
4
|
-
|
5
1
|
module Rookout
|
6
2
|
module Augs
|
7
|
-
|
8
|
-
require "concurrent-ruby/concurrent/atom"
|
3
|
+
require_relative "../utils"
|
9
4
|
|
10
5
|
require_relative "../processor/namespaces/frame_namespace"
|
11
6
|
require_relative "../processor/namespaces/stack_namespace"
|
12
7
|
require_relative "../processor/namespaces/container_namespace"
|
13
8
|
require_relative "../processor/namespaces/ruby_utils_namespace"
|
14
9
|
require_relative "../processor/namespaces/noop_namespace"
|
15
|
-
|
16
10
|
require_relative "../logger"
|
17
11
|
|
18
|
-
MAX_LOG_CACHE_SIZE = 10
|
19
|
-
|
20
12
|
class Aug
|
21
|
-
def initialize aug_id,
|
22
|
-
# NOTE: max_aux_time is not implemented
|
23
|
-
|
13
|
+
def initialize aug_id, action, condition, limits_manager, _max_aug_time
|
24
14
|
@id = aug_id
|
25
|
-
@location = location
|
26
15
|
@action = action
|
27
16
|
@condition = condition
|
28
|
-
@
|
29
|
-
@output = output
|
17
|
+
@limits_manager = limits_manager
|
30
18
|
|
19
|
+
@executed = false
|
31
20
|
@enabled = true
|
32
21
|
@status = nil
|
33
22
|
@log_cache = []
|
34
23
|
end
|
35
|
-
end
|
36
|
-
|
37
|
-
attr_reader :id
|
38
24
|
|
39
|
-
|
40
|
-
@location.add_aug trigger_services, self
|
41
|
-
rescue SystemExit
|
42
|
-
raise
|
43
|
-
rescue Exception => e
|
44
|
-
message = "Exception when adding aug"
|
45
|
-
Logger.instance.error message, e
|
46
|
-
notify_error RookError.new e, message
|
47
|
-
end
|
25
|
+
attr_reader :id
|
48
26
|
|
49
|
-
|
50
|
-
|
27
|
+
def execute frame_binding, stack_trace, extracted, output
|
28
|
+
return unless @enabled
|
51
29
|
|
52
|
-
|
53
|
-
|
54
|
-
|
30
|
+
if output.user_messages_queue_full?
|
31
|
+
output.send_output_queue_full_warning @id
|
32
|
+
return
|
33
|
+
end
|
55
34
|
|
56
|
-
|
35
|
+
namespace = create_namespaces frame_binding, stack_trace, extracted
|
36
|
+
return if @condition && !@condition.evaluate(namespace)
|
57
37
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
rescue Exception => e
|
65
|
-
message = "Exception while processing Aug"
|
66
|
-
error = RookError.new e, message
|
67
|
-
notify_warning error unless silence_log? error
|
38
|
+
should_skip_limiters = @condition.nil? && !@executed
|
39
|
+
@limits_manager.with_limit should_skip_limiters do
|
40
|
+
@executed = true
|
41
|
+
report_id = Utils.uuid
|
42
|
+
Logger.instance.info "Executing aug-\t#{id} (msg ID #{report_id})"
|
43
|
+
@action.execute @id, report_id, namespace, output
|
68
44
|
end
|
69
45
|
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def notify_active
|
73
|
-
send_rule_status :Active
|
74
|
-
end
|
75
|
-
|
76
|
-
def notify_pending
|
77
|
-
send_rule_status :Pending
|
78
|
-
end
|
79
|
-
|
80
|
-
def notify_removed
|
81
|
-
send_rule_status :Deleted
|
82
|
-
end
|
83
|
-
|
84
|
-
def notify_error error
|
85
|
-
send_rule_status :Error, error
|
86
|
-
end
|
87
|
-
|
88
|
-
def notify_warning error
|
89
|
-
return if silence_log? error
|
90
|
-
send_rule_status :Warning, error
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def create_namespaces frame, extracted
|
96
|
-
ContainerNamespace.new("frame": Processor::Namespaces::FrameNamespace.new(frame[1]),
|
97
|
-
"stack": Processor::Namespaces::StackNamespace.new(frame, 1),
|
98
|
-
"extracted": Processor::Namespaces::ContainerNamespace.new(extracted),
|
99
|
-
"store": Processor::Namespaces::ContainerNamespace.new,
|
100
|
-
"temp": Processor::Namespaces::ContainerNamespace.new,
|
101
|
-
"utils": Processor::Namespaces::RubyUtisNamespace.new,
|
102
|
-
"trace": Processor::Namespaces::NoopNamespace.new)
|
103
|
-
end
|
104
|
-
|
105
|
-
def silence_log? error
|
106
|
-
return true if @log_cache.length >= MAX_LOG_CACHE_SIZE || @log_cache.include(error.message)
|
107
|
-
|
108
|
-
@log_cache << error.message
|
109
|
-
false
|
110
|
-
end
|
111
46
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def create_namespaces frame_binding, stack_trace, extracted
|
50
|
+
Processor::Namespaces::ContainerNamespace.new(
|
51
|
+
"frame" => Processor::Namespaces::FrameNamespace.new(frame_binding, stack_trace[0]),
|
52
|
+
"stack" => Processor::Namespaces::StackNamespace.new(stack_trace),
|
53
|
+
"extracted" => Processor::Namespaces::ContainerNamespace.new(extracted),
|
54
|
+
"store" => Processor::Namespaces::ContainerNamespace.new,
|
55
|
+
"temp" => Processor::Namespaces::ContainerNamespace.new,
|
56
|
+
"utils" => Processor::Namespaces::RubyUtilsNamespace.new,
|
57
|
+
"trace" => Processor::Namespaces::NoopNamespace.new,
|
58
|
+
"state" => Processor::Namespaces::NoopNamespace.new
|
59
|
+
)
|
60
|
+
end
|
119
61
|
end
|
120
62
|
end
|
121
63
|
end
|
@@ -6,7 +6,13 @@ module Rookout
|
|
6
6
|
|
7
7
|
require_relative "actions/action_run_processor"
|
8
8
|
require_relative "conditions/condition"
|
9
|
+
require_relative "locations/location_file_line"
|
10
|
+
require_relative "locations/location_exception_handler"
|
9
11
|
require_relative "aug_rate_limiter"
|
12
|
+
require_relative "aug"
|
13
|
+
require_relative "limits_manager"
|
14
|
+
require_relative "../utils"
|
15
|
+
require_relative "../logger"
|
10
16
|
|
11
17
|
class AugFactory
|
12
18
|
def initialize output
|
@@ -16,53 +22,114 @@ module Rookout
|
|
16
22
|
|
17
23
|
def create_aug configuration
|
18
24
|
aug_id = configuration["id"]
|
19
|
-
raise Exceptions.
|
20
|
-
|
21
|
-
location_configuration = configuration["location"]
|
22
|
-
raise Exceptions.RookAugInvalidKey "location", configuration unless location_configuration.is_a? Hash
|
23
|
-
location = create_location location_configuration
|
25
|
+
raise Exceptions::RookAugInvalidKey.new("id", configuration) unless aug_id.is_a? String
|
24
26
|
|
25
27
|
action_configuration = configuration["action"]
|
26
|
-
raise Exceptions.
|
27
|
-
action = Actions.
|
28
|
+
raise Exceptions::RookAugInvalidKey.new("action", configuration) unless action_configuration.is_a? Hash
|
29
|
+
action = Actions::ActionRunProcessor.new action_configuration, @factory
|
28
30
|
|
29
|
-
max_aug_time = configuration["maxAugTime"] || Config.
|
31
|
+
max_aug_time = configuration["maxAugTime"] || Config.instrumentation_max_aug_time
|
30
32
|
|
31
33
|
condition_configuration = configuration["conditional"]
|
32
|
-
|
33
|
-
|
34
|
+
unless condition_configuration.nil? || condition_configuration.is_a?(String)
|
35
|
+
raise Exceptions::RookAugInvalidKey.new("conditional", configuration)
|
36
|
+
end
|
37
|
+
condition = condition_configuration.nil? ? nil : Conditions::Condition.new(condition_configuration)
|
34
38
|
|
35
|
-
|
39
|
+
limits_manager = create_limits_manager configuration
|
36
40
|
|
37
|
-
|
41
|
+
max_aug_time_ns = Utils.milliseconds_to_nanoseconds max_aug_time
|
42
|
+
aug = Aug.new aug_id, action, condition, limits_manager, max_aug_time_ns
|
43
|
+
|
44
|
+
location_configuration = configuration["location"]
|
45
|
+
raise Exceptions::RookAugInvalidKey.new("location", configuration) unless location_configuration.is_a? Hash
|
46
|
+
create_location location_configuration, aug
|
38
47
|
end
|
39
48
|
|
40
49
|
private
|
41
50
|
|
42
|
-
def create_location configuration
|
51
|
+
def create_location configuration, aug
|
43
52
|
name = configuration["name"]
|
44
|
-
raise Exceptions
|
45
|
-
|
53
|
+
raise Exceptions::RookObjectNameMissing, configuration if name.nil?
|
54
|
+
|
55
|
+
case name
|
56
|
+
when "file_line"
|
57
|
+
Locations::LocationFileLine.new configuration, @output, aug
|
58
|
+
when "exception_handler"
|
59
|
+
Locations::LocationExceptionHandler.new configuration, @output, aug
|
60
|
+
when "log_handler"
|
61
|
+
raise Exceptions::RookUnsupportedLiveLogger
|
62
|
+
else
|
63
|
+
raise Exceptions::RookUnsupportedLocation, configuration if name != "file_line"
|
64
|
+
end
|
65
|
+
end
|
46
66
|
|
47
|
-
|
67
|
+
def create_limits_manager configuration
|
68
|
+
limiters = []
|
69
|
+
if global_rate_limiter.nil?
|
70
|
+
rate_limit = parse_rate_limit configuration["rateLimit"], configuration["rateLimitModifier"], 200, 5000
|
71
|
+
unless rate_limit.nil?
|
72
|
+
limiters.append AugRateLimiter.new(*rate_limit)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
limiters.append global_rate_limiter
|
76
|
+
end
|
77
|
+
|
78
|
+
LimitsManager.new limiters
|
48
79
|
end
|
49
80
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
81
|
+
def global_rate_limiter
|
82
|
+
if @global_rate_limiter.nil? && Rookout::Config.global_rate_limit != ""
|
83
|
+
begin
|
84
|
+
rate_limit = parse_rate_limit Rookout::Config.global_rate_limit,
|
85
|
+
"0", 0, 0
|
86
|
+
if rate_limit.nil?
|
87
|
+
raise Exceptions::RookInvalidRateLimitConfiguration, Rookout::Config.global_rate_limit
|
88
|
+
end
|
89
|
+
rescue Exceptions::RookInvalidRateLimitConfiguration => e
|
90
|
+
Logger.instance.warning "Failed to create global rate limiter: #{e.message}"
|
91
|
+
err = Processor::RookError.new e
|
92
|
+
UserWarnings.notify_error err
|
93
|
+
return nil
|
94
|
+
end
|
53
95
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
96
|
+
@global_rate_limiter = AugRateLimiter.new(*rate_limit)
|
97
|
+
Logger.instance.debug "Using global rate limiter with configuration: #{rate_limit}"
|
98
|
+
Rookout::Config.using_global_rate_limiter = true
|
99
|
+
end
|
100
|
+
|
101
|
+
@global_rate_limiter
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_rate_limit config, modifier_config, default_quota, default_window
|
105
|
+
window_quota = default_quota
|
106
|
+
window_size = default_window
|
107
|
+
|
108
|
+
unless config.nil? || config.empty?
|
109
|
+
rate_limit_split = config.split "/"
|
110
|
+
unless rate_limit_split.length == 2 && \
|
111
|
+
Utils.is_number?(rate_limit_split[0]) && \
|
112
|
+
Utils.is_number?(rate_limit_split[1])
|
113
|
+
raise Exceptions::RookInvalidRateLimitConfiguration, config
|
60
114
|
end
|
115
|
+
|
116
|
+
window_quota = rate_limit_split[0].to_i
|
117
|
+
window_size = rate_limit_split[1].to_i
|
61
118
|
end
|
62
119
|
|
63
|
-
|
120
|
+
window_quota_ns = Utils.milliseconds_to_nanoseconds window_quota
|
121
|
+
window_size_ns = Utils.milliseconds_to_nanoseconds window_size
|
122
|
+
rate_limit_modifier = modifier_config.to_i || 5
|
123
|
+
|
124
|
+
if window_quota_ns == 0
|
125
|
+
return nil
|
126
|
+
end
|
127
|
+
|
128
|
+
if window_quota_ns >= window_size_ns
|
129
|
+
raise Exceptions::RookInvalidRateLimitConfiguration, config
|
130
|
+
end
|
64
131
|
|
65
|
-
|
132
|
+
[window_quota_ns, window_size_ns, rate_limit_modifier]
|
66
133
|
end
|
67
134
|
end
|
68
135
|
end
|
@@ -1,61 +1,72 @@
|
|
1
1
|
module Rookout
|
2
2
|
module Augs
|
3
3
|
require_relative "../exceptions"
|
4
|
+
require_relative "../utils"
|
4
5
|
|
5
6
|
class AugRateLimiter
|
6
7
|
def initialize quota, window_size, active_limit
|
7
8
|
@quota = quota
|
9
|
+
@has_quota = !@quota.nil? && (@quota > 0)
|
8
10
|
@window_size = window_size
|
9
|
-
|
11
|
+
if active_limit > 0
|
12
|
+
@active_weight = quota / active_limit
|
13
|
+
else
|
14
|
+
@active_weight = 0
|
15
|
+
end
|
10
16
|
|
11
17
|
@mutex = Mutex.new
|
12
18
|
@active_count = 0
|
13
19
|
@windows = {}
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
active = true
|
36
|
-
|
37
|
-
# If exceeding quota
|
38
|
-
if current_usage(now_ms, current_window_key, prev_window_key) > @quota
|
39
|
-
warning = RookError.new Exceptions::RookRuleRateLimited.new
|
40
|
-
UserWarnings.notify_warning warning
|
41
|
-
return
|
42
|
-
end
|
22
|
+
def before_run start_time
|
23
|
+
# If no quota, we can safely exit
|
24
|
+
unless @has_quota
|
25
|
+
return true
|
26
|
+
end
|
27
|
+
now_ns = Utils.time_to_nanoseconds start_time
|
28
|
+
current_window_key, prev_window_key = timestamp_to_window_keys now_ns
|
29
|
+
|
30
|
+
@mutex.synchronize do
|
31
|
+
# Clean old windows
|
32
|
+
cleanup now_ns
|
33
|
+
usage = current_usage now_ns, current_window_key, prev_window_key
|
34
|
+
@active_count += 1
|
35
|
+
|
36
|
+
# If exceeding quota
|
37
|
+
if usage > @quota
|
38
|
+
warning = Processor::RookError.new Exceptions::RookRuleRateLimited.create
|
39
|
+
UserWarnings.notify_warning warning
|
40
|
+
return false
|
43
41
|
end
|
42
|
+
|
43
|
+
return true
|
44
44
|
end
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
def after_run start_time
|
48
|
+
if @has_quota
|
49
|
+
now_ns = Utils.time_to_nanoseconds start_time
|
50
|
+
current_window_key, = timestamp_to_window_keys now_ns
|
51
|
+
time_used = Utils.time_to_nanoseconds(Time.now) - now_ns
|
52
|
+
time_recorded = time_used > Config.min_rate_limit_value_ns ? time_used : Config.min_rate_limit_value_ns
|
53
|
+
@mutex.synchronize { record_usage current_window_key, time_recorded }
|
50
54
|
end
|
51
|
-
ensure
|
52
55
|
# Reduce active count
|
53
|
-
@mutex.synchronize { @active_count -= 1 }
|
56
|
+
@mutex.synchronize { @active_count -= 1 }
|
54
57
|
end
|
55
58
|
|
56
59
|
private
|
57
60
|
|
58
|
-
|
61
|
+
attr_reader :windows # will be used only in tests using <OBJ>.send(:windows)
|
62
|
+
|
63
|
+
def timestamp_to_window_keys now_ns
|
64
|
+
current_window_key = (now_ns / @window_size) * @window_size
|
65
|
+
prev_window_key = current_window_key - @window_size
|
66
|
+
[current_window_key, prev_window_key]
|
67
|
+
end
|
68
|
+
|
69
|
+
def current_usage now_ns, current_window_key, prev_window_key
|
59
70
|
# Get usage information
|
60
71
|
current_window_usage = @windows[current_window_key]
|
61
72
|
if current_window_usage.nil?
|
@@ -65,7 +76,7 @@ module Rookout
|
|
65
76
|
prev_window_usage = @windows[prev_window_key] || 0
|
66
77
|
|
67
78
|
# Previous window weight
|
68
|
-
prev_weight = 1 - (
|
79
|
+
prev_weight = 1 - ((now_ns - current_window_key) / @window_size.to_f)
|
69
80
|
|
70
81
|
# Final weighted usage
|
71
82
|
(prev_window_usage * prev_weight) + (@active_count * @active_weight) + current_window_usage
|
@@ -77,19 +88,11 @@ module Rookout
|
|
77
88
|
return if prev_value.nil?
|
78
89
|
|
79
90
|
# Add value to quota
|
80
|
-
@windows[current_window_key] +=
|
91
|
+
@windows[current_window_key] += [duration, 5].max.to_f
|
81
92
|
end
|
82
93
|
|
83
|
-
def cleanup
|
84
|
-
|
85
|
-
return if @mutex.locked?
|
86
|
-
|
87
|
-
@mutex.synchronize do
|
88
|
-
# every 5 windows-times, clear windows older than 10 window-times
|
89
|
-
if @windows.length > 10
|
90
|
-
@windows.reject! { |key, _| key < (now_ms - @window_size * 5) }
|
91
|
-
end
|
92
|
-
end
|
94
|
+
def cleanup now_ns
|
95
|
+
@windows.reject! { |key, _| key < (now_ns - (@window_size * 5)) } if @windows.length > 10
|
93
96
|
end
|
94
97
|
end
|
95
98
|
end
|
@@ -2,6 +2,8 @@ module Rookout
|
|
2
2
|
module Augs
|
3
3
|
require_relative "../logger"
|
4
4
|
|
5
|
+
require_relative "../processor/rook_error"
|
6
|
+
|
5
7
|
require_relative "aug_factory"
|
6
8
|
|
7
9
|
class AugsManager
|
@@ -43,7 +45,7 @@ module Rookout
|
|
43
45
|
return
|
44
46
|
end
|
45
47
|
|
46
|
-
error = RookError.new e, message
|
48
|
+
error = Rookout::Processor::RookError.new e, message
|
47
49
|
@output.send_rule_status aug_id, "Error", error
|
48
50
|
return
|
49
51
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
module Rookout
|
2
2
|
module Augs
|
3
3
|
module Conditions
|
4
|
+
require_relative "../../processor/paths/arithmetic_path"
|
5
|
+
|
4
6
|
class Condition
|
5
7
|
def initialize condition
|
6
|
-
@path = ArithmeticPath.new condition
|
8
|
+
@path = Processor::Paths::ArithmeticPath.new condition
|
7
9
|
end
|
8
10
|
|
9
11
|
def evaluate namespace
|
10
|
-
@path.read_from(namespace).
|
12
|
+
@path.read_from(namespace).obj == true
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Rookout
|
2
|
+
module Augs
|
3
|
+
class LimitsManager
|
4
|
+
def initialize limiters
|
5
|
+
@limiters = limiters
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_limit skip_limiters, start_time = nil
|
9
|
+
start_time ||= Time.now
|
10
|
+
can_execute = true
|
11
|
+
after_execute = []
|
12
|
+
|
13
|
+
@limiters.each do |limiter|
|
14
|
+
limiter_passed = limiter.before_run start_time
|
15
|
+
if limiter_passed || skip_limiters
|
16
|
+
after_execute.append -> { limiter.after_run start_time }
|
17
|
+
else
|
18
|
+
can_execute = false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if can_execute
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
unless after_execute.nil?
|
27
|
+
after_execute.each(&:call)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|