google-cloud-debugger 0.26.1 → 0.27.0

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
  SHA1:
3
- metadata.gz: 7a8f4cd45e74a4f18bf53c08fb05284529937c6b
4
- data.tar.gz: '0718436023043859a8c9b958dc43bb623fb7ec79'
3
+ metadata.gz: 51d29e7310e1ea9e0f409ee2e2198d52af61c163
4
+ data.tar.gz: 0e8474858473a49f70b06481f281c98b79e0bd70
5
5
  SHA512:
6
- metadata.gz: 323fde821b65e2167e7ea0b56f2ff988203d62d5391032890be39636bec869750e4bf701a7756b50b59b7b9eb11c71819a8a0df3830574304b7b3d38e1cfa595
7
- data.tar.gz: e68aa3d18c0aaf72db470b4dba4e1ecf439da21b43aeb081a552a49d8da093121795ffd32beec52fda075b68a90564cc70a88b579fca4008b1f2b6386032920c
6
+ metadata.gz: a1e9da07abc025976a843eee2a93d545a09beedac8b7bfc34345ffd77e676ad17a9827fcafd285be65a05ed2d0adfd5380f2f06a12bcaa63b8cf7a000ac88eed
7
+ data.tar.gz: b91cc538bbdc514d8105ae0220c482df52be13539c36ad3cb50bb4d0db071a54c146a687c5a34af40a36de04ddd012b283b26b2a309d0d30ef616450c27c33f9
@@ -23,19 +23,24 @@ eval_trace_callback(void *data, rb_trace_arg_t *trace_arg)
23
23
  {
24
24
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
25
25
  VALUE evaluator = (VALUE)data;
26
- VALUE klass = rb_tracearg_defined_class(trace_arg);
27
- VALUE obj = rb_tracearg_self(trace_arg);
28
- VALUE method_id = rb_tracearg_method_id(trace_arg);
26
+ VALUE klass;
27
+ VALUE obj;
28
+ VALUE method_id;
29
29
  ID trace_func_cb_id;
30
30
  ID trace_c_func_cb_id;
31
31
 
32
32
  CONST_ID(trace_func_cb_id, "trace_func_callback");
33
33
  CONST_ID(trace_c_func_cb_id, "trace_c_func_callback");
34
34
 
35
+ obj = rb_tracearg_self(trace_arg);
36
+ method_id = rb_tracearg_method_id(trace_arg);
37
+
35
38
  if (event & RUBY_EVENT_CALL) {
36
39
  rb_funcall(evaluator, trace_func_cb_id, 2, obj, method_id);
37
40
  }
38
41
  if (event & RUBY_EVENT_C_CALL) {
42
+ klass = rb_tracearg_defined_class(trace_arg);
43
+
39
44
  rb_funcall(evaluator, trace_c_func_cb_id, 3, obj, klass, method_id);
40
45
  }
41
46
 
@@ -144,17 +144,13 @@ line_trace_callback(rb_event_flag_t event, VALUE data, VALUE obj, ID mid, VALUE
144
144
  VALUE trace_binding;
145
145
  VALUE call_stack_bindings;
146
146
 
147
- int i;
148
147
  VALUE matching_result = match_breakpoints(self, c_trace_path, c_trace_lineno);
149
- VALUE *c_matching_breakpoints;
150
- VALUE matching_breakpoint;
151
- int matching_breakpoints_len;
152
148
 
153
149
  ID callers_id;
154
- ID breakpoint_hit_id;
150
+ ID breakpoints_hit_id;
155
151
 
156
152
  CONST_ID(callers_id, "callers");
157
- CONST_ID(breakpoint_hit_id, "breakpoint_hit");
153
+ CONST_ID(breakpoints_hit_id, "breakpoints_hit");
158
154
 
159
155
  // If matching result isn't an array, it means we're in completely wrong file,
160
156
  // or not on the right line. Turn line tracing off if we're in wrong file.
@@ -165,17 +161,11 @@ line_trace_callback(rb_event_flag_t event, VALUE data, VALUE obj, ID mid, VALUE
165
161
  return;
166
162
  }
167
163
 
168
- c_matching_breakpoints = RARRAY_PTR(matching_result);
169
- matching_breakpoints_len = RARRAY_LEN(matching_result);
170
164
  trace_binding = rb_binding_new();
171
165
  call_stack_bindings = rb_funcall(trace_binding, callers_id, 0);
172
166
  rb_ary_pop(call_stack_bindings);
173
167
 
174
- // Evaluate each of the matching breakpoint
175
- for (i = 0; i < matching_breakpoints_len; i++) {
176
- matching_breakpoint = c_matching_breakpoints[i];
177
- rb_funcall(self, breakpoint_hit_id, 2, matching_breakpoint, call_stack_bindings);
178
- }
168
+ rb_funcall(self, breakpoints_hit_id, 2, matching_result, call_stack_bindings);
179
169
 
180
170
  return;
181
171
  }
@@ -90,6 +90,19 @@ module Google
90
90
  # The logger used to write the results of Logpoints.
91
91
  attr_accessor :logger
92
92
 
93
+ ##
94
+ # A quota tracking object helps tracking resource consumption during
95
+ # evaluations.
96
+ attr_accessor :quota_manager
97
+
98
+ ##
99
+ # Absolute path to the debuggee Ruby application root directory. The
100
+ # Stackdriver Debugger service creates canonical breakpoints with only
101
+ # relative path. So the debugger agent combines the relative path to
102
+ # the application directory to trace and evaluate breakpoints.
103
+ # @return [String]
104
+ attr_accessor :app_root
105
+
93
106
  ##
94
107
  # @private The last exception captured in the agent child thread
95
108
  attr_reader :last_exception
@@ -102,11 +115,13 @@ module Google
102
115
  # @param [Google::Cloud::Logging::Logger] logger The logger used
103
116
  # to write the results of Logpoints.
104
117
  # @param [String] module_name Name for the debuggee application.
105
- # Optional.
106
118
  # @param [String] module_version Version identifier for the debuggee
107
- # application. Optional.
119
+ # application.
120
+ # @param [String] app_root Absolute path to the root directory of
121
+ # the debuggee application. Default to Rack root.
108
122
  #
109
- def initialize service, logger: nil, module_name:, module_version:
123
+ def initialize service, logger: nil, module_name:, module_version:,
124
+ app_root: nil
110
125
  super()
111
126
 
112
127
  @service = service
@@ -121,6 +136,9 @@ module Google
121
136
 
122
137
  @logger = logger || default_logger
123
138
 
139
+ @app_root = app_root
140
+ @app_root ||= Rack::Directory.new("").root if defined? Rack::Directory
141
+
124
142
  # Agent actor thread needs to force exit immediately.
125
143
  set_cleanup_options timeout: 0
126
144
  end
@@ -17,11 +17,21 @@ require "time"
17
17
  require "google/cloud/debugger/breakpoint/evaluator"
18
18
  require "google/cloud/debugger/breakpoint/source_location"
19
19
  require "google/cloud/debugger/breakpoint/stack_frame"
20
+ require "google/cloud/debugger/breakpoint/status_message"
21
+ require "google/cloud/debugger/breakpoint/validator"
20
22
  require "google/cloud/debugger/breakpoint/variable"
23
+ require "google/cloud/debugger/breakpoint/variable_table"
21
24
 
22
25
  module Google
23
26
  module Cloud
24
27
  module Debugger
28
+ ##
29
+ # # Breakpoint
30
+ #
31
+ # Abstract class that represents a breakpoint, which can be set and
32
+ # triggered in a debuggee application. Maps to gRPC struct
33
+ # {Google::Devtools::Clouddebugger::V2::Breakpoint}.
34
+ #
25
35
  class Breakpoint
26
36
  include MonitorMixin
27
37
 
@@ -34,6 +44,11 @@ module Google
34
44
  # @return [Symbol]
35
45
  attr_accessor :action
36
46
 
47
+ ##
48
+ # Absolute path to the debuggee Ruby application root directory.
49
+ # @return [String]
50
+ attr_accessor :app_root
51
+
37
52
  ##
38
53
  # Only relevant when action is LOG. Defines the message to log when the
39
54
  # breakpoint hits. The message may include parameter placeholders $0,
@@ -124,8 +139,7 @@ module Google
124
139
  # field. The stored objects are nameless and get their name from the
125
140
  # referencing variable. The effective variable is a merge of the
126
141
  # referencing variable and the referenced variable.
127
- # TODO: Implement variable table
128
- # attr_accessor :variable_table
142
+ attr_accessor :variable_table
129
143
 
130
144
  ##
131
145
  # A set of custom breakpoint properties, populated by the agent, to be
@@ -145,6 +159,8 @@ module Google
145
159
 
146
160
  @id = id
147
161
  @action = :CAPTURE
162
+ # Use relative path for SourceLocation, because that's how the server
163
+ # side canonical breakpoints are defined.
148
164
  @location = SourceLocation.new.tap do |sl|
149
165
  sl.path = path
150
166
  sl.line = line.to_i
@@ -153,6 +169,7 @@ module Google
153
169
  @evaluated_expressions = []
154
170
  @stack_frames = []
155
171
  @labels = {}
172
+ @variable_table = VariableTable.new
156
173
  end
157
174
 
158
175
  ##
@@ -160,26 +177,39 @@ module Google
160
177
  # from a Google::Devtools::Clouddebugger::V2::Breakpoint object.
161
178
  def self.from_grpc grpc
162
179
  return new if grpc.nil?
163
- new.tap do |b|
180
+
181
+ breakpoint = grpc.action == :LOG ? Logpoint.new : Snappoint.new
182
+ breakpoint.tap do |b|
164
183
  b.id = grpc.id
165
184
  b.action = grpc.action
166
185
  b.condition = grpc.condition
167
- b.create_time = timestamp_from_grpc grpc.create_time
168
- b.evaluated_expressions =
169
- Breakpoint::Variable.from_grpc_list grpc.evaluated_expressions
170
186
  b.expressions = grpc.expressions.to_a
171
- b.final_time = timestamp_from_grpc grpc.final_time
172
187
  b.labels = hashify_labels grpc.labels
173
188
  b.log_message_format = grpc.log_message_format
174
189
  b.log_level = grpc.log_level
175
- b.location = Breakpoint::SourceLocation.from_grpc grpc.location
176
190
  b.is_final_state = grpc.is_final_state
177
- b.status = grpc.status
178
- b.stack_frames = stack_frames_from_grpc grpc
179
191
  b.user_email = grpc.user_email
192
+
193
+ assign_complex_grpc_fields grpc, b
180
194
  end
181
195
  end
182
196
 
197
+ ##
198
+ # @private Helper method that helps extracting complex fields from
199
+ # grpc struct into a breakpoint.
200
+ def self.assign_complex_grpc_fields grpc, breakpoint
201
+ breakpoint.create_time = timestamp_from_grpc grpc.create_time
202
+ breakpoint.evaluated_expressions =
203
+ Breakpoint::Variable.from_grpc_list grpc.evaluated_expressions
204
+ breakpoint.final_time = timestamp_from_grpc grpc.final_time
205
+ breakpoint.location =
206
+ Breakpoint::SourceLocation.from_grpc grpc.location
207
+ breakpoint.stack_frames = stack_frames_from_grpc grpc
208
+ breakpoint.status = Breakpoint::StatusMessage.from_grpc grpc.status
209
+ breakpoint.variable_table =
210
+ Breakpoint::VariableTable.from_grpc grpc.variable_table
211
+ end
212
+
183
213
  ##
184
214
  # @private Extract array of stack_frame from grpc
185
215
  def self.stack_frames_from_grpc grpc
@@ -205,8 +235,10 @@ module Google
205
235
  end
206
236
  end
207
237
 
208
- private_class_method :stack_frames_from_grpc, :timestamp_from_grpc,
209
- :hashify_labels
238
+ private_class_method :stack_frames_from_grpc,
239
+ :timestamp_from_grpc,
240
+ :hashify_labels,
241
+ :assign_complex_grpc_fields
210
242
 
211
243
  ##
212
244
  # Marks a breakpoint as complete if this breakpoint isn't completed
@@ -220,7 +252,21 @@ module Google
220
252
  end
221
253
  end
222
254
 
223
- alias_method :complete?, :is_final_state
255
+ ##
256
+ # Check if the breakpoint has been evaluated or set to a final error
257
+ # state.
258
+ def complete?
259
+ is_final_state ? true : false
260
+ end
261
+
262
+ ##
263
+ # Check if the breakpoint is valid or not. Invoke validation function
264
+ # if breakpoint hasn't been finallized yet.
265
+ def valid?
266
+ Validator.validate self unless complete?
267
+
268
+ status && status.is_error ? false : true
269
+ end
224
270
 
225
271
  ##
226
272
  # Get the file path of this breakpoint
@@ -244,44 +290,33 @@ module Google
244
290
 
245
291
  ##
246
292
  # Evaluate the breakpoint's condition expression against a given binding
247
- # object. Returns true if the condition expression evalutes to true;
248
- # false if error happens or the expression evaluates to false.
293
+ # object. Returns true if the condition expression evalutes to true or
294
+ # there isn't a condition; otherwise false. Set breakpoint to error
295
+ # state if exception happens.
249
296
  #
250
297
  # @param [Binding] binding A Ruby Binding object
251
- # @return [Boolean] True if condition evalutes to true, false if
252
- # condition evaluates to false or error raised during evaluation.
253
- #
298
+ # @return [Boolean] True if condition evalutes to true or there isn't a
299
+ # condition. False if condition evaluates to false or error raised
300
+ # during evaluation.
254
301
  def check_condition binding
255
302
  return true if condition.nil? || condition.empty?
256
- begin
257
- Evaluator.eval_condition binding, condition
258
- rescue
259
- set_error_state "Unable to evaluate condition",
260
- refers_to: :BREAKPOINT_CONDITION
261
- false
262
- end
263
- end
303
+ condition_result =
304
+ Evaluator.readonly_eval_expression binding, condition
264
305
 
265
- ##
266
- # Evaluate the breakpoint unless it's already marked as completed.
267
- # Store evaluted results in @evaluated_expressions, @stack_frames, and
268
- # @evaluated_log_message, depends on the action of breakpoint. Mark
269
- # breakpoint complete if successfully evaluated a breakpoint with
270
- # :CAPTURE action.
271
- #
272
- # @param [Array<Binding>] call_stack_bindings An array of Ruby Binding
273
- # objects, from the call stack that leads to the triggering of the
274
- # breakpoints.
275
- #
276
- # @return [Boolean] True if evaluated successfully; false otherwise.
277
- #
278
- def evaluate call_stack_bindings
279
- case action
280
- when :CAPTURE
281
- evaluate_snapshot_point call_stack_bindings
282
- when :LOG
283
- evaluate_logpoint call_stack_bindings[0]
306
+ if condition_result.is_a?(Exception) &&
307
+ condition_result.instance_variable_get(:@mutation_cause)
308
+ set_error_state "Error: #{condition_result.message}",
309
+ refers_to: StatusMessage::BREAKPOINT_CONDITION
310
+
311
+ return false
284
312
  end
313
+
314
+
315
+ condition_result ? true : false
316
+ rescue => e
317
+ set_error_state "Error: #{e.message}",
318
+ refers_to: StatusMessage::BREAKPOINT_CONDITION
319
+ false
285
320
  end
286
321
 
287
322
  ##
@@ -313,8 +348,9 @@ module Google
313
348
  user_email: user_email,
314
349
  stack_frames: stack_frames_to_grpc,
315
350
  evaluated_expressions: evaluated_expressions_to_grpc,
316
- status: status,
317
- labels: labels_to_grpc
351
+ status: status_to_grpc,
352
+ labels: labels_to_grpc,
353
+ variable_table: variable_table.to_grpc
318
354
  )
319
355
  end
320
356
 
@@ -324,79 +360,39 @@ module Google
324
360
  # completed if is_final is true.
325
361
  #
326
362
  # @param [String] message The error message
327
- # @param [Google::Devtools::Clouddebugger::V2::StatusMessage::Reference]
328
- # refers_to Enum that specifies what the error refers to. Defaults
329
- # :UNSPECIFIED.
363
+ # @param [Symbol] refers_to Enum that specifies what the error refers
364
+ # to. Defaults :UNSPECIFIED. See {Breakpoint::StatusMessage} class for
365
+ # list of possible values
330
366
  # @param [Boolean] is_final Marks the breakpoint as final if true.
331
367
  # Defaults true.
332
368
  #
333
- # @return [Google::Devtools::Clouddebugger::V2::StatusMessage] The grpc
369
+ # @return [Google::Cloud::Debugger::Breakpoint::StatusMessage] The grpc
334
370
  # StatusMessage object, which describes the breakpoint's error state.
335
- def set_error_state message, refers_to: :UNSPECIFIED, is_final: true
336
- description = Google::Devtools::Clouddebugger::V2::FormatMessage.new(
337
- format: message
338
- )
339
- @status = Google::Devtools::Clouddebugger::V2::StatusMessage.new(
340
- is_error: true,
341
- refers_to: refers_to,
342
- description: description
343
- )
371
+ def set_error_state message, refers_to: StatusMessage::UNSPECIFIED,
372
+ is_final: true
373
+ @status = StatusMessage.new.tap do |s|
374
+ s.is_error = true
375
+ s.refers_to = refers_to
376
+ s.description = message
377
+ end
344
378
 
345
379
  complete if is_final
346
380
 
347
381
  @status
348
382
  end
349
383
 
350
- private
351
-
352
384
  ##
353
- # @private Evaluate snapshot point
354
- def evaluate_snapshot_point call_stack_bindings
355
- synchronize do
356
- top_binding = call_stack_bindings[0]
357
-
358
- return false if complete? || !check_condition(top_binding)
359
-
360
- begin
361
- unless expressions.empty?
362
- @evaluated_expressions =
363
- Evaluator.eval_expressions top_binding, @expressions
364
- end
365
-
366
- @stack_frames = Evaluator.eval_call_stack call_stack_bindings
367
-
368
- complete
369
- rescue
370
- return false
371
- end
372
- end
373
-
374
- true
375
- end
376
-
377
- ##
378
- # @private Evaluate logpoint
379
- def evaluate_logpoint binding
380
- synchronize do
381
- return false if complete? || !check_condition(binding)
382
-
383
- begin
384
- unless expressions.empty?
385
- @evaluated_expressions = expressions.map do |expression|
386
- Evaluator.readonly_eval_expression binding, expression
387
- end
388
- end
389
- @evaluated_log_message =
390
- Evaluator.format_message log_message_format,
391
- evaluated_expressions
392
- rescue
393
- return false
394
- end
385
+ # Get full absolute file path by combining the relative file path
386
+ # with application root directory path.
387
+ def full_path
388
+ if app_root.nil? || app_root.empty?
389
+ path
390
+ else
391
+ File.join app_root, path
395
392
  end
396
-
397
- true
398
393
  end
399
394
 
395
+ private
400
396
 
401
397
  ##
402
398
  # @private Formats the labels so they can be saved to a
@@ -417,11 +413,18 @@ module Google
417
413
 
418
414
  ##
419
415
  # @private Exports the Breakpoint stack_frames to an array of
420
- # Google::Devtools::Clouddebugger::V2::StackFrame objects.
416
+ # Google::Devtools::Clouddebugger::V2::Variable objects.
421
417
  def evaluated_expressions_to_grpc
422
418
  evaluated_expressions.nil? ? [] : evaluated_expressions.map(&:to_grpc)
423
419
  end
424
420
 
421
+ ##
422
+ # @private Exports Breakpoint status to
423
+ # Google::Devtools::Clouddebugger::V2::StatusMessage object
424
+ def status_to_grpc
425
+ status.nil? ? nil: status.to_grpc
426
+ end
427
+
425
428
  ##
426
429
  # @private Formats the timestamp as a Google::Protobuf::Timestamp
427
430
  # object.