rookout 0.1.28 → 0.1.50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rookout/augs/actions/action_run_processor.rb +1 -0
  3. data/lib/rookout/augs/aug.rb +7 -6
  4. data/lib/rookout/augs/aug_factory.rb +71 -19
  5. data/lib/rookout/augs/aug_rate_limiter.rb +35 -36
  6. data/lib/rookout/augs/limits_manager.rb +32 -0
  7. data/lib/rookout/augs/locations/location.rb +1 -1
  8. data/lib/rookout/augs/locations/location_file_line.rb +5 -1
  9. data/lib/rookout/com_ws/agent_com_ws.rb +24 -20
  10. data/lib/rookout/com_ws/command_handler.rb +1 -1
  11. data/lib/rookout/com_ws/envelope_wrapper.rb +68 -0
  12. data/lib/rookout/com_ws/git.rb +1 -1
  13. data/lib/rookout/com_ws/information.rb +45 -1
  14. data/lib/rookout/com_ws/output.rb +62 -12
  15. data/lib/rookout/commit.rb +1 -1
  16. data/lib/rookout/config.rb +86 -15
  17. data/lib/rookout/exceptions.rb +49 -10
  18. data/lib/rookout/interface.rb +10 -8
  19. data/lib/rookout/logger.rb +13 -7
  20. data/lib/rookout/processor/namespace_serializer.rb +1 -1
  21. data/lib/rookout/processor/namespace_serializer2.rb +331 -0
  22. data/lib/rookout/processor/namespaces/container_namespace.rb +5 -0
  23. data/lib/rookout/processor/namespaces/frame_namespace.rb +2 -3
  24. data/lib/rookout/processor/namespaces/namespace.rb +1 -0
  25. data/lib/rookout/processor/namespaces/noop_namespace.rb +0 -4
  26. data/lib/rookout/processor/namespaces/ruby_object_namespace.rb +37 -22
  27. data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +9 -7
  28. data/lib/rookout/processor/namespaces/ruby_utils_namespace.rb +0 -4
  29. data/lib/rookout/processor/namespaces/stack_namespace.rb +1 -0
  30. data/lib/rookout/processor/namespaces/traceback_namespace.rb +5 -0
  31. data/lib/rookout/processor/operations/set_operation.rb +2 -0
  32. data/lib/rookout/processor/paths/arithmetic_path.rb +4 -2
  33. data/lib/rookout/processor/paths/canopy/actions.rb +5 -1
  34. data/lib/rookout/processor/paths/canopy/consts.rb +6 -4
  35. data/lib/rookout/processor/paths/canopy/markers.rb +15 -5
  36. data/lib/rookout/processor/processor_factory.rb +0 -2
  37. data/lib/rookout/processor/rook_error.rb +3 -1
  38. data/lib/rookout/protobuf/controller_info_pb.rb +1 -0
  39. data/lib/rookout/protobuf/messages_pb.rb +54 -0
  40. data/lib/rookout/protobuf/variant2_pb.rb +42 -0
  41. data/lib/rookout/protobuf/variant_pb.rb +22 -0
  42. data/lib/rookout/rookout_singleton.rb +4 -3
  43. data/lib/rookout/sanitizer.rb +22 -0
  44. data/lib/rookout/services/position.rb +4 -3
  45. data/lib/rookout/services/tracer.rb +5 -2
  46. data/lib/rookout/utils.rb +28 -14
  47. data/lib/rookout/version.rb +1 -1
  48. data/lib/rookout.rb +4 -0
  49. metadata +46 -13
@@ -9,12 +9,17 @@ module Rookout
9
9
  require_relative "../processor/namespace_serializer"
10
10
 
11
11
  require_relative "token_bucket"
12
+ require_relative "envelope_wrapper"
13
+
14
+ require "concurrent"
12
15
 
13
16
  class Output
14
17
  def initialize
15
18
  @agent_id = nil
16
19
  @agent_com = nil
17
20
 
21
+ @skipped_aug_ids = Concurrent::Set.new
22
+
18
23
  @rule_status_update_bucket = TokenBucket.new Config.output_max_status_updates,
19
24
  Config.output_bucket_refresh_rate do
20
25
  Logger.instance.error "Limit reached, dropping status updates"
@@ -41,7 +46,8 @@ module Rookout
41
46
  @closing = false
42
47
  end
43
48
 
44
- attr_accessor :agent_id, :agent_com
49
+ attr_accessor :agent_id
50
+ attr_accessor :agent_com
45
51
 
46
52
  def close
47
53
  @closing = true
@@ -53,6 +59,17 @@ module Rookout
53
59
  @user_message_bucket.exhausted? || (!@agent_com.nil? && @agent_com.queue_full?)
54
60
  end
55
61
 
62
+ def send_output_queue_full_warning aug_id
63
+ if @skipped_aug_ids.include? aug_id
64
+ return
65
+ end
66
+
67
+ @skipped_aug_ids.add aug_id
68
+ error = Processor::RookError.new Exceptions::RookOutputQueueFull.new
69
+ send_rule_status aug_id, :Warning, error
70
+ Logger.instance.warning "Skipping aug-\t#{aug_id} execution because the queue is full"
71
+ end
72
+
56
73
  def send_warning rule_id, error
57
74
  send_rule_status rule_id, :Warning, error
58
75
  end
@@ -61,14 +78,25 @@ module Rookout
61
78
  return if @closing || !@agent_com
62
79
 
63
80
  @rule_status_update_bucket.if_available do
81
+ if active == "Deleted"
82
+ @skipped_aug_ids.delete? rule_id
83
+ end
84
+
64
85
  status = Com::Rookout::RuleStatusMessage.new agent_id: @agent_id,
65
86
  rule_id: rule_id,
66
87
  active: active
88
+
67
89
  if error
68
90
  status.error = error.dumps
69
91
  end
70
92
 
71
- @agent_com.add status
93
+ envelope_wrapper = EnvelopeWrapper.new status
94
+
95
+ begin
96
+ @agent_com.add envelope_wrapper
97
+ rescue Exceptions::RookOutputQueueFull
98
+ # Ignored
99
+ end
72
100
  end
73
101
  end
74
102
 
@@ -76,17 +104,31 @@ module Rookout
76
104
  return if @closing || !@agent_com
77
105
 
78
106
  @user_message_bucket.if_available do
79
- if arguments.nil? || arguments.call_method("size", "") == 0
80
- protobuf_arguments = nil
107
+ if Config.protobuf_version2
108
+ envelope_wrapper = Variant2EnvelopeWrapper.new @agent_id, aug_id, report_id, arguments
81
109
  else
82
- protobuf_arguments = Processor::NamespaceSerializer.dump arguments
110
+ if arguments.nil? || arguments.call_method("size", "") == 0
111
+ protobuf_arguments = nil
112
+ else
113
+ protobuf_arguments = Processor::NamespaceSerializer.dump arguments, true
114
+ end
115
+
116
+ envelope_wrapper = EnvelopeWrapper.new(
117
+ Com::Rookout::AugReportMessage.new(
118
+ agent_id: @agent_id,
119
+ aug_id: aug_id,
120
+ report_id: report_id,
121
+ arguments: protobuf_arguments
122
+ )
123
+ )
83
124
  end
84
125
 
85
- msg = Com::Rookout::AugReportMessage.new agent_id: @agent_id,
86
- aug_id: aug_id,
87
- report_id: report_id,
88
- arguments: protobuf_arguments
89
- @agent_com.add msg
126
+ begin
127
+ @agent_com.add envelope_wrapper
128
+ @skipped_aug_ids.delete? aug_id
129
+ rescue Exceptions::RookOutputQueueFull
130
+ send_output_queue_full_warning aug_id
131
+ end
90
132
  end
91
133
  end
92
134
 
@@ -114,7 +156,8 @@ module Rookout
114
156
  protobuf_arguments = nil
115
157
  else
116
158
  protobuf_arguments = Processor::NamespaceSerializer.dump(
117
- Processor::Namespaces::RubyObjectNamespace.new(arguments)
159
+ Processor::Namespaces::RubyObjectNamespace.new(arguments),
160
+ true
118
161
  )
119
162
  end
120
163
 
@@ -126,7 +169,14 @@ module Rookout
126
169
  text: text,
127
170
  formatted_message: formatted_message,
128
171
  legacy_arguments: protobuf_arguments
129
- @agent_com.add msg
172
+
173
+ envelope_wrapper = EnvelopeWrapper.new msg
174
+
175
+ begin
176
+ @agent_com.add envelope_wrapper
177
+ rescue Exceptions::RookOutputQueueFull
178
+ # Ignored
179
+ end
130
180
  end
131
181
  end
132
182
  end
@@ -1,3 +1,3 @@
1
1
  module Rookout
2
- COMMIT = "ad844d5f1e4bb119998eaedc927902a531b95b1f".freeze
2
+ COMMIT = "9f3ecb29fbadc0c8f66233c9c44be100a912e577".freeze
3
3
  end
@@ -6,51 +6,122 @@ module Rookout
6
6
  # Magic to allow for module variables to be easily accessible
7
7
  class << self
8
8
  attr_accessor :debug
9
+ attr_accessor :quiet
10
+
9
11
  Rookout::Config.debug = false
12
+ Rookout::Config.quiet = false
13
+
14
+ attr_accessor :logger_filename
15
+ attr_accessor :logger_log_to_stderr
16
+ attr_accessor :logger_log_level
10
17
 
11
- attr_accessor :logger_filename, :logger_log_to_stderr, :logger_log_level
12
18
  Rookout::Config.logger_filename = "rookout/ruby-rook.log".freeze
13
19
  Rookout::Config.logger_log_to_stderr = false
14
20
  Rookout::Config.logger_log_level = :info
15
21
 
16
- attr_accessor :agent_com_configuration_command_thread_name,
17
- :agent_com_max_message_limit,
18
- :agent_com_timeout,
19
- :agent_com_ping_interval,
20
- :agent_com_ping_timeout,
21
- :agent_com_flush_timeout,
22
- :agent_com_max_queued_messages
22
+ attr_accessor :agent_com_configuration_command_thread_name
23
+ attr_accessor :agent_com_max_message_limit
24
+ attr_accessor :agent_com_max_queue_messages_length
25
+ attr_accessor :agent_com_timeout
26
+ attr_accessor :agent_com_ping_interval
27
+ attr_accessor :agent_com_ping_timeout
28
+ attr_accessor :agent_com_flush_timeout
29
+ attr_accessor :agent_com_max_queued_messages
30
+
23
31
  Rookout::Config.agent_com_max_message_limit = 1024 * 1024
32
+ Rookout::Config.agent_com_max_queue_messages_length = 15 * 1024 * 1024
24
33
  Rookout::Config.agent_com_timeout = 3
25
34
  Rookout::Config.agent_com_ping_interval = 10
26
35
  Rookout::Config.agent_com_ping_timeout = 30
27
36
  Rookout::Config.agent_com_flush_timeout = 3
28
37
  Rookout::Config.agent_com_max_queued_messages = 100
29
38
 
30
- attr_accessor :backoff_factor, :backoff_reset_time, :backoff_max_time
39
+ attr_accessor :backoff_factor
40
+ attr_accessor :backoff_reset_time
41
+ attr_accessor :backoff_max_time
42
+
31
43
  Rookout::Config.backoff_factor = 0.2
32
44
  Rookout::Config.backoff_max_time = 60
33
45
  Rookout::Config.backoff_reset_time = 3 * 60.0
34
46
 
35
- attr_accessor :output_max_status_updates,
36
- :output_max_aug_messages,
37
- :output_max_log_items,
38
- :output_bucket_refresh_rate
47
+ attr_accessor :output_max_status_updates
48
+ attr_accessor :output_max_aug_messages
49
+ attr_accessor :output_max_log_items
50
+ attr_accessor :output_bucket_refresh_rate
51
+
39
52
  Rookout::Config.output_max_status_updates = 200
40
53
  Rookout::Config.output_max_aug_messages = 100
41
54
  Rookout::Config.output_max_log_items = 200
42
55
  Rookout::Config.output_bucket_refresh_rate = 10
43
56
 
44
57
  attr_accessor :instrumentation_max_aug_time
58
+
45
59
  Rookout::Config.instrumentation_max_aug_time = 400
46
60
 
47
- attr_accessor :user_git_commit, :user_git_origin
61
+ attr_accessor :user_git_commit
62
+ attr_accessor :user_git_origin
63
+
48
64
  Rookout::Config.user_git_commit = nil
49
65
  Rookout::Config.user_git_origin = nil
50
66
 
51
- attr_accessor :rookout_version, :rookout_commit
67
+ attr_accessor :rookout_version
68
+ attr_accessor :rookout_commit
69
+
52
70
  Rookout::Config.rookout_version = Rookout::VERSION
53
71
  Rookout::Config.rookout_commit = Rookout::COMMIT
72
+
73
+ attr_accessor :protobuf_version2
74
+
75
+ Rookout::Config.protobuf_version2 = false
76
+
77
+ attr_accessor :true_values
78
+
79
+ Rookout::Config.true_values = ["y", "Y", "yes", "Yes", "YES", "true", "True", "TRUE", "1"]
80
+
81
+ attr_accessor :global_rate_limit_quota
82
+ attr_accessor :global_rate_limit_window_size
83
+ attr_accessor :global_rate_limit
84
+ attr_accessor :using_global_rate_limiter
85
+
86
+ Rookout::Config.global_rate_limit_quota = ""
87
+ Rookout::Config.global_rate_limit_window_size = ""
88
+ Rookout::Config.global_rate_limit = ""
89
+ Rookout::Config.using_global_rate_limiter = false
90
+
91
+ def update_config configuration
92
+ update_var2_config configuration
93
+ update_global_rate_limit_config configuration
94
+ end
95
+
96
+ def update_var2_config configuration
97
+ is_config_proto2 = configuration["RUBY_PROTOBUF_VERSION_2"]
98
+ return if is_config_proto2.nil?
99
+ is_env_proto2 = ENV["ROOKOUT_Protobuf_Version2"]
100
+ if is_env_proto2.nil?
101
+ @protobuf_version2 = true if @true_values.include? is_config_proto2
102
+ elsif @true_values.include? is_env_proto2
103
+ Logger.instance.debug "ROOKOUT_Protobuf_Version2 env is preset: #{is_env_proto2}"
104
+ @protobuf_version2 = true
105
+ end
106
+ Logger.instance.info "Updating ROOKOUT_Protobuf_Version2 value to: #{@protobuf_version2}"
107
+ end
108
+
109
+ def update_global_rate_limit_config configuration
110
+ global_rate_limit = ENV["ROOKOUT_GLOBAL_RATE_LIMIT"]
111
+ if global_rate_limit.nil?
112
+ quota = configuration["RUBY_GLOBAL_RATE_LIMIT_QUOTA_MS"]
113
+ window_size = configuration["RUBY_GLOBAL_RATE_LIMIT_WINDOW_SIZE_MS"]
114
+
115
+ if quota != "" && !quota.nil? && window_size != "" && !window_size.nil?
116
+ global_rate_limit = "#{quota}/#{window_size}"
117
+ end
118
+ end
119
+
120
+ return if global_rate_limit.nil? || global_rate_limit == ""
121
+
122
+ @global_rate_limit = global_rate_limit
123
+ Logger.instance.info "Updating global rate limit to: #{global_rate_limit}"
124
+ end
54
125
  end
55
126
  end
56
127
  end
@@ -11,9 +11,6 @@ module Rookout
11
11
  end
12
12
 
13
13
  class RookInterfaceException < ToolException
14
- def initialize message
15
- super message
16
- end
17
14
  end
18
15
 
19
16
  class RookVersionNotSupported < ToolException
@@ -92,16 +89,39 @@ module Rookout
92
89
  class RookMessageSizeExceeded < ToolException
93
90
  def initialize message_size, max_message_size
94
91
  super "Message size of #{message_size} exceeds max size limit of #{max_message_size}. " \
95
- "Change the depth of collection or change the default by setting ROOKOUT_MAX_MESSAGE_SIZE " \
96
- "as environment variable or system property",
92
+ "Change the depth of collection or change the default by setting ROOKOUT_MAX_MESSAGE_SIZE " \
93
+ "as environment variable or system property",
97
94
  { "message_size" => message_size, "max_message_size" => max_message_size }
98
95
  end
99
96
  end
100
97
 
101
- class RookRuleRateLimited < ToolException
98
+ class RookOutputQueueFull < ToolException
99
+ def initialize
100
+ super "Breakpoint triggered but output queue is full. " \
101
+ "Data collection will be disabled until the queue has emptied."
102
+ end
103
+ end
104
+
105
+ class RookRuleAugRateLimited < ToolException
102
106
  def initialize
103
107
  super "Breakpoint was disabled due to rate-limiting. " \
104
- "For more information: https://docs.rookout.com/docs/breakpoints-tasks.html#rate-limiting"
108
+ "For more information: https://docs.rookout.com/docs/breakpoints-tasks.html#rate-limiting"
109
+ end
110
+ end
111
+
112
+ class RookRuleGlobalRateLimited < ToolException
113
+ def initialize
114
+ super "Breakpoint was disabled due to global rate-limiting. " \
115
+ "For more information: https://docs.rookout.com/docs/breakpoints-tasks.html#rate-limiting"
116
+ end
117
+ end
118
+
119
+ class RookRuleRateLimited
120
+ def self.create
121
+ if Rookout::Config.using_global_rate_limiter
122
+ return RookRuleGlobalRateLimited.new
123
+ end
124
+ RookRuleAugRateLimited.new
105
125
  end
106
126
  end
107
127
 
@@ -126,6 +146,13 @@ module Rookout
126
146
  end
127
147
  end
128
148
 
149
+ class RookInvalidPositionException < ToolException
150
+ def initialize filename, line
151
+ super "Invalid code position for TracePoint: #{filename}:#{line}",
152
+ { filename: filename, line: line }
153
+ end
154
+ end
155
+
129
156
  class RookObjectCannotBeSerialized < ToolException
130
157
  def initialize object, message
131
158
  super message, { "class" => object.class.to_s }
@@ -139,9 +166,6 @@ module Rookout
139
166
  end
140
167
 
141
168
  class RookInvalidOptions < ToolException
142
- def initialize description
143
- super description
144
- end
145
169
  end
146
170
 
147
171
  class RookInvalidLabel < ToolException
@@ -219,5 +243,20 @@ module Rookout
219
243
  }
220
244
  end
221
245
  end
246
+
247
+ class RookInvalidRateLimitConfiguration < ToolException
248
+ def initialize config
249
+ super "Invalid rate limit configuration: #{config}",
250
+ {
251
+ "config" => config
252
+ }
253
+ end
254
+ end
255
+
256
+ class RookUnsupportedLiveLogger < ToolException
257
+ def initialize
258
+ super "Live Logger is not supported. Try using Rookout Live Debugger instead."
259
+ end
260
+ end
222
261
  end
223
262
  end
@@ -4,6 +4,7 @@ module Rookout
4
4
  include Singleton
5
5
 
6
6
  require_relative "config"
7
+ require_relative "utils"
7
8
  require_relative "exceptions"
8
9
  include Exceptions
9
10
 
@@ -14,7 +15,7 @@ module Rookout
14
15
 
15
16
  def print_debug_messages
16
17
  puts "[Rookout] Running in debug mode"
17
- puts "[Rookout] Rookout SDK for ruby: " + Config.rookout_version
18
+ puts "[Rookout] Rookout SDK for ruby: #{Config.rookout_version}"
18
19
  end
19
20
 
20
21
  def start options = {}
@@ -36,16 +37,16 @@ module Rookout
36
37
  rook.connect(**@start_options)
37
38
  rescue LoadError
38
39
  raise if throw_errors
39
- STDERR.puts "[Rookout] Failed to load Rookout. Please make sure to force build native extensions by setting" \
40
- "'bundle config force_ruby_platform true'"
40
+ $stderr.puts "[Rookout] Failed to load Rookout. Please make sure to force build native extensions by setting" \
41
+ "'bundle config force_ruby_platform true'"
41
42
  rescue RookMissingToken, RookInvalidToken, RookInvalidOptions, RookVersionNotSupported, RookBadProtobuf => e
42
43
  raise if throw_errors
43
- STDERR.puts "[Rookout] Failed to start Rookout: #{e.message}"
44
+ $stderr.puts "[Rookout] Failed to start Rookout: #{e.message}"
44
45
  rescue RookCommunicationException => e
45
46
  raise if throw_errors
46
- STDERR.puts "[Rookout] " + e.message
47
+ Logger.instance.warning "[Rookout] #{e.message}"
47
48
  rescue Exception => e
48
- STDERR.puts e.full_message if Config.debug
49
+ $stderr.puts e.full_message if Config.debug
49
50
  raise if throw_errors
50
51
  end
51
52
  end
@@ -82,12 +83,13 @@ module Rookout
82
83
  # Only test alpine
83
84
  return unless File.exist? "/etc/alpine-release"
84
85
 
86
+ # Make sure protobuf is built from source
85
87
  protobuf = Gem::Specification.find_by_path "google/protobuf"
86
- STDERR.puts RookBadProtobuf.new.message if protobuf.nil?
88
+ $stderr.puts RookBadProtobuf.new.message if protobuf.nil?
87
89
  return unless protobuf.platform != "ruby"
88
90
 
89
91
  error = RookBadProtobufPlatform.new protobuf.platform
90
- STDERR.puts error.message
92
+ $stderr.puts error.message
91
93
  end
92
94
 
93
95
  def configure_globals options
@@ -66,7 +66,7 @@ module Rookout
66
66
 
67
67
  arguments.each do |argument|
68
68
  if argument.is_a? Exception
69
- @formatted_message += "\n" + argument.message + "\n" + argument.backtrace.join("\n\t")
69
+ @formatted_message += "\n#{argument.message}\n#{argument.backtrace.join "\n\t"}"
70
70
  end
71
71
  end
72
72
 
@@ -74,7 +74,13 @@ module Rookout
74
74
  set_caller
75
75
  end
76
76
 
77
- attr_reader :level, :time, :filename, :lineno, :message, :formatted_message, :arguments
77
+ attr_reader :level
78
+ attr_reader :time
79
+ attr_reader :filename
80
+ attr_reader :lineno
81
+ attr_reader :message
82
+ attr_reader :formatted_message
83
+ attr_reader :arguments
78
84
 
79
85
  def format
80
86
  "#{@time} #{Process.pid}:#{Thread.current.name}-" \
@@ -137,19 +143,19 @@ module Rookout
137
143
  file = nil
138
144
 
139
145
  if Config.debug
140
- STDERR.puts "[Rookout] Failed to open log file: #{log_file_path}"
141
- STDERR.puts e.backtrace
146
+ $stderr.puts "[Rookout] Failed to open log file: #{log_file_path}"
147
+ $stderr.puts e.backtrace
142
148
  end
143
149
  end
144
150
 
145
- ->(record) { file.write record.format + "\n" if file }
151
+ ->(record) { file.write "#{record.format}\n" if file }
146
152
  end
147
153
 
148
154
  def calculate_log_file_path
149
155
  return Config.logger_filename if absolute_path? Config.logger_filename
150
156
 
151
157
  if RUBY_PLATFORM.include? "darwin"
152
- File.join ENV["HOME"], Config.logger_filename
158
+ File.join Dir.home, Config.logger_filename
153
159
  elsif RUBY_PLATFORM.match?(/cygwin|mswin|mingw|bccwin|wince|emx/)
154
160
  File.join ENV["USERPROFILE"], Config.logger_filename
155
161
  else
@@ -158,7 +164,7 @@ module Rookout
158
164
  end
159
165
 
160
166
  def new_stderr_handler
161
- ->(record) { STDERR.puts record.format }
167
+ ->(record) { $stderr.puts record.format }
162
168
  end
163
169
 
164
170
  def new_remote_handler
@@ -7,7 +7,7 @@ module Rookout
7
7
 
8
8
  module_function
9
9
 
10
- def dump namespace, log_errors = true
10
+ def dump namespace, log_errors
11
11
  namespace.dump log_errors
12
12
  rescue StandardError => e
13
13
  message = "Failed to serialize namespace"