rookout 0.1.0 → 0.1.56
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/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
|