rookout 0.1.0

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +12 -0
  3. data/bin/rookout +30 -0
  4. data/lib/rookout.rb +18 -0
  5. data/lib/rookout/augs/actions/action.rb +11 -0
  6. data/lib/rookout/augs/actions/action_run_processor.rb +29 -0
  7. data/lib/rookout/augs/aug.rb +121 -0
  8. data/lib/rookout/augs/aug_factory.rb +69 -0
  9. data/lib/rookout/augs/aug_rate_limiter.rb +96 -0
  10. data/lib/rookout/augs/augs_manager.rb +77 -0
  11. data/lib/rookout/augs/conditions/condition.rb +15 -0
  12. data/lib/rookout/augs/locations/location.rb +11 -0
  13. data/lib/rookout/augs/locations/location_file_line.rb +26 -0
  14. data/lib/rookout/com_ws/agent_com_ws.rb +221 -0
  15. data/lib/rookout/com_ws/backoff.rb +35 -0
  16. data/lib/rookout/com_ws/command_handler.rb +22 -0
  17. data/lib/rookout/com_ws/git.rb +53 -0
  18. data/lib/rookout/com_ws/information.rb +85 -0
  19. data/lib/rookout/com_ws/output.rb +135 -0
  20. data/lib/rookout/com_ws/token_bucket.rb +36 -0
  21. data/lib/rookout/config.rb +55 -0
  22. data/lib/rookout/exceptions.rb +140 -0
  23. data/lib/rookout/interface.rb +140 -0
  24. data/lib/rookout/logger.rb +158 -0
  25. data/lib/rookout/processor/namespace_serializer.rb +26 -0
  26. data/lib/rookout/processor/namespaces/container_namespace.rb +45 -0
  27. data/lib/rookout/processor/namespaces/frame_namespace.rb +65 -0
  28. data/lib/rookout/processor/namespaces/namespace.rb +28 -0
  29. data/lib/rookout/processor/namespaces/noop_namespace.rb +32 -0
  30. data/lib/rookout/processor/namespaces/ruby_object_namespace.rb +97 -0
  31. data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +208 -0
  32. data/lib/rookout/processor/namespaces/ruby_utils_namespace.rb +65 -0
  33. data/lib/rookout/processor/namespaces/stack_namespace.rb +30 -0
  34. data/lib/rookout/processor/namespaces/traceback_namespace.rb +40 -0
  35. data/lib/rookout/processor/operations/operation.rb +11 -0
  36. data/lib/rookout/processor/operations/set_operation.rb +48 -0
  37. data/lib/rookout/processor/paths/arithmetic_path.rb +84 -0
  38. data/lib/rookout/processor/paths/canopy/actions.rb +184 -0
  39. data/lib/rookout/processor/paths/canopy/consts.rb +82 -0
  40. data/lib/rookout/processor/paths/canopy/maps.rb +2837 -0
  41. data/lib/rookout/processor/paths/canopy/markers.rb +186 -0
  42. data/lib/rookout/processor/paths/path.rb +15 -0
  43. data/lib/rookout/processor/processor.rb +34 -0
  44. data/lib/rookout/processor/processor_factory.rb +23 -0
  45. data/lib/rookout/processor/rook_error.rb +45 -0
  46. data/lib/rookout/protobuf/.gitignore +0 -0
  47. data/lib/rookout/protobuf/agent_info_pb.rb +68 -0
  48. data/lib/rookout/protobuf/controller_info_pb.rb +29 -0
  49. data/lib/rookout/protobuf/envelope_pb.rb +21 -0
  50. data/lib/rookout/protobuf/messages_pb.rb +189 -0
  51. data/lib/rookout/protobuf/variant_pb.rb +139 -0
  52. data/lib/rookout/rookout_singleton.rb +73 -0
  53. data/lib/rookout/services/position.rb +163 -0
  54. data/lib/rookout/services/tracer.rb +83 -0
  55. data/lib/rookout/trigger_services.rb +34 -0
  56. data/lib/rookout/user_warnings.rb +25 -0
  57. data/lib/rookout/version.rb +4 -0
  58. metadata +269 -0
@@ -0,0 +1,139 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: variant.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'google/protobuf/timestamp_pb'
7
+ Google::Protobuf::DescriptorPool.generated_pool.build do
8
+ add_file("variant.proto", :syntax => :proto3) do
9
+ add_message "com.rookout.Error" do
10
+ optional :message, :string, 1
11
+ optional :type, :string, 2
12
+ optional :parameters, :message, 3, "com.rookout.Variant"
13
+ optional :exc, :message, 4, "com.rookout.Variant"
14
+ optional :traceback, :message, 5, "com.rookout.Variant"
15
+ end
16
+ add_message "com.rookout.Variant" do
17
+ optional :variant_type, :enum, 1, "com.rookout.Variant.Type"
18
+ optional :original_type, :string, 2
19
+ repeated :attributes, :message, 3, "com.rookout.Variant.NamedValue"
20
+ optional :max_depth, :bool, 4
21
+ oneof :value do
22
+ optional :int_value, :int32, 11
23
+ optional :long_value, :int64, 12
24
+ optional :double_value, :double, 13
25
+ optional :binary_value, :message, 14, "com.rookout.Variant.Binary"
26
+ optional :string_value, :message, 15, "com.rookout.Variant.String"
27
+ optional :list_value, :message, 16, "com.rookout.Variant.List"
28
+ optional :map_value, :message, 17, "com.rookout.Variant.Map"
29
+ optional :namespace_value, :message, 19, "com.rookout.Variant.Namespace"
30
+ optional :error_value, :message, 20, "com.rookout.Error"
31
+ optional :message_value, :message, 23, "com.rookout.Variant.FormattedMessage"
32
+ optional :time_value, :message, 24, "google.protobuf.Timestamp"
33
+ optional :code_value, :message, 26, "com.rookout.Variant.CodeObject"
34
+ optional :large_int_value, :message, 27, "com.rookout.Variant.LargeInt"
35
+ optional :complex_value, :message, 28, "com.rookout.Variant.Complex"
36
+ optional :enum_value, :message, 31, "com.rookout.Variant.Enumeration"
37
+ optional :traceback, :message, 32, "com.rookout.Variant.Traceback"
38
+ end
39
+ end
40
+ add_message "com.rookout.Variant.NamedValue" do
41
+ optional :name, :string, 1
42
+ optional :value, :message, 2, "com.rookout.Variant"
43
+ end
44
+ add_message "com.rookout.Variant.Binary" do
45
+ optional :original_size, :int32, 1
46
+ optional :value, :bytes, 2
47
+ end
48
+ add_message "com.rookout.Variant.String" do
49
+ optional :original_size, :int32, 1
50
+ optional :value, :string, 2
51
+ end
52
+ add_message "com.rookout.Variant.List" do
53
+ optional :type, :string, 1
54
+ optional :original_size, :int32, 2
55
+ repeated :values, :message, 3, "com.rookout.Variant"
56
+ end
57
+ add_message "com.rookout.Variant.Pair" do
58
+ optional :first, :message, 1, "com.rookout.Variant"
59
+ optional :second, :message, 2, "com.rookout.Variant"
60
+ end
61
+ add_message "com.rookout.Variant.Map" do
62
+ optional :original_size, :int32, 1
63
+ repeated :pairs, :message, 2, "com.rookout.Variant.Pair"
64
+ end
65
+ add_message "com.rookout.Variant.Namespace" do
66
+ repeated :attributes, :message, 1, "com.rookout.Variant.NamedValue"
67
+ end
68
+ add_message "com.rookout.Variant.FormattedMessage" do
69
+ optional :message, :string, 1
70
+ end
71
+ add_message "com.rookout.Variant.CodeObject" do
72
+ optional :name, :string, 1
73
+ optional :module, :string, 2
74
+ optional :filename, :string, 3
75
+ optional :lineno, :uint32, 4
76
+ end
77
+ add_message "com.rookout.Variant.LargeInt" do
78
+ optional :value, :string, 1
79
+ end
80
+ add_message "com.rookout.Variant.Complex" do
81
+ optional :real, :double, 1
82
+ optional :imaginary, :double, 2
83
+ end
84
+ add_message "com.rookout.Variant.Enumeration" do
85
+ optional :string_value, :string, 1
86
+ optional :ordinal_value, :int32, 2
87
+ optional :type_name, :string, 3
88
+ end
89
+ add_message "com.rookout.Variant.Traceback" do
90
+ repeated :locations, :message, 1, "com.rookout.Variant.CodeObject"
91
+ end
92
+ add_enum "com.rookout.Variant.Type" do
93
+ value :VARIANT_NONE, 0
94
+ value :VARIANT_INT, 1
95
+ value :VARIANT_LONG, 2
96
+ value :VARIANT_DOUBLE, 3
97
+ value :VARIANT_BINARY, 4
98
+ value :VARIANT_STRING, 5
99
+ value :VARIANT_LIST, 6
100
+ value :VARIANT_MAP, 7
101
+ value :VARIANT_OBJECT, 8
102
+ value :VARIANT_NAMESPACE, 9
103
+ value :VARIANT_ERROR, 10
104
+ value :VARIANT_NOT_SUPPORTED, 11
105
+ value :VARIANT_MAX_DEPTH, 12
106
+ value :VARIANT_FORMATTED_MESSAGE, 13
107
+ value :VARIANT_TIME, 14
108
+ value :VARIANT_UKNOWN_OBJECT, 15
109
+ value :VARIANT_CODE_OBJECT, 16
110
+ value :VARIANT_LARGE_INT, 17
111
+ value :VARIANT_COMPLEX, 18
112
+ value :VARIANT_UNDEFINED, 19
113
+ value :VARIANT_DYNAMIC, 20
114
+ value :VARIANT_ENUM, 21
115
+ value :VARIANT_TRACEBACK, 22
116
+ end
117
+ end
118
+ end
119
+
120
+ module Com
121
+ module Rookout
122
+ Error = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Error").msgclass
123
+ Variant = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant").msgclass
124
+ Variant::NamedValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.NamedValue").msgclass
125
+ Variant::Binary = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Binary").msgclass
126
+ Variant::String = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.String").msgclass
127
+ Variant::List = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.List").msgclass
128
+ Variant::Pair = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Pair").msgclass
129
+ Variant::Map = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Map").msgclass
130
+ Variant::Namespace = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Namespace").msgclass
131
+ Variant::FormattedMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.FormattedMessage").msgclass
132
+ Variant::CodeObject = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.CodeObject").msgclass
133
+ Variant::LargeInt = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.LargeInt").msgclass
134
+ Variant::Complex = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Complex").msgclass
135
+ Variant::Enumeration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Enumeration").msgclass
136
+ Variant::Traceback = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Traceback").msgclass
137
+ Variant::Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Type").enummodule
138
+ end
139
+ end
@@ -0,0 +1,73 @@
1
+ module Rookout
2
+ require_relative "logger"
3
+ require_relative "trigger_services"
4
+ require_relative "exceptions"
5
+
6
+ require_relative "augs/augs_manager"
7
+
8
+ require_relative "com_ws/agent_com_ws"
9
+ require_relative "com_ws/output"
10
+ require_relative "com_ws/command_handler"
11
+
12
+ class RookoutSingleton
13
+ require "singleton"
14
+ include Singleton
15
+
16
+ def initialize
17
+ check_version_supported
18
+
19
+ @output = ComWs::Output.new
20
+
21
+ @services_started = false
22
+ @services = TriggerServices.new
23
+
24
+ @aug_manager = Augs::AugsManager.new @services, @output
25
+
26
+ @agent_com = nil
27
+ end
28
+
29
+ def start_trigger_services
30
+ return if @services_started
31
+
32
+ @services.start
33
+ @services_started = true
34
+ end
35
+
36
+ def stop_trigger_services
37
+ return unless @services_started
38
+
39
+ @services.close
40
+ @services_started = false
41
+ end
42
+
43
+ def connect token, host, port, proxy, labels, async_start, _fork
44
+ raise Exceptions::RookInterfaceException, "Multiple connection attempts not supported!" unless @agent_com.nil?
45
+
46
+ start_trigger_services
47
+
48
+ Logger.instance.debug "Initiating AgentCom-\t#{host}:#{port}"
49
+
50
+ @agent_com = ComWs::AgentComWs.new @output, host, port, proxy, token, labels
51
+ @command_handler = ComWs::CommandHandler.new @agent_com, @aug_manager
52
+
53
+ @agent_com.connect
54
+ return if async_start
55
+
56
+ @agent_com.wait_for_ready
57
+ end
58
+
59
+ def flush
60
+ @output.flush_messages if !@output.nil && !@agent_com.nil?
61
+ end
62
+
63
+ attr_reader :services
64
+
65
+ private
66
+
67
+ def check_version_supported
68
+ raise Exceptions:: RookVersionNotSupported, "platform", RUBY_ENGINE unless RUBY_ENGINE == "ruby"
69
+ raise Exceptions::RookVersionNotSupported, "version", RUBY_VERSION unless
70
+ RUBY_VERSION.start_with?("2.7") || RUBY_VERSION.start_with?("2.6")
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,163 @@
1
+ module Rookout
2
+ module Services
3
+ require_relative "../logger"
4
+ require_relative "../exceptions"
5
+
6
+ class PositionMarker
7
+ def initialize lineno, method
8
+ @lineno = lineno
9
+ @method = method
10
+ end
11
+
12
+ attr_reader :lineno, :method
13
+ end
14
+
15
+ class PositionResolver
16
+ def initialize tracer
17
+ @tracer = tracer
18
+ @augs = {}
19
+ @trace_point = TracePoint.new :script_compiled do |tp|
20
+ begin
21
+ begin
22
+ evaluate_script tp.instruction_sequence
23
+ rescue Exception => e
24
+ Logger.instance.exception "Exception while evaluating script", e
25
+ end
26
+ rescue
27
+ end
28
+ end
29
+
30
+ @trace_point.enable
31
+ end
32
+
33
+ def add_aug location, aug
34
+ positions = resolve_positions location, aug
35
+ if positions.empty?
36
+ @augs[aug.id] = [location, aug]
37
+ else
38
+ @tracer.add_breakpoint_aug positions, aug
39
+ end
40
+ end
41
+
42
+ def remove_aug aug_id
43
+ pair = @augs[aug_id]
44
+ return if pair.nil?
45
+
46
+ @augs.delete [aug_id]
47
+ aug = pair[1]
48
+ aug.notify_removed
49
+ end
50
+
51
+ def clear_augs
52
+ @augs.values.each do |aug_id|
53
+ remove_aug aug_id
54
+ end
55
+
56
+ @augs = {}
57
+ end
58
+
59
+ def close
60
+ clear_augs
61
+ @trace_point.disable
62
+ end
63
+
64
+ private
65
+
66
+ #########################################################################################
67
+ # Dynamic Loading Section
68
+ def evaluate_script iseq
69
+ filename = iseq.absolute_path
70
+ return if filename.nil?
71
+
72
+ @augs.each do |pair|
73
+ location = pair[0]
74
+
75
+ if exact_match? location, filename
76
+ # TODO: CHECK FILE AND LINE HASH COMPARED TO AUG
77
+ position = PositionMarker.new iseq.absolute_path, location.lineno, iseq
78
+ @tracer.add_breakpoint_aug [position], pair[1]
79
+ elsif suggested_match? location, filename
80
+ warning = Exceptions::RookSourceFilePathSuggestion.new location.filename, filename
81
+ pair[1].notify_warning warning
82
+ end
83
+ end
84
+ end
85
+
86
+ #########################################################################################
87
+ # Enumerating Section
88
+ def resolve_positions location, aug
89
+ # TODO: ADD HASHES AND SUGGESTIONS TO THIS FLOW
90
+ positions = []
91
+
92
+ ObjectSpace.each_object Module do |mod|
93
+ positions += scan_module_or_class mod, location, aug
94
+ end
95
+
96
+ ObjectSpace.each_object Class do |klass|
97
+ positions += scan_module_or_class klass, location, aug
98
+ end
99
+
100
+ positions
101
+ end
102
+
103
+ def scan_module_or_class mod, location, aug
104
+ positions = []
105
+
106
+ mod.instance_methods(false).each do |method_name|
107
+ method = mod.instance_method method_name
108
+ next unless method_match? method, location, aug
109
+
110
+ position = PositionMarker.new location.lineno, method
111
+ positions.push position
112
+ end
113
+
114
+ mod.private_instance_methods(false).each do |method_name|
115
+ method = mod.instance_method method_name
116
+ next unless method_match? method, location, aug
117
+
118
+ position = PositionMarker.new location.lineno, method
119
+ positions.push position
120
+ end
121
+
122
+ positions
123
+ end
124
+
125
+ def method_match? method, location, aug
126
+ return false unless method.source_location
127
+ filename = method.source_location[0]
128
+
129
+ if exact_match? location, filename
130
+ disasm_header = "== disasm: #<ISeq:#{method.name}@#{location.filename}:"
131
+ line_in_disasm = "(#{location.lineno.to_s.rjust 4})"
132
+ text = RubyVM::InstructionSequence.disasm method
133
+ return false if text.nil?
134
+
135
+ text.start_with?(disasm_header) && text.include?(line_in_disasm)
136
+ else
137
+ if suggested_match? location, filename
138
+ warning = Exceptions::RookSourceFilePathSuggestion.new location.filename, filename
139
+ aug.notify_warning warning
140
+ end
141
+ false
142
+ end
143
+ end
144
+
145
+ #########################################################################################
146
+ # Utils
147
+ def exact_match? location, filename
148
+ filename.end_with? location.filename
149
+ end
150
+
151
+ def suggested_match? location, filename
152
+ return unless File.basename(location.filename) == File.basename(filename)
153
+ location.file_hash == get_hash(filename)
154
+ end
155
+
156
+ def get_hash filename
157
+ content = File.read filename
158
+ content.gsub!(/(?:\r\n|\r|\n)/, "\n")
159
+ Digest::SHA2.new(256).hexdigest content
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,83 @@
1
+ module Rookout
2
+ module Services
3
+ require "binding_of_caller"
4
+ include BindingOfCaller::BindingExtensions
5
+
6
+ class Tracer
7
+ def initialize
8
+ @trace_points = {}
9
+ @augs = {}
10
+ end
11
+
12
+ def add_breakpoint_aug positions, aug
13
+ return if @augs.include? aug.id
14
+
15
+ aug_trace_points = []
16
+ positions.each do |position|
17
+ trace_point = create_trace_point aug
18
+
19
+ begin
20
+ trace_point.enable target: position.method, target_line: position.lineno
21
+ rescue ArgumentError => e
22
+ raise Exceptions::RookSetTracepointFailed, position.lineno, e
23
+ end
24
+
25
+ # We add and remove a dummy trace point to re-align the tracing mechanism as a result of some bug in adding
26
+ # a breakpoint
27
+ dummy_trace_point = TracePoint.new(:line) {}
28
+ dummy_trace_point.enable target: position.method, target_line: position.lineno
29
+ dummy_trace_point.disable
30
+
31
+ aug_trace_points.push trace_point
32
+ end
33
+
34
+ @trace_points[aug.id] = aug_trace_points
35
+ @augs[aug.id] = aug
36
+ aug.notify_active
37
+ end
38
+
39
+ def remove_aug aug_id
40
+ aug = @augs[aug_id]
41
+ return if aug.nil?
42
+
43
+ aug_trace_points = @trace_points[aug_id]
44
+ unless aug_trace_points.nil?
45
+ aug_trace_points.each(&:disable)
46
+ end
47
+
48
+ @augs.delete aug_id
49
+ @trace_points.delete aug_id
50
+ aug.notify_removed
51
+ end
52
+
53
+ def clear_augs
54
+ @augs.values.each do |aug_id|
55
+ remove_aug aug_id
56
+ end
57
+
58
+ @trace_points = {}
59
+ @augs = {}
60
+ end
61
+
62
+ def close
63
+ clear_augs
64
+ end
65
+
66
+ private
67
+
68
+ def create_trace_point aug
69
+ TracePoint.new :line do
70
+ begin
71
+ begin
72
+ aug.execute BindingOfCaller::BindingExtensions.callers, nil
73
+ rescue Exception => e
74
+ Logger.instance.exception "Exception while evaluating script", e
75
+ end
76
+ rescue
77
+ # Don't leak any exception from here
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end