rookout 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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