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 +4 -4
- data/ext/google/cloud/debugger/debugger_c/evaluator.c +8 -3
- data/ext/google/cloud/debugger/debugger_c/tracer.c +3 -13
- data/lib/google/cloud/debugger/agent.rb +21 -3
- data/lib/google/cloud/debugger/breakpoint.rb +110 -107
- data/lib/google/cloud/debugger/breakpoint/evaluator.rb +49 -162
- data/lib/google/cloud/debugger/breakpoint/status_message.rb +95 -0
- data/lib/google/cloud/debugger/breakpoint/validator.rb +91 -0
- data/lib/google/cloud/debugger/breakpoint/variable.rb +313 -41
- data/lib/google/cloud/debugger/breakpoint/variable_table.rb +96 -0
- data/lib/google/cloud/debugger/breakpoint_manager.rb +45 -10
- data/lib/google/cloud/debugger/credentials.rb +2 -1
- data/lib/google/cloud/debugger/logpoint.rb +97 -0
- data/lib/google/cloud/debugger/middleware.rb +16 -5
- data/lib/google/cloud/debugger/request_quota_manager.rb +95 -0
- data/lib/google/cloud/debugger/snappoint.rb +208 -0
- data/lib/google/cloud/debugger/tracer.rb +20 -32
- data/lib/google/cloud/debugger/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51d29e7310e1ea9e0f409ee2e2198d52af61c163
|
4
|
+
data.tar.gz: 0e8474858473a49f70b06481f281c98b79e0bd70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
27
|
-
VALUE obj
|
28
|
-
VALUE method_id
|
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
|
150
|
+
ID breakpoints_hit_id;
|
155
151
|
|
156
152
|
CONST_ID(callers_id, "callers");
|
157
|
-
CONST_ID(
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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,
|
209
|
-
:
|
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
|
-
|
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
|
-
#
|
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
|
252
|
-
# condition evaluates to false or error raised
|
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
|
-
|
257
|
-
Evaluator.
|
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
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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:
|
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 [
|
328
|
-
#
|
329
|
-
#
|
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::
|
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:
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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
|
-
#
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
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::
|
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.
|