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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rookout/atfork.rb +73 -0
  3. data/lib/rookout/augs/actions/action_run_processor.rb +4 -3
  4. data/lib/rookout/augs/aug.rb +33 -91
  5. data/lib/rookout/augs/aug_factory.rb +94 -27
  6. data/lib/rookout/augs/aug_rate_limiter.rb +50 -47
  7. data/lib/rookout/augs/augs_manager.rb +3 -1
  8. data/lib/rookout/augs/conditions/condition.rb +4 -2
  9. data/lib/rookout/augs/limits_manager.rb +32 -0
  10. data/lib/rookout/augs/locations/location.rb +75 -1
  11. data/lib/rookout/augs/locations/location_exception_handler.rb +22 -0
  12. data/lib/rookout/augs/locations/location_file_line.rb +21 -5
  13. data/lib/rookout/com_ws/agent_com_ws.rb +97 -58
  14. data/lib/rookout/com_ws/backoff.rb +5 -10
  15. data/lib/rookout/com_ws/command_handler.rb +1 -1
  16. data/lib/rookout/com_ws/envelope_wrapper.rb +68 -0
  17. data/lib/rookout/com_ws/git.rb +1 -1
  18. data/lib/rookout/com_ws/information.rb +95 -4
  19. data/lib/rookout/com_ws/output.rb +69 -21
  20. data/lib/rookout/com_ws/pinger.rb +41 -0
  21. data/lib/rookout/com_ws/websocket_client.rb +173 -0
  22. data/lib/rookout/commit.rb +3 -0
  23. data/lib/rookout/config.rb +94 -18
  24. data/lib/rookout/exceptions.rb +147 -12
  25. data/lib/rookout/interface.rb +95 -32
  26. data/lib/rookout/logger.rb +39 -10
  27. data/lib/rookout/processor/namespace_serializer.rb +2 -2
  28. data/lib/rookout/processor/namespace_serializer2.rb +331 -0
  29. data/lib/rookout/processor/namespaces/container_namespace.rb +5 -0
  30. data/lib/rookout/processor/namespaces/frame_namespace.rb +20 -17
  31. data/lib/rookout/processor/namespaces/namespace.rb +3 -2
  32. data/lib/rookout/processor/namespaces/noop_namespace.rb +4 -8
  33. data/lib/rookout/processor/namespaces/ruby_object_namespace.rb +39 -22
  34. data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +15 -12
  35. data/lib/rookout/processor/namespaces/ruby_utils_namespace.rb +0 -4
  36. data/lib/rookout/processor/namespaces/stack_namespace.rb +6 -4
  37. data/lib/rookout/processor/namespaces/traceback_namespace.rb +13 -9
  38. data/lib/rookout/processor/operations/set_operation.rb +6 -1
  39. data/lib/rookout/processor/paths/arithmetic_path.rb +5 -3
  40. data/lib/rookout/processor/paths/canopy/actions.rb +5 -1
  41. data/lib/rookout/processor/paths/canopy/consts.rb +6 -4
  42. data/lib/rookout/processor/paths/canopy/maps.rb +286 -286
  43. data/lib/rookout/processor/paths/canopy/markers.rb +35 -4
  44. data/lib/rookout/processor/processor_factory.rb +0 -2
  45. data/lib/rookout/processor/rook_error.rb +6 -1
  46. data/lib/rookout/protobuf/controller_info_pb.rb +1 -0
  47. data/lib/rookout/protobuf/messages_pb.rb +54 -0
  48. data/lib/rookout/protobuf/variant2_pb.rb +42 -0
  49. data/lib/rookout/protobuf/variant_pb.rb +22 -0
  50. data/lib/rookout/rookout_singleton.rb +23 -5
  51. data/lib/rookout/sanitizer.rb +22 -0
  52. data/lib/rookout/services/position.rb +92 -75
  53. data/lib/rookout/services/tracer.rb +30 -16
  54. data/lib/rookout/start.rb +12 -0
  55. data/lib/rookout/trigger_services.rb +2 -2
  56. data/lib/rookout/user_warnings.rb +2 -0
  57. data/lib/rookout/utils.rb +34 -0
  58. data/lib/rookout/version.rb +1 -2
  59. data/lib/rookout.rb +4 -0
  60. metadata +77 -51
@@ -4,7 +4,14 @@ module Rookout
4
4
  module Canopy
5
5
  require_relative "consts"
6
6
 
7
- class Marker; end
7
+ require_relative "../../../exceptions"
8
+ require_relative "../../namespaces/container_namespace"
9
+
10
+ # rubocop:disable Lint/EmptyClass
11
+ class Marker
12
+ # Empty base class
13
+ end
14
+ # rubocop:enable Lint/EmptyClass
8
15
 
9
16
  class Operation < Marker
10
17
  def read _namespace, _create
@@ -12,12 +19,13 @@ module Rookout
12
19
  end
13
20
 
14
21
  def write _namespace, _value
15
- raise Exception.RookOperationReadOnly, self.class.to_s
22
+ raise Exception::RookOperationReadOnly, self.class.to_s
16
23
  end
17
24
  end
18
25
 
19
26
  class FunctionOperation < Operation
20
27
  def initialize name, args
28
+ super()
21
29
  @name = name
22
30
  @args = args
23
31
  end
@@ -29,6 +37,7 @@ module Rookout
29
37
 
30
38
  class AttributeOperation < Operation
31
39
  def initialize name
40
+ super()
32
41
  @name = name
33
42
  end
34
43
 
@@ -36,7 +45,7 @@ module Rookout
36
45
  namespace.read_attribute @name
37
46
  rescue Exceptions::RookAttributeNotFound
38
47
  raise unless create
39
- namespace.write_attribute name, ContainerNamespace.new
48
+ namespace.write_attribute @name, Namespaces::ContainerNamespace.new
40
49
  end
41
50
 
42
51
  def write namespace, value
@@ -46,6 +55,7 @@ module Rookout
46
55
 
47
56
  class LookupOperation < Operation
48
57
  def initialize text
58
+ super()
49
59
  if (text.start_with?("'") && text.end_with?("'")) || (text.start_with?("\"") && text.end_with?("\""))
50
60
  @key = text[1...-1]
51
61
  else
@@ -60,11 +70,13 @@ module Rookout
60
70
 
61
71
  class ObjectMarker < Marker
62
72
  def initialize text, obj
73
+ super()
63
74
  @text = text
64
75
  @obj = obj
65
76
  end
66
77
 
67
- attr_reader :text, :obj
78
+ attr_reader :text
79
+ attr_reader :obj
68
80
 
69
81
  def to_s
70
82
  @obj.to_s
@@ -133,6 +145,8 @@ module Rookout
133
145
 
134
146
  class Opt < Marker
135
147
  def initialize opt
148
+ super()
149
+
136
150
  @opt = opt
137
151
  @level = nil
138
152
 
@@ -151,6 +165,21 @@ module Rookout
151
165
 
152
166
  attr_reader :level
153
167
 
168
+ def check_result result, first_obj, second_obj
169
+ return unless [true, false].include? result
170
+ if result
171
+ return
172
+ end
173
+
174
+ if !first_obj.nil? && !(PRIMITIVES.include? first_obj.class)
175
+ raise Exceptions::RookNonPrimitiveObjectType, first_obj.class.to_s
176
+ end
177
+
178
+ return if second_obj.nil?
179
+ raise Exceptions::RookNonPrimitiveObjectType, second_obj.class.to_s unless
180
+ PRIMITIVES.include? second_obj.class
181
+ end
182
+
154
183
  def execute_operation first, second
155
184
  # Remove wrapping of objects as needed
156
185
  first_obj = decapsulate_item first
@@ -163,6 +192,8 @@ module Rookout
163
192
  raise Exceptions::RookExceptionEvaluationFailed.new "", e
164
193
  end
165
194
 
195
+ check_result result, first_obj, second_obj
196
+
166
197
  # If we don't have a result
167
198
  if result.nil?
168
199
  # Verify objects are primitives
@@ -5,8 +5,6 @@ module Rookout
5
5
  require_relative "paths/arithmetic_path"
6
6
 
7
7
  class ProcessorFactory
8
- def initialize; end
9
-
10
8
  def create_operation configuration
11
9
  Operations::SetOperation.new configuration, self
12
10
  end
@@ -25,12 +25,17 @@ module Rookout
25
25
  end
26
26
 
27
27
  attr_reader :message
28
+ attr_reader :exception
29
+ attr_reader :parameters
28
30
 
29
31
  def dumps
30
32
  parameters = NamespaceSerializer.dump Namespaces::RubyObjectNamespace.new(@parameters), false
31
33
  exception = NamespaceSerializer.dump Namespaces::RubyObjectNamespace.new(@exception), false
32
34
 
33
- backtrace_string = @exception.backtrace.join "\n\t"
35
+ backtrace_string = ""
36
+ unless @exception.backtrace.nil?
37
+ backtrace_string = @exception.backtrace.join "\n\t"
38
+ end
34
39
  backtrace_object = Namespaces::RubyObjectNamespace.new(backtrace_string).tailor_limits!
35
40
  traceback = NamespaceSerializer.dump backtrace_object, false
36
41
 
@@ -18,6 +18,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
18
18
  optional :platform_release, :string, 10
19
19
  optional :platform_version, :string, 11
20
20
  optional :platform_string, :string, 12
21
+ optional :parent_controller_id, :string, 13
21
22
  end
22
23
  end
23
24
  end
@@ -4,6 +4,7 @@
4
4
  require 'google/protobuf'
5
5
 
6
6
  require_relative 'variant_pb'
7
+ require_relative 'variant2_pb'
7
8
  require_relative 'agent_info_pb'
8
9
  require_relative 'controller_info_pb'
9
10
  require 'google/protobuf/any_pb'
@@ -87,6 +88,11 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
87
88
  optional :aug_id, :string, 2
88
89
  optional :arguments, :message, 3, "com.rookout.Variant"
89
90
  optional :report_id, :string, 4
91
+ map :strings_cache, :string, :uint32, 5
92
+ repeated :buffer_cache_buffers, :bytes, 6
93
+ repeated :buffer_cache_indexes, :uint32, 7
94
+ optional :arguments2, :message, 8, "com.rookout.Variant2"
95
+ optional :reverse_list_order, :bool, 9
90
96
  end
91
97
  add_message "com.rookout.UserMsg" do
92
98
  optional :aug_report, :message, 1, "com.rookout.AugReportMessage"
@@ -98,6 +104,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
98
104
  end
99
105
  add_message "com.rookout.InitialAugsCommand" do
100
106
  repeated :augs, :string, 1
107
+ map :sdk_configuration, :string, :string, 2
101
108
  end
102
109
  add_message "com.rookout.RemoveAugCommand" do
103
110
  optional :aug_id, :string, 1
@@ -117,6 +124,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
117
124
  repeated :connectedAgents, :string, 2
118
125
  end
119
126
  add_message "com.rookout.DataOnPremTokenRequest" do
127
+ optional :access_type, :enum, 1, "com.rookout.DataOnPremTokenAccessType"
120
128
  end
121
129
  add_message "com.rookout.DataOnPremTokenResponse" do
122
130
  optional :token, :bytes, 1
@@ -150,6 +158,44 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
150
158
  optional :message, :message, 2, "google.protobuf.Any"
151
159
  optional :error, :string, 3
152
160
  end
161
+ add_message "com.rookout.StartDatastoreConnectivityTestCommand" do
162
+ optional :orgId, :string, 1
163
+ optional :controllerId, :string, 2
164
+ optional :datastoreUrl, :string, 3
165
+ optional :workspaceId, :string, 4
166
+ end
167
+ add_message "com.rookout.DatastoreConnectivityTestC2cResponse" do
168
+ optional :controllerId, :string, 1
169
+ optional :TestMessageId, :string, 2
170
+ optional :isSuccess, :bool, 3
171
+ optional :errorString, :string, 4
172
+ end
173
+ add_message "com.rookout.PingDatastoreCommand" do
174
+ optional :datastoreUrl, :string, 1
175
+ end
176
+ add_message "com.rookout.DatastoreInformation" do
177
+ optional :version, :string, 1
178
+ optional :hostname, :string, 2
179
+ optional :machine_type, :string, 3
180
+ optional :network, :string, 4
181
+ optional :ip, :string, 5
182
+ optional :os, :string, 6
183
+ optional :os_release, :string, 7
184
+ optional :os_version, :string, 8
185
+ optional :os_string, :string, 9
186
+ end
187
+ add_message "com.rookout.OrgLanguagesConfigsRequest" do
188
+ end
189
+ add_message "com.rookout.LanguageConfig" do
190
+ map :config, :string, :string, 1
191
+ end
192
+ add_message "com.rookout.OrgLanguagesConfigsResponse" do
193
+ map :OrgConfig, :string, :message, 1, "com.rookout.LanguageConfig"
194
+ end
195
+ add_enum "com.rookout.DataOnPremTokenAccessType" do
196
+ value :WRITE, 0
197
+ value :READ, 1
198
+ end
153
199
  end
154
200
  end
155
201
 
@@ -185,5 +231,13 @@ module Com
185
231
  HitCountUpdateMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.HitCountUpdateMessage").msgclass
186
232
  C2cRpcRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.C2cRpcRequest").msgclass
187
233
  C2cRpcResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.C2cRpcResponse").msgclass
234
+ StartDatastoreConnectivityTestCommand = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.StartDatastoreConnectivityTestCommand").msgclass
235
+ DatastoreConnectivityTestC2cResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.DatastoreConnectivityTestC2cResponse").msgclass
236
+ PingDatastoreCommand = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.PingDatastoreCommand").msgclass
237
+ DatastoreInformation = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.DatastoreInformation").msgclass
238
+ OrgLanguagesConfigsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.OrgLanguagesConfigsRequest").msgclass
239
+ LanguageConfig = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.LanguageConfig").msgclass
240
+ OrgLanguagesConfigsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.OrgLanguagesConfigsResponse").msgclass
241
+ DataOnPremTokenAccessType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.DataOnPremTokenAccessType").enummodule
188
242
  end
189
243
  end
@@ -0,0 +1,42 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: variant2.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ require 'google/protobuf/timestamp_pb'
7
+ require_relative 'variant_pb'
8
+ Google::Protobuf::DescriptorPool.generated_pool.build do
9
+ add_file("variant2.proto", :syntax => :proto3) do
10
+ add_message "com.rookout.Error2" do
11
+ optional :message, :string, 1
12
+ optional :type, :string, 2
13
+ optional :parameters, :message, 3, "com.rookout.Variant2"
14
+ optional :exc, :message, 4, "com.rookout.Variant2"
15
+ optional :traceback, :message, 5, "com.rookout.Variant2"
16
+ end
17
+ add_message "com.rookout.Variant2" do
18
+ optional :variant_type_max_depth, :uint32, 1
19
+ optional :original_type_index_in_cache, :uint32, 2
20
+ repeated :attribute_names_in_cache, :uint32, 3
21
+ repeated :attribute_values, :message, 4, "com.rookout.Variant2"
22
+ optional :original_size, :uint32, 5
23
+ optional :long_value, :int64, 6
24
+ optional :bytes_index_in_cache, :uint32, 7
25
+ repeated :collection_keys, :message, 8, "com.rookout.Variant2"
26
+ repeated :collection_values, :message, 9, "com.rookout.Variant2"
27
+ optional :double_value, :double, 10
28
+ repeated :code_values, :message, 11, "com.rookout.Variant.CodeObject"
29
+ optional :time_value, :message, 12, "google.protobuf.Timestamp"
30
+ optional :error_value, :message, 16, "com.rookout.Error2"
31
+ optional :complex_value, :message, 17, "com.rookout.Variant.Complex"
32
+ optional :livetail, :message, 18, "com.rookout.Variant.LiveTailMessage"
33
+ end
34
+ end
35
+ end
36
+
37
+ module Com
38
+ module Rookout
39
+ Error2 = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Error2").msgclass
40
+ Variant2 = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant2").msgclass
41
+ end
42
+ end
@@ -18,6 +18,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
18
18
  optional :original_type, :string, 2
19
19
  repeated :attributes, :message, 3, "com.rookout.Variant.NamedValue"
20
20
  optional :max_depth, :bool, 4
21
+ optional :original_type_index_in_cache, :uint32, 5
21
22
  oneof :value do
22
23
  optional :int_value, :int32, 11
23
24
  optional :long_value, :int64, 12
@@ -35,6 +36,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
35
36
  optional :complex_value, :message, 28, "com.rookout.Variant.Complex"
36
37
  optional :enum_value, :message, 31, "com.rookout.Variant.Enumeration"
37
38
  optional :traceback, :message, 32, "com.rookout.Variant.Traceback"
39
+ optional :livetail, :message, 33, "com.rookout.Variant.LiveTailMessage"
38
40
  end
39
41
  end
40
42
  add_message "com.rookout.Variant.NamedValue" do
@@ -48,6 +50,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
48
50
  add_message "com.rookout.Variant.String" do
49
51
  optional :original_size, :int32, 1
50
52
  optional :value, :string, 2
53
+ optional :value_index_in_cache, :uint32, 3
51
54
  end
52
55
  add_message "com.rookout.Variant.List" do
53
56
  optional :type, :string, 1
@@ -73,6 +76,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
73
76
  optional :module, :string, 2
74
77
  optional :filename, :string, 3
75
78
  optional :lineno, :uint32, 4
79
+ optional :name_index_in_cache, :uint32, 5
80
+ optional :module_index_in_cache, :uint32, 6
81
+ optional :filename_index_in_cache, :uint32, 7
76
82
  end
77
83
  add_message "com.rookout.Variant.LargeInt" do
78
84
  optional :value, :string, 1
@@ -89,6 +95,19 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
89
95
  add_message "com.rookout.Variant.Traceback" do
90
96
  repeated :locations, :message, 1, "com.rookout.Variant.CodeObject"
91
97
  end
98
+ add_message "com.rookout.Variant.LiveTailMessage" do
99
+ optional :level_name, :string, 1
100
+ optional :msg, :string, 2
101
+ optional :formatted_message, :string, 3
102
+ optional :time, :double, 4
103
+ optional :filename, :string, 5
104
+ optional :lineno, :int32, 6
105
+ optional :function, :string, 7
106
+ optional :module, :string, 8
107
+ optional :thread_id, :int64, 9
108
+ optional :thread_name, :string, 10
109
+ map :log_context, :string, :string, 11
110
+ end
92
111
  add_enum "com.rookout.Variant.Type" do
93
112
  value :VARIANT_NONE, 0
94
113
  value :VARIANT_INT, 1
@@ -113,6 +132,8 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
113
132
  value :VARIANT_DYNAMIC, 20
114
133
  value :VARIANT_ENUM, 21
115
134
  value :VARIANT_TRACEBACK, 22
135
+ value :VARIANT_LIVETAIL, 23
136
+ value :VARIANT_SET, 24
116
137
  end
117
138
  end
118
139
  end
@@ -134,6 +155,7 @@ module Com
134
155
  Variant::Complex = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Complex").msgclass
135
156
  Variant::Enumeration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Enumeration").msgclass
136
157
  Variant::Traceback = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Traceback").msgclass
158
+ Variant::LiveTailMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.LiveTailMessage").msgclass
137
159
  Variant::Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("com.rookout.Variant.Type").enummodule
138
160
  end
139
161
  end
@@ -40,14 +40,21 @@ module Rookout
40
40
  @services_started = false
41
41
  end
42
42
 
43
- def connect token, host, port, proxy, labels, async_start, _fork
43
+ def connect token: nil, host: nil, port: nil, proxy: nil, labels: {}, async_start: false, fork: false,
44
+ throw_errors: false
44
45
  raise Exceptions::RookInterfaceException, "Multiple connection attempts not supported!" unless @agent_com.nil?
45
46
 
47
+ if fork
48
+ require_relative "atfork"
49
+ Rookout::ForkManager.instance.activate!
50
+ end
51
+
46
52
  start_trigger_services
47
53
 
48
54
  Logger.instance.debug "Initiating AgentCom-\t#{host}:#{port}"
49
55
 
50
- @agent_com = ComWs::AgentComWs.new @output, host, port, proxy, token, labels
56
+ @agent_com = ComWs::AgentComWs.new @output, host, port, proxy, token, labels, !throw_errors
57
+ @output.agent_com = @agent_com
51
58
  @command_handler = ComWs::CommandHandler.new @agent_com, @aug_manager
52
59
 
53
60
  @agent_com.connect
@@ -60,14 +67,25 @@ module Rookout
60
67
  @output.flush_messages if !@output.nil && !@agent_com.nil?
61
68
  end
62
69
 
70
+ def post_fork_clean
71
+ @agent_com.stop
72
+ @agent_com = nil
73
+
74
+ @command_handler = nil
75
+
76
+ # We don't disable services because we will lose all loaded scripts
77
+ @services.clear_augs
78
+ end
79
+
63
80
  attr_reader :services
64
81
 
65
82
  private
66
83
 
67
84
  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")
85
+ raise Exceptions::RookVersionNotSupported.new("platform", RUBY_ENGINE) unless RUBY_ENGINE == "ruby"
86
+ raise Exceptions::RookVersionNotSupported.new("version", RUBY_VERSION) unless
87
+ RUBY_VERSION.start_with?("2.7") || RUBY_VERSION.start_with?("2.6") ||
88
+ RUBY_VERSION.start_with?("3.0") || RUBY_VERSION.start_with?("3.1") || RUBY_VERSION.start_with?("3.2")
71
89
  end
72
90
  end
73
91
  end
@@ -0,0 +1,22 @@
1
+ require "set"
2
+ module Rookout
3
+ class Sanitizer
4
+ @@blacklisted_properties = Set["labels", "ROOKOUT_LABELS"]
5
+
6
+ def self.sanitize_object! obj
7
+ obj.each_key do |key|
8
+ if obj[key].is_a?(String) && !@@blacklisted_properties.include?(key.to_s)
9
+ obj[key] = obj[key].strip
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.sanitize_properties!
15
+ ENV.each do |key, val|
16
+ if key.start_with?("ROOKOUT_") && !@@blacklisted_properties.include?(key.to_s)
17
+ ENV[key] = val.strip.delete_suffix("/")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,7 @@
1
1
  module Rookout
2
2
  module Services
3
+ require "zlib"
4
+
3
5
  require_relative "../logger"
4
6
  require_relative "../exceptions"
5
7
 
@@ -9,17 +11,25 @@ module Rookout
9
11
  @method = method
10
12
  end
11
13
 
12
- attr_reader :lineno, :method
14
+ attr_reader :lineno
15
+ attr_reader :method
13
16
  end
14
17
 
15
18
  class PositionResolver
16
19
  def initialize tracer
17
20
  @tracer = tracer
18
21
  @augs = {}
22
+ @augs_lock = Mutex.new
23
+ @iseqs = []
19
24
  @trace_point = TracePoint.new :script_compiled do |tp|
20
25
  begin
21
26
  begin
22
- evaluate_script tp.instruction_sequence
27
+ iseq = tp.instruction_sequence
28
+ # Ignore script without sources
29
+ if iseq.absolute_path
30
+ @iseqs << iseq
31
+ evaluate_script iseq
32
+ end
23
33
  rescue Exception => e
24
34
  Logger.instance.exception "Exception while evaluating script", e
25
35
  end
@@ -30,26 +40,22 @@ module Rookout
30
40
  @trace_point.enable
31
41
  end
32
42
 
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
43
+ def add_aug location
44
+ positions = evaluate_all_scripts_to_location location
45
+ @tracer.add_breakpoint_aug positions, location unless positions.empty?
46
+ @augs_lock.synchronize { @augs[location.id] = location }
40
47
  end
41
48
 
42
49
  def remove_aug aug_id
43
- pair = @augs[aug_id]
44
- return if pair.nil?
50
+ location = @augs[aug_id]
51
+ return if location.nil?
45
52
 
46
53
  @augs.delete [aug_id]
47
- aug = pair[1]
48
- aug.notify_removed
54
+ location.notify_removed
49
55
  end
50
56
 
51
57
  def clear_augs
52
- @augs.values.each do |aug_id|
58
+ @augs.each_value do |aug_id|
53
59
  remove_aug aug_id
54
60
  end
55
61
 
@@ -64,88 +70,52 @@ module Rookout
64
70
  private
65
71
 
66
72
  #########################################################################################
67
- # Dynamic Loading Section
73
+ # ISEQ comparison Section
68
74
  def evaluate_script iseq
69
75
  filename = iseq.absolute_path
70
76
  return if filename.nil?
71
77
 
72
- @augs.each do |pair|
73
- location = pair[0]
78
+ @augs_lock.synchronize do
79
+ @augs.each_value do |location|
80
+ position = evaluate_script_to_location iseq, filename, location
81
+ next if position.nil?
74
82
 
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
83
+ @tracer.add_breakpoint_aug [position], location
82
84
  end
83
85
  end
84
86
  end
85
87
 
86
- #########################################################################################
87
- # Enumerating Section
88
- def resolve_positions location, aug
89
- # TODO: ADD HASHES AND SUGGESTIONS TO THIS FLOW
88
+ def evaluate_all_scripts_to_location location
90
89
  positions = []
90
+ @iseqs.each do |iseq|
91
+ position = evaluate_script_to_location iseq, iseq.absolute_path, location
92
+ next if position.nil?
91
93
 
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
94
+ positions << position
98
95
  end
99
96
 
100
97
  positions
101
98
  end
102
99
 
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
100
+ def evaluate_script_to_location iseq, filename, location
101
+ if exact_match? location.filename, filename
102
+ lineno = find_updated_line filename, location
103
+ return if lineno == -1
104
+
105
+ PositionMarker.new lineno, iseq
106
+ elsif suggested_match? location, filename
107
+ warning = Exceptions::RookSourceFilePathSuggestion.new location.filename, filename
108
+ location.notify_warning Processor::RookError.new warning
109
+ # Must return nil in order to skip this script
110
+ nil
142
111
  end
143
112
  end
144
113
 
145
114
  #########################################################################################
146
115
  # Utils
147
- def exact_match? location, filename
148
- filename.end_with? location.filename
116
+ def exact_match? location_filename, script_filename
117
+ return unless script_filename.end_with? location_filename
118
+ File.basename(script_filename) == File.basename(location_filename)
149
119
  end
150
120
 
151
121
  def suggested_match? location, filename
@@ -158,6 +128,53 @@ module Rookout
158
128
  content.gsub!(/(?:\r\n|\r|\n)/, "\n")
159
129
  Digest::SHA2.new(256).hexdigest content
160
130
  end
131
+
132
+ def handle_unique_line lines, location, filename
133
+ first_line = nil
134
+ second_found = false
135
+
136
+ lines.each_with_index do |line, index|
137
+ if crc_line(line) == location.line_crc
138
+ if first_line.nil?
139
+ first_line = index
140
+ else
141
+ second_found = true
142
+ break
143
+ end
144
+ end
145
+ end
146
+
147
+ if first_line && !second_found
148
+ updated_line = first_line + 1
149
+ location.notify_warning Processor::RookError.new Exceptions::RookLineMoved.new(filename,
150
+ location.lineno,
151
+ updated_line)
152
+ return updated_line
153
+ end
154
+ nil
155
+ end
156
+
157
+ def find_updated_line filename, location
158
+ return location.lineno if location.line_crc.nil?
159
+
160
+ lines = File.readlines filename, chomp: true
161
+ line_crc32 = lines.length >= location.lineno ? crc_line(lines[location.lineno - 1]) : nil
162
+ return location.lineno if location.line_crc == line_crc32
163
+
164
+ if location.line_unique
165
+ updated_line = handle_unique_line lines, location, filename
166
+ unless updated_line.nil?
167
+ return updated_line
168
+ end
169
+ end
170
+
171
+ location.notify_error Exceptions::RookCrcMismatchException.new(filename, location.line_crc, line_crc32)
172
+ -1
173
+ end
174
+
175
+ def crc_line line
176
+ (Zlib.crc32(line) & 0xffffffff).to_s 16
177
+ end
161
178
  end
162
179
  end
163
180
  end