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
@@ -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
@@ -49,6 +55,21 @@ module Rookout
49
55
  Logger.instance.remove_output self
50
56
  end
51
57
 
58
+ def user_messages_queue_full?
59
+ @user_message_bucket.exhausted? || (!@agent_com.nil? && @agent_com.queue_full?)
60
+ end
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
+
52
73
  def send_warning rule_id, error
53
74
  send_rule_status rule_id, :Warning, error
54
75
  end
@@ -57,20 +78,25 @@ module Rookout
57
78
  return if @closing || !@agent_com
58
79
 
59
80
  @rule_status_update_bucket.if_available do
60
- protobuf_error = nil
61
- if error
62
- protobuf_error = Com::Rookout::Error.new message: error.messsage,
63
- type: error.type
64
- protobuf_error.parameters.copy_from error.parameters
65
- protobuf_error.exc.copy_from error.exc
66
- protobuf_error.traceback.copy_from error.traceback
81
+ if active == "Deleted"
82
+ @skipped_aug_ids.delete? rule_id
67
83
  end
68
84
 
69
85
  status = Com::Rookout::RuleStatusMessage.new agent_id: @agent_id,
70
86
  rule_id: rule_id,
71
- active: active,
72
- error: protobuf_error
73
- @agent_com.add status
87
+ active: active
88
+
89
+ if error
90
+ status.error = error.dumps
91
+ end
92
+
93
+ envelope_wrapper = EnvelopeWrapper.new status
94
+
95
+ begin
96
+ @agent_com.add envelope_wrapper
97
+ rescue Exceptions::RookOutputQueueFull
98
+ # Ignored
99
+ end
74
100
  end
75
101
  end
76
102
 
@@ -78,17 +104,31 @@ module Rookout
78
104
  return if @closing || !@agent_com
79
105
 
80
106
  @user_message_bucket.if_available do
81
- if arguments.nil? || arguments.call_method("size", "") == 0
82
- protobuf_arguments = nil
107
+ if Config.protobuf_version2
108
+ envelope_wrapper = Variant2EnvelopeWrapper.new @agent_id, aug_id, report_id, arguments
83
109
  else
84
- 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
+ )
85
124
  end
86
125
 
87
- msg = Com::Rookout::AugReportMessage.new agent_id: @agent_id,
88
- aug_id: aug_id,
89
- report_id: report_id,
90
- arguments: protobuf_arguments
91
- @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
92
132
  end
93
133
  end
94
134
 
@@ -116,7 +156,8 @@ module Rookout
116
156
  protobuf_arguments = nil
117
157
  else
118
158
  protobuf_arguments = Processor::NamespaceSerializer.dump(
119
- Processor::Namespaces::RubyObjectNamespace.new(arguments)
159
+ Processor::Namespaces::RubyObjectNamespace.new(arguments),
160
+ true
120
161
  )
121
162
  end
122
163
 
@@ -128,7 +169,14 @@ module Rookout
128
169
  text: text,
129
170
  formatted_message: formatted_message,
130
171
  legacy_arguments: protobuf_arguments
131
- @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
132
180
  end
133
181
  end
134
182
  end
@@ -0,0 +1,41 @@
1
+ module Rookout
2
+ module ComWs
3
+ require_relative "../logger"
4
+
5
+ class Pinger
6
+ def initialize connection, interval, timeout
7
+ @interval = interval
8
+ @timeout = timeout
9
+ @connection = connection
10
+
11
+ @last_pong = Time.now
12
+ @last_ping = Time.now
13
+ end
14
+
15
+ def repeat
16
+ loop do
17
+ if Time.now - @last_ping > @interval
18
+ Logger.instance.debug "Sending Ping"
19
+ @last_ping = Time.now
20
+ begin
21
+ @connection.ping Time.now.to_s do
22
+ Logger.instance.debug "Got Ping reply"
23
+ @last_pong = Time.now
24
+ end
25
+ rescue RuntimeError, Errno::EPIPE
26
+ Logger.instance.debug "Failed to send ping"
27
+ break
28
+ end
29
+ end
30
+
31
+ if Time.now - @last_pong > @timeout
32
+ Logger.instance.debug "Ping timeout"
33
+ break
34
+ end
35
+
36
+ yield
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,173 @@
1
+ module Rookout
2
+ module ComWs
3
+ require "openssl"
4
+ require "websocket/driver"
5
+ require "uri"
6
+
7
+ require_relative "../config"
8
+ require_relative "../exceptions"
9
+
10
+ class WebsocketClient
11
+ def initialize url, proxy, token
12
+ @token = token
13
+ @connection = WebsocketConnection.new url, proxy
14
+ @proxy = proxy
15
+ @driver = nil
16
+ end
17
+
18
+ def connect
19
+ connection_error = nil
20
+ @driver = WebSocket::Driver.client @connection
21
+
22
+ headers.each do |key, value|
23
+ @driver.set_header key, value
24
+ end
25
+
26
+ @driver.on :error do |error|
27
+ connection_error = error
28
+ end
29
+
30
+ # Connect to the remote server
31
+ # TODO: ADD CONNECT TIMEOUT
32
+ @connection.connect @driver
33
+ @driver.start
34
+
35
+ while @driver.state == :connecting
36
+ recv_data = @connection.read_char
37
+ @driver.parse recv_data
38
+ end
39
+
40
+ raise Exceptions::RookWebsocketException, connection_error if @driver.state != :open
41
+ end
42
+
43
+ def connection_pump message_handler
44
+ @driver.on :message do |e|
45
+ message_handler.call e.data
46
+ end
47
+
48
+ until @driver.state == :closed
49
+ recv_data = @connection.read_char
50
+ @driver.parse recv_data
51
+ end
52
+ end
53
+
54
+ def send_frame msg
55
+ @driver.binary msg
56
+ end
57
+
58
+ def ping message, &callback
59
+ @driver.ping message, &callback
60
+ end
61
+
62
+ def close
63
+ return if @driver.nil?
64
+
65
+ begin
66
+ @driver.close
67
+ rescue RuntimeError, Errno::EPIPE, OpenSSL::OpenSSLError
68
+ # Protocol close may fail if the connection is already closed
69
+ nil
70
+ end
71
+ @connection.close
72
+ end
73
+
74
+ private
75
+
76
+ def headers
77
+ result = {
78
+ "User-Agent" => "RookoutAgent/#{Config.rookout_version}+#{Config.rookout_commit}"
79
+ }
80
+
81
+ result["X-Rookout-Token"] = @token unless @token.nil?
82
+
83
+ result
84
+ end
85
+ end
86
+
87
+ class WebsocketConnection
88
+ def initialize url, proxy
89
+ @url = url
90
+ @proxy = proxy
91
+
92
+ @uri = URI.parse @url
93
+ @secure = %w[https wss].include? @uri.scheme
94
+
95
+ @socket = nil
96
+
97
+ @proxy_connected = false
98
+ end
99
+
100
+ def connect driver
101
+ @socket = tcp_connect
102
+
103
+ proxy_connect driver if @proxy
104
+
105
+ @socket = ssl_connect @socket if @secure
106
+ end
107
+
108
+ def proxy_connect driver
109
+ connection_error = nil
110
+ @proxy_connected = false
111
+ proxy = driver.proxy @proxy
112
+
113
+ proxy.on :connect do
114
+ @proxy_connected = true
115
+ end
116
+
117
+ proxy.on :error do |error|
118
+ connection_error = error
119
+ end
120
+
121
+ proxy.start
122
+
123
+ proxy.parse read_char until @proxy_connected == true || !connection_error.nil?
124
+
125
+ raise Exceptions::RookProxyException, connection_error unless connection_error.nil?
126
+ end
127
+
128
+ attr_reader :url
129
+
130
+ def read_char
131
+ @socket.getc
132
+ end
133
+
134
+ def write buffer
135
+ @socket << buffer
136
+ end
137
+
138
+ def close
139
+ return if @socket.nil?
140
+
141
+ @socket.close
142
+ @socket = nil
143
+ end
144
+
145
+ private
146
+
147
+ def tcp_connect
148
+ if @proxy
149
+ uri = URI(@proxy)
150
+ TCPSocket.new uri.host, uri.port
151
+ else
152
+ TCPSocket.new @uri.host,
153
+ @uri.port || (@secure ? 443 : 80)
154
+ end
155
+ end
156
+
157
+ def ssl_connect tcp_socket
158
+ ctx = ::OpenSSL::SSL::SSLContext.new
159
+ ctx.min_version = ::OpenSSL::SSL::TLS1_2_VERSION
160
+ cert_store = ::OpenSSL::X509::Store.new
161
+ cert_store.set_default_paths
162
+ ctx.cert_store = cert_store
163
+
164
+ ssl_socket = ::OpenSSL::SSL::SSLSocket.new tcp_socket, ctx
165
+ ssl_socket.hostname = @uri.host
166
+ ssl_socket.sync_close = true
167
+ ssl_socket.connect
168
+
169
+ ssl_socket
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,3 @@
1
+ module Rookout
2
+ COMMIT = "90ea969881b03cf95cef779cbcd072ef05270308".freeze
3
+ end
@@ -1,55 +1,131 @@
1
1
  module Rookout
2
2
  require_relative "version"
3
+ require_relative "commit"
3
4
 
4
5
  module Config
5
6
  # Magic to allow for module variables to be easily accessible
6
7
  class << self
7
8
  attr_accessor :debug
9
+ attr_accessor :quiet
10
+
8
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
9
17
 
10
- attr_accessor :logger_filename, :logger_log_to_stderr, :logger_log_level
11
18
  Rookout::Config.logger_filename = "rookout/ruby-rook.log".freeze
12
19
  Rookout::Config.logger_log_to_stderr = false
13
20
  Rookout::Config.logger_log_level = :info
14
21
 
15
- attr_accessor :agent_com_configuration_command_thread_name,
16
- :agent_com_max_message_limit,
17
- :agent_com_timeout,
18
- :agent_com_ping_interval,
19
- :agent_com_ping_timeout,
20
- :agent_com_flush_timeout,
21
- :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
+
22
31
  Rookout::Config.agent_com_max_message_limit = 1024 * 1024
32
+ Rookout::Config.agent_com_max_queue_messages_length = 15 * 1024 * 1024
23
33
  Rookout::Config.agent_com_timeout = 3
24
34
  Rookout::Config.agent_com_ping_interval = 10
25
35
  Rookout::Config.agent_com_ping_timeout = 30
26
36
  Rookout::Config.agent_com_flush_timeout = 3
27
- Rookout::Config.agent_com_max_queued_messages = 500
37
+ Rookout::Config.agent_com_max_queued_messages = 1000
38
+
39
+ attr_accessor :backoff_factor
40
+ attr_accessor :backoff_reset_time
41
+ attr_accessor :backoff_max_time
28
42
 
29
- attr_accessor :backoff_factor, :backoff_reset_time, :backoff_max_time
30
43
  Rookout::Config.backoff_factor = 0.2
31
44
  Rookout::Config.backoff_max_time = 60
32
45
  Rookout::Config.backoff_reset_time = 3 * 60.0
33
46
 
34
- attr_accessor :output_max_status_updates,
35
- :output_max_aug_messages,
36
- :output_max_log_items,
37
- :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
+
38
52
  Rookout::Config.output_max_status_updates = 200
39
- Rookout::Config.output_max_aug_messages = 100
53
+ Rookout::Config.output_max_aug_messages = 1000
40
54
  Rookout::Config.output_max_log_items = 200
41
- Rookout::Config.output_bucket_refresh_rate = 10
55
+ Rookout::Config.output_bucket_refresh_rate = 5
42
56
 
43
57
  attr_accessor :instrumentation_max_aug_time
58
+
44
59
  Rookout::Config.instrumentation_max_aug_time = 400
45
60
 
46
- attr_accessor :user_git_commit, :user_git_origin
61
+ attr_accessor :user_git_commit
62
+ attr_accessor :user_git_origin
63
+ attr_accessor :user_git_sources
64
+
47
65
  Rookout::Config.user_git_commit = nil
48
66
  Rookout::Config.user_git_origin = nil
67
+ Rookout::Config.user_git_sources = nil
68
+
69
+ attr_accessor :rookout_version
70
+ attr_accessor :rookout_commit
49
71
 
50
- attr_accessor :rookout_version, :rookout_commit
51
72
  Rookout::Config.rookout_version = Rookout::VERSION
52
73
  Rookout::Config.rookout_commit = Rookout::COMMIT
74
+
75
+ attr_accessor :protobuf_version2
76
+
77
+ Rookout::Config.protobuf_version2 = false
78
+
79
+ attr_accessor :true_values
80
+
81
+ Rookout::Config.true_values = ["y", "Y", "yes", "Yes", "YES", "true", "True", "TRUE", "1"]
82
+
83
+ attr_accessor :global_rate_limit_quota
84
+ attr_accessor :global_rate_limit_window_size
85
+ attr_accessor :global_rate_limit
86
+ attr_accessor :using_global_rate_limiter
87
+ attr_accessor :min_rate_limit_value_ns
88
+
89
+ Rookout::Config.global_rate_limit_quota = ""
90
+ Rookout::Config.global_rate_limit_window_size = ""
91
+ Rookout::Config.global_rate_limit = ""
92
+ Rookout::Config.using_global_rate_limiter = false
93
+ Rookout::Config.min_rate_limit_value_ns = 125 * 1000
94
+
95
+ def update_config configuration
96
+ update_var2_config configuration
97
+ update_global_rate_limit_config configuration
98
+ end
99
+
100
+ def update_var2_config configuration
101
+ is_config_proto2 = configuration["RUBY_PROTOBUF_VERSION_2"]
102
+ return if is_config_proto2.nil?
103
+ is_env_proto2 = ENV["ROOKOUT_Protobuf_Version2"]
104
+ if is_env_proto2.nil?
105
+ @protobuf_version2 = true if @true_values.include? is_config_proto2
106
+ elsif @true_values.include? is_env_proto2
107
+ Logger.instance.debug "ROOKOUT_Protobuf_Version2 env is preset: #{is_env_proto2}"
108
+ @protobuf_version2 = true
109
+ end
110
+ Logger.instance.info "Updating ROOKOUT_Protobuf_Version2 value to: #{@protobuf_version2}"
111
+ end
112
+
113
+ def update_global_rate_limit_config configuration
114
+ global_rate_limit = ENV["ROOKOUT_GLOBAL_RATE_LIMIT"]
115
+ if global_rate_limit.nil?
116
+ quota = configuration["RUBY_GLOBAL_RATE_LIMIT_QUOTA_MS"]
117
+ window_size = configuration["RUBY_GLOBAL_RATE_LIMIT_WINDOW_SIZE_MS"]
118
+
119
+ if quota != "" && !quota.nil? && window_size != "" && !window_size.nil?
120
+ global_rate_limit = "#{quota}/#{window_size}"
121
+ end
122
+ end
123
+
124
+ return if global_rate_limit.nil? || global_rate_limit == ""
125
+
126
+ @global_rate_limit = global_rate_limit
127
+ Logger.instance.info "Updating global rate limit to: #{global_rate_limit}"
128
+ end
53
129
  end
54
130
  end
55
131
  end