rookout 0.1.0 → 0.1.56

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