rookout 0.1.0 → 0.1.1

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