rookout 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17eda3a68e52adf758e353e65066c8e68e65c5df18e67299c95e111a60717260
4
- data.tar.gz: fd7cadcf2f2890130e9d92c6f56312c7c1a6bf1ad55efc84a83c39ad67f68020
3
+ metadata.gz: 874a75dff546e6c6959ecd21b5083d3b6f8a6a0f3c055722221471572d6633c1
4
+ data.tar.gz: cef6e4460d9a852de5ca2af9dbd1fe865a1ead4cdb7186e62d7383453702402c
5
5
  SHA512:
6
- metadata.gz: c1968166a99e6c85d7476de449bea06d7105bd9b0b71681c8c4263ccc33d88440e2a956a1d29d4681db44af1d6a8ea5e1cfb142895c182bb1388868c6f920035
7
- data.tar.gz: f805c321af5605bade4d443557b3c575d7f432afa392820c4589bc8023af8a971e7a7d72f851ff2899ae7c4aca5fd3864f4e35dd0fb5e942cc4c3e570402cbdc
6
+ metadata.gz: 3ea95c83e5b19b8279ea1ce829814bebda8425411e926b3b7bcbcbf72d5c9a08bedb87dc2a6ff7e5f10083f9f062d2c1ca85e93364d63d0e35b043dee843498d
7
+ data.tar.gz: d10b3af2d478bc77f2488d7a86083f6f46bdfda8ea450bc65d17dec194efdaf9495e8c1972381473136e4766e88c805b930ea66ecfba086a54a23876b4fc46fe
@@ -15,12 +15,12 @@ module Rookout
15
15
  end
16
16
  end
17
17
 
18
- def execute aug_id, report_id, namespace, _output
18
+ def execute aug_id, report_id, namespace, output
19
19
  @processor.process namespace
20
- @output.send_user_message aug_id, report_id, namespace.read_attribute("store")
20
+ output.send_user_message aug_id, report_id, namespace.read_attribute("store")
21
21
  return unless @post_processor
22
22
 
23
- @output.flush_message
23
+ output.flush_message
24
24
  @post_processor.process namespace
25
25
  end
26
26
  end
@@ -1,11 +1,6 @@
1
- require_relative "../logger"
2
- require_relative "../user_warnings"
3
- require_relative "../processor/rook_error"
4
-
5
1
  module Rookout
6
2
  module Augs
7
- require "securerandom"
8
- require "concurrent-ruby/concurrent/atom"
3
+ require_relative "../utils"
9
4
 
10
5
  require_relative "../processor/namespaces/frame_namespace"
11
6
  require_relative "../processor/namespaces/stack_namespace"
@@ -13,109 +8,47 @@ module Rookout
13
8
  require_relative "../processor/namespaces/ruby_utils_namespace"
14
9
  require_relative "../processor/namespaces/noop_namespace"
15
10
 
16
- require_relative "../logger"
17
-
18
- MAX_LOG_CACHE_SIZE = 10
19
-
20
11
  class Aug
21
- def initialize aug_id, location, action, condition, rate_limiter, _max_aug_time, output
12
+ def initialize aug_id, action, condition, rate_limiter, _max_aug_time
22
13
  # NOTE: max_aux_time is not implemented
23
14
 
24
15
  @id = aug_id
25
- @location = location
26
16
  @action = action
27
17
  @condition = condition
28
18
  @rate_limiter = rate_limiter
29
- @output = output
30
19
 
31
20
  @enabled = true
32
21
  @status = nil
33
22
  @log_cache = []
34
23
  end
35
- end
36
-
37
- attr_reader :id
38
-
39
- def add_aug trigger_services
40
- @location.add_aug trigger_services, self
41
- rescue SystemExit
42
- raise
43
- rescue Exception => e
44
- message = "Exception when adding aug"
45
- Logger.instance.error message, e
46
- notify_error RookError.new e, message
47
- end
48
24
 
49
- def execute frame, extracted
50
- return unless @enabled
25
+ attr_reader :id
51
26
 
52
- UserWarnings.with self do
53
- begin
54
- namespace = create_namespaces frame, extracted
27
+ def execute frame, extracted, output
28
+ return unless @enabled
55
29
 
56
- return if @condition && !@condition.evaluate(namespace)
30
+ namespace = create_namespaces frame, extracted
31
+ return if @condition && !@condition.evaluate(namespace)
57
32
 
58
- @rate_limiter.with_limit do
59
- report_id = SecureRandom.uuid
60
- @action.execute @aug_id, report_id, namespace, @output
61
- end
62
- rescue SystemExit
63
- raise
64
- rescue Exception => e
65
- message = "Exception while processing Aug"
66
- error = RookError.new e, message
67
- notify_warning error unless silence_log? error
33
+ @rate_limiter.with_limit do
34
+ report_id = Utils.uuid
35
+ @action.execute @id, report_id, namespace, output
68
36
  end
69
37
  end
70
- end
71
-
72
- def notify_active
73
- send_rule_status :Active
74
- end
75
-
76
- def notify_pending
77
- send_rule_status :Pending
78
- end
79
-
80
- def notify_removed
81
- send_rule_status :Deleted
82
- end
83
38
 
84
- def notify_error error
85
- send_rule_status :Error, error
86
- end
87
-
88
- def notify_warning error
89
- return if silence_log? error
90
- send_rule_status :Warning, error
91
- end
92
-
93
- private
94
-
95
- def create_namespaces frame, extracted
96
- ContainerNamespace.new("frame": Processor::Namespaces::FrameNamespace.new(frame[1]),
97
- "stack": Processor::Namespaces::StackNamespace.new(frame, 1),
98
- "extracted": Processor::Namespaces::ContainerNamespace.new(extracted),
99
- "store": Processor::Namespaces::ContainerNamespace.new,
100
- "temp": Processor::Namespaces::ContainerNamespace.new,
101
- "utils": Processor::Namespaces::RubyUtisNamespace.new,
102
- "trace": Processor::Namespaces::NoopNamespace.new)
103
- end
104
-
105
- def silence_log? error
106
- return true if @log_cache.length >= MAX_LOG_CACHE_SIZE || @log_cache.include(error.message)
107
-
108
- @log_cache << error.message
109
- false
110
- end
111
-
112
- def send_rule_status status, error = nil
113
- return unless @status != status
114
-
115
- Logger.instance.info "Updating rule status for #{@id} to #{status}"
116
- @status = status
117
-
118
- @output.send_rule_status @id, status, error
39
+ private
40
+
41
+ def create_namespaces frame, extracted
42
+ Processor::Namespaces::ContainerNamespace.new(
43
+ "frame" => Processor::Namespaces::FrameNamespace.new(frame[1]),
44
+ "stack" => Processor::Namespaces::StackNamespace.new(frame, 1),
45
+ "extracted" => Processor::Namespaces::ContainerNamespace.new(extracted),
46
+ "store" => Processor::Namespaces::ContainerNamespace.new,
47
+ "temp" => Processor::Namespaces::ContainerNamespace.new,
48
+ "utils" => Processor::Namespaces::RubyUtilsNamespace.new,
49
+ "trace" => Processor::Namespaces::NoopNamespace.new
50
+ )
51
+ end
119
52
  end
120
53
  end
121
54
  end
@@ -6,7 +6,9 @@ module Rookout
6
6
 
7
7
  require_relative "actions/action_run_processor"
8
8
  require_relative "conditions/condition"
9
+ require_relative "locations/location_file_line"
9
10
  require_relative "aug_rate_limiter"
11
+ require_relative "aug"
10
12
 
11
13
  class AugFactory
12
14
  def initialize output
@@ -16,35 +18,36 @@ module Rookout
16
18
 
17
19
  def create_aug configuration
18
20
  aug_id = configuration["id"]
19
- raise Exceptions.RookAugInvalidKey "id", configuration unless aug_id.is_a? String
20
-
21
- location_configuration = configuration["location"]
22
- raise Exceptions.RookAugInvalidKey "location", configuration unless location_configuration.is_a? Hash
23
- location = create_location location_configuration
21
+ raise Exceptions::RookAugInvalidKey.new("id", configuration) unless aug_id.is_a? String
24
22
 
25
23
  action_configuration = configuration["action"]
26
- raise Exceptions.RookAugInvalidKey "action", configuration unless action_configuration.is_a? Hash
27
- action = Actions.ActionRunProcess.new action_configuration, @factory
24
+ raise Exceptions::RookAugInvalidKey.new("action", configuration) unless action_configuration.is_a? Hash
25
+ action = Actions::ActionRunProcessor.new action_configuration, @factory
28
26
 
29
- max_aug_time = configuration["maxAugTime"] || Config.INSTRUMENTATION_MAX_AUG_TIME
27
+ max_aug_time = configuration["maxAugTime"] || Config.instrumentation_max_aug_time
30
28
 
31
29
  condition_configuration = configuration["conditional"]
32
- raise Exceptions.RookAugInvalidKey "conditional", configuration unless condition_configuration.is_a? String
33
- condition = Conditions.Condition.new condition_configuration
30
+ raise Exceptions::RookAugInvalidKey.new("conditional", configuration) unless
31
+ condition_configuration.nil? || condition_configuration.is_a?(String)
32
+ condition = condition_configuration.nil? ? nil : Conditions::Condition.new(condition_configuration)
34
33
 
35
34
  rate_limit = create_rate_limit configuration
36
35
 
37
- Aug.new aug_id, location, action, condition, rate_limit, max_aug_time, @output
36
+ aug = Aug.new aug_id, action, condition, rate_limit, max_aug_time
37
+
38
+ location_configuration = configuration["location"]
39
+ raise Exceptions::RookAugInvalidKey.new("location", configuration) unless location_configuration.is_a? Hash
40
+ create_location location_configuration, aug
38
41
  end
39
42
 
40
43
  private
41
44
 
42
- def create_location configuration
45
+ def create_location configuration, aug
43
46
  name = configuration["name"]
44
47
  raise Exceptions.RookObjectNameMissing if name.nil?
45
48
  raise Exceptions.RookUnsupportedLocation if name != "file_line"
46
49
 
47
- Locations.LocationFileLine.new configuration, @factory
50
+ Locations::LocationFileLine.new configuration, @output, aug
48
51
  end
49
52
 
50
53
  def create_rate_limit configuration
@@ -15,12 +15,12 @@ module Rookout
15
15
 
16
16
  def with_limit start_time = nil
17
17
  active = false
18
- start_time ||= Time.new
18
+ start_time ||= Time.now
19
19
 
20
20
  # If quota, verify it
21
21
  if @quota
22
22
  # Get current time
23
- now_ms = (now * 1000).to_i
23
+ now_ms = (start_time.to_f * 1000).to_i
24
24
 
25
25
  # Calculate window keys
26
26
  current_window_key = (now_ms / @window_size) * @window_size
@@ -77,7 +77,7 @@ module Rookout
77
77
  return if prev_value.nil?
78
78
 
79
79
  # Add value to quota
80
- @windows[current_window_key] += max(duration, 5).to_f
80
+ @windows[current_window_key] += [duration, 5].max.to_f
81
81
  end
82
82
 
83
83
  def cleanup now_ms
@@ -1,13 +1,15 @@
1
1
  module Rookout
2
2
  module Augs
3
3
  module Conditions
4
+ require_relative "../../processor/paths/arithmetic_path"
5
+
4
6
  class Condition
5
7
  def initialize condition
6
- @path = ArithmeticPath.new condition
8
+ @path = Processor::Paths::ArithmeticPath.new condition
7
9
  end
8
10
 
9
11
  def evaluate namespace
10
- @path.read_from(namespace).object == true
12
+ @path.read_from(namespace).obj == true
11
13
  end
12
14
  end
13
15
  end
@@ -1,10 +1,84 @@
1
1
  module Rookout
2
2
  module Augs
3
3
  module Locations
4
+ require_relative "../../processor/rook_error"
5
+
6
+ MAX_LOG_CACHE_SIZE = 10
7
+
4
8
  class Location
5
- def add_aug _trigger_services, _aug
9
+ def initialize output, aug
10
+ @output = output
11
+ @aug = aug
12
+ @log_cache = []
13
+ end
14
+
15
+ def add_aug _trigger_services
6
16
  raise NotImplementedError
7
17
  end
18
+
19
+ def id
20
+ @aug.id
21
+ end
22
+
23
+ def execute frame, extracted
24
+ UserWarnings.with self do
25
+ begin
26
+ @aug.execute frame, extracted, @output
27
+ rescue SystemExit
28
+ raise
29
+ rescue Exception => e
30
+ message = "Exception while processing Aug"
31
+ puts e.message + "\n" + e.backtrace.join("\n\t")
32
+ error = Processor::RookError.new e, message
33
+ notify_warning error
34
+ end
35
+ end
36
+ end
37
+
38
+ def notify_active
39
+ send_rule_status :Active
40
+ end
41
+
42
+ def notify_pending
43
+ send_rule_status :Pending
44
+ end
45
+
46
+ def notify_removed
47
+ send_rule_status :Deleted
48
+ end
49
+
50
+ def notify_error error
51
+ send_rule_status :Error, error
52
+ end
53
+
54
+ def notify_warning error
55
+ return if silence_log? error
56
+
57
+ Logger.instance.warning error.message
58
+
59
+ send_rule_status :Warning, error
60
+ end
61
+
62
+ private
63
+
64
+ def silence_log? error
65
+ return true if @log_cache.length >= MAX_LOG_CACHE_SIZE || @log_cache.include?(error.message)
66
+
67
+ @log_cache << error.message
68
+ false
69
+ end
70
+
71
+ def send_rule_status status, error = nil
72
+ return if @status == status
73
+
74
+ Logger.instance.info "Updating rule status for #{@id} to #{status}"
75
+ @status = status
76
+
77
+ # For easier testing
78
+ return if @output.nil?
79
+
80
+ @output.send_rule_status id, status, error
81
+ end
8
82
  end
9
83
  end
10
84
  end
@@ -1,24 +1,36 @@
1
1
  module Rookout
2
2
  module Augs
3
+ require_relative "../../logger"
4
+
5
+ require_relative "../../processor/rook_error"
6
+
3
7
  module Locations
4
8
  require_relative "location"
5
9
 
6
10
  class LocationFileLine < Location
7
11
  NAME = "file_line".freeze
8
12
 
9
- def initialize arguments, _processor_factory
13
+ def initialize arguments, output, aug
14
+ super output, aug
10
15
  @filename = arguments["filename"]
11
16
  @lineno = arguments["lineno"]
12
17
 
18
+ # NOTE: Hashes are only used for suggestions, not for verification
13
19
  @file_hash = arguments["sha256"]
14
20
  @line_crc = arguments["line_crc32_2"]
15
- @line_unique = arguments["line_unique"] != 0
21
+ @line_unique = arguments["line_unique"] || false
16
22
  end
17
23
 
18
24
  attr_reader :filename, :lineno, :file_hash, :line_crc, :line_unique
19
25
 
20
- def add_aug trigger_services, aug
21
- trigger_services.get_service("position").add_aug self, aug
26
+ def add_aug trigger_services
27
+ trigger_services.get_service("position").add_aug self
28
+ rescue SystemExit
29
+ raise
30
+ rescue Exception => e
31
+ message = "Exception when adding aug"
32
+ Logger.instance.error message, e
33
+ notify_error Processor::RookError.new e, message
22
34
  end
23
35
  end
24
36
  end
@@ -1,7 +1,5 @@
1
1
  module Rookout
2
2
  module ComWs
3
- require "securerandom"
4
- require "kontena-websocket-client"
5
3
  require "event_emitter"
6
4
  require "google/protobuf/well_known_types"
7
5
  require "concurrent"
@@ -10,14 +8,17 @@ module Rookout
10
8
  require_relative "../logger"
11
9
  require_relative "../user_warnings"
12
10
  require_relative "../exceptions"
11
+ require_relative "../utils"
13
12
 
14
13
  require_relative "../processor/rook_error"
15
14
 
16
15
  require_relative "../protobuf/messages_pb"
17
16
  require_relative "../protobuf/envelope_pb"
18
17
 
18
+ require_relative "websocket_client"
19
19
  require_relative "backoff"
20
20
  require_relative "information"
21
+ require_relative "pinger"
21
22
 
22
23
  class AgentComWs
23
24
  include EventEmitter
@@ -68,7 +69,11 @@ module Rookout
68
69
  end
69
70
 
70
71
  def wait_for_ready
71
- @ready_event.wait Config.agent_com_timeout
72
+ is_finished = @ready_event.wait Config.agent_com_timeout
73
+ # We didn't finish - will keep trying in the background
74
+ raise Exceptions::RookCommunicationException unless is_finished
75
+
76
+ # We finished - raise if we failed
72
77
  raise @connection_error if @connection_error
73
78
  end
74
79
 
@@ -86,17 +91,15 @@ module Rookout
86
91
  while @running
87
92
  begin
88
93
  backoff.before_connection_attempt
89
- Kontena::Websocket::Client.connect(@uri, **create_options) do |client|
90
- register client
94
+ client = open_new_connection
91
95
 
92
- Logger.instance.debug "WebSocket connected successfully"
93
- @token_valid = true
94
- backoff.after_connect
96
+ Logger.instance.debug "WebSocket connected successfully"
97
+ @token_valid = true
98
+ backoff.after_connect
95
99
 
96
- connection_pump client
97
- end
100
+ connection_pump client
98
101
  rescue Exception => e
99
- if !@token_valid && e.is_a?(Kontena::Websocket::ProtocolError) && e.message.include?("403")
102
+ if !@token_valid && e.message.include?("403")
100
103
  @connection_error = Exceptions::RookInvalidToken.new @token
101
104
  @ready_event.set
102
105
  end
@@ -109,26 +112,15 @@ module Rookout
109
112
  end
110
113
  end
111
114
 
112
- def create_options
113
- headers = {
114
- "User-Agent" => "RookoutAgent/#{Config.rookout_version}+#{Config.rookout_commit}"
115
- }
116
-
117
- headers["X-Rookout-Token"] = @token unless @token.nil?
118
-
119
- # NOTE: WE DONT HAVE PROXY SUPPORT (YET) - THIS WILL PROBABLY REQUIRE FORKING KONTENA
120
- { headers: headers,
121
- connect_timeout: Config.agent_com_timeout,
122
- open_timeout: Config.agent_com_timeout,
123
- ping_interval: Config.agent_com_ping_interval,
124
- ping_timeout: Config.agent_com_ping_timeout }
125
- end
115
+ def open_new_connection
116
+ client = WebsocketClient.new @uri, @proxy, @token
117
+ client.connect
126
118
 
127
- def register client
128
119
  Logger.instance.info "Registering agent with id #{@agent_id}"
129
-
130
120
  msg = Com::Rookout::NewAgentMessage.new agent_info: @info.pack
131
- client.send wrap_in_envelope(msg)
121
+ client.send_frame wrap_in_envelope(msg)
122
+
123
+ client
132
124
  end
133
125
 
134
126
  ACCEPTED_MESSAGE_TYPES = [
@@ -140,11 +132,11 @@ module Rookout
140
132
  ].freeze
141
133
 
142
134
  def connection_pump client
143
- on_outgoing_exit = proc { client.disconnect }
135
+ on_outgoing_exit = proc { client.close }
144
136
  send_thread = Thread.new { outgoing client, on_outgoing_exit }
145
137
  send_thread.name = "rookout-outgoing-thread"
146
138
 
147
- client.read do |raw_message|
139
+ message_handler = proc do |raw_message|
148
140
  envelope = Com::Rookout::Envelope.decode raw_message.pack("c*")
149
141
 
150
142
  ACCEPTED_MESSAGE_TYPES.each do |klass|
@@ -153,6 +145,8 @@ module Rookout
153
145
  end
154
146
  end
155
147
 
148
+ client.connection_pump message_handler
149
+
156
150
  Logger.instance.debug "Incoming loop - socket disconnected"
157
151
 
158
152
  @pending_messages.push ExitMessage.new(send_thread)
@@ -160,7 +154,7 @@ module Rookout
160
154
  end
161
155
 
162
156
  def outgoing client, on_exit
163
- loop do
157
+ Pinger.new(client, Config.agent_com_ping_interval, Config.agent_com_ping_timeout).repeat do
164
158
  begin
165
159
  msg = @pending_messages.pop true
166
160
  rescue ThreadError
@@ -174,7 +168,7 @@ module Rookout
174
168
  msg.event.set
175
169
  else
176
170
  begin
177
- client.send msg
171
+ client.send_frame msg
178
172
  rescue RuntimeError
179
173
  @queue << msg
180
174
  break
@@ -184,6 +178,7 @@ module Rookout
184
178
  rescue Exception => e
185
179
  Logger.instance.exception "Outgoing thread failed", e
186
180
  ensure
181
+ Logger.instance.debug "Outgoing thread exiting"
187
182
  on_exit.call
188
183
  end
189
184
 
@@ -196,7 +191,7 @@ module Rookout
196
191
  end
197
192
 
198
193
  def reset_id
199
- @agent_id = SecureRandom.uuid
194
+ @agent_id = Utils.uuid
200
195
  @output.agent_id = @agent_id
201
196
  @info.agent_id = @agent_id
202
197
  end