google-cloud-debugger 0.26.1 → 0.27.0
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 +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
@@ -13,6 +13,8 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
+
require "google/cloud/debugger/breakpoint/status_message"
|
17
|
+
|
16
18
|
module Google
|
17
19
|
module Cloud
|
18
20
|
module Debugger
|
@@ -83,12 +85,21 @@ module Google
|
|
83
85
|
|
84
86
|
##
|
85
87
|
# Max number of member variables to evaluate in compound variables
|
86
|
-
MAX_MEMBERS =
|
88
|
+
MAX_MEMBERS = 1000
|
87
89
|
|
88
90
|
##
|
89
91
|
# Max length on variable inspect results. Truncate extra and replace
|
90
92
|
# with ellipsis.
|
91
|
-
MAX_STRING_LENGTH =
|
93
|
+
MAX_STRING_LENGTH = 500
|
94
|
+
|
95
|
+
##
|
96
|
+
# @private Minimum amount of size limit needed for evaluation.
|
97
|
+
MIN_REQUIRED_SIZE = 100
|
98
|
+
|
99
|
+
##
|
100
|
+
# @private Message to display on variables when snapshot buffer is
|
101
|
+
# full.
|
102
|
+
BUFFER_FULL_MSG = "Buffer full. Use an expression to see more data."
|
92
103
|
|
93
104
|
##
|
94
105
|
# @private Name of the variable, if any.
|
@@ -111,6 +122,17 @@ module Google
|
|
111
122
|
# @return [Array<Variable>]
|
112
123
|
attr_accessor :members
|
113
124
|
|
125
|
+
##
|
126
|
+
# @private Reference to a variable in the shared variable table. More
|
127
|
+
# than one variable can reference the same variable in the table. The
|
128
|
+
# var_table_index field is an index into variable_table in Breakpoint.
|
129
|
+
attr_accessor :var_table_index
|
130
|
+
|
131
|
+
##
|
132
|
+
# @private The variable table this variable references to (if
|
133
|
+
# var_table_index is set).
|
134
|
+
attr_accessor :var_table
|
135
|
+
|
114
136
|
##
|
115
137
|
# @private Status associated with the variable. This field will
|
116
138
|
# usually stay unset. A status of a single variable only applies to
|
@@ -121,8 +143,12 @@ module Google
|
|
121
143
|
# VARIABLE_NAME. Alternatively refers_to will be set to
|
122
144
|
# VARIABLE_VALUE. In either case variable value and members will be
|
123
145
|
# unset.
|
124
|
-
|
125
|
-
|
146
|
+
attr_accessor :status
|
147
|
+
|
148
|
+
##
|
149
|
+
# @private The original Ruby object this Breakpoint::Variable is based
|
150
|
+
# upon.
|
151
|
+
attr_accessor :source_var
|
126
152
|
|
127
153
|
##
|
128
154
|
# @private Create an empty Variable object.
|
@@ -132,22 +158,29 @@ module Google
|
|
132
158
|
|
133
159
|
##
|
134
160
|
# Convert a Ruby variable into a
|
135
|
-
# Google::Cloud::Debugger::Breakpoint::Variable object.
|
161
|
+
# Google::Cloud::Debugger::Breakpoint::Variable object. If
|
162
|
+
# a variable table is provided, it will store all the subsequently
|
163
|
+
# created compound variables into the variable table for sharing.
|
136
164
|
#
|
137
165
|
# @param [Any] source Source Ruby variable to convert from
|
138
166
|
# @param [String] name Name of the varaible
|
139
167
|
# @param [Integer] depth Number of levels to evaluate in compound
|
140
168
|
# variables. Default to
|
141
169
|
# {Google::Cloud::Debugger::Breakpoint::Variable::MAX_DEPTH}
|
170
|
+
# @param [Breakpoint::VariableTable] var_table A variable table
|
171
|
+
# to store shared compound variables. Optional.
|
172
|
+
# @param [Integer] limit Maximum number of bytes this conversion
|
173
|
+
# should take. This include nested compound member variables'
|
174
|
+
# conversions.
|
142
175
|
#
|
143
|
-
# @example
|
176
|
+
# @example Simple variable conversion
|
144
177
|
# x = 3
|
145
178
|
# var = Variable.from_rb_var x, name: "x"
|
146
179
|
# var.name #=> "x"
|
147
180
|
# var.value #=> "3"
|
148
181
|
# var.type #=> "Integer"
|
149
182
|
#
|
150
|
-
# @example
|
183
|
+
# @example Hash conversion
|
151
184
|
# hash = {a: 1, b: :two}
|
152
185
|
# var = Variable.from_rb_var hash, name: "hash"
|
153
186
|
# var.name #=> "hash"
|
@@ -159,8 +192,9 @@ module Google
|
|
159
192
|
# var.members[1].value #=> "two"
|
160
193
|
# var.members[1].type #=> "Symbol"
|
161
194
|
#
|
162
|
-
# @example
|
195
|
+
# @example Custom compound variable conversion
|
163
196
|
# foo = Foo.new(a: 1, b: []) #=> #<Foo:0x0000 @a: 1, @b: []>
|
197
|
+
# var_table = VariableTable.new
|
164
198
|
# var = Variable.from_rb_var foo, name: "foo"
|
165
199
|
# var.name #=> "foo"
|
166
200
|
# var.type #=> "Foo"
|
@@ -171,71 +205,186 @@ module Google
|
|
171
205
|
# var.members[1].value #=> "[]"
|
172
206
|
# var.members[1].type #=> "Array"
|
173
207
|
#
|
208
|
+
# @example Use variable table for shared compound variables
|
209
|
+
# hash = {a: 1}
|
210
|
+
# ary = [hash, hash]
|
211
|
+
# var_table = VariableTable.new
|
212
|
+
# var = Variable.from_rb_var ary, name: "ary", var_table: var_table
|
213
|
+
# var.name #=> "ary"
|
214
|
+
# var.var_table_index #=> 0
|
215
|
+
# var_table[0].type #=> "Array"
|
216
|
+
# var_table[0].members[0].name #=> "[0]"
|
217
|
+
# var_table[0].members[0].var_table_index #=> 1
|
218
|
+
# var_table[0].members[1].name #=> "[1]"
|
219
|
+
# var_table[0].members[1].var_table_index #=> 1
|
220
|
+
# var_table[1].type #=> "Hash"
|
221
|
+
# var_table[1].members[0].name #=> "a"
|
222
|
+
# var_table[1].members[0].type #=> "Integer"
|
223
|
+
# var_table[1].members[0].value #=> "1"
|
224
|
+
#
|
174
225
|
# @return [Google::Cloud::Debugger::Breakpoint::Variable] Converted
|
175
226
|
# variable.
|
176
227
|
#
|
177
|
-
def self.from_rb_var source, name: nil, depth: MAX_DEPTH
|
228
|
+
def self.from_rb_var source, name: nil, depth: MAX_DEPTH,
|
229
|
+
var_table: nil, limit: nil
|
178
230
|
return source if source.is_a? Variable
|
179
231
|
|
232
|
+
if limit && limit < MIN_REQUIRED_SIZE
|
233
|
+
return buffer_full_variable var_table
|
234
|
+
end
|
235
|
+
|
180
236
|
# If source is a non-empty Array or Hash, or source has instance
|
181
237
|
# variables, evaluate source as a compound variable.
|
182
|
-
if (
|
183
|
-
|
184
|
-
|
185
|
-
from_compound_var source, name: name, depth: depth
|
238
|
+
if compound_var?(source) && depth > 0
|
239
|
+
from_compound_var source, name: name, depth: depth,
|
240
|
+
var_table: var_table, limit: limit
|
186
241
|
else
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
242
|
+
new.tap do |var|
|
243
|
+
var.name = name.to_s if name
|
244
|
+
var.type = source.class.to_s
|
245
|
+
limit = deduct_limit limit,
|
246
|
+
var.name.to_s.bytesize + var.type.bytesize
|
247
|
+
var.value = truncate_value source.inspect, limit
|
248
|
+
var.source_var = source
|
249
|
+
end
|
193
250
|
end
|
194
251
|
end
|
195
252
|
|
196
253
|
##
|
197
254
|
# @private Helper method that converts compound variables.
|
198
|
-
def self.from_compound_var source, name: nil, depth: MAX_DEPTH
|
255
|
+
def self.from_compound_var source, name: nil, depth: MAX_DEPTH,
|
256
|
+
var_table: nil, limit: nil
|
199
257
|
return source if source.is_a? Variable
|
200
|
-
|
258
|
+
|
259
|
+
if limit && limit < MIN_REQUIRED_SIZE
|
260
|
+
return buffer_full_variable var_table
|
261
|
+
end
|
262
|
+
|
263
|
+
var = new
|
201
264
|
var.name = name.to_s if name
|
265
|
+
var.source_var = source
|
266
|
+
limit = deduct_limit limit, var.name.to_s.bytesize
|
267
|
+
|
268
|
+
if var_table
|
269
|
+
var.var_table = var_table
|
270
|
+
var.var_table_index =
|
271
|
+
var_table.rb_var_index(source) ||
|
272
|
+
add_shared_compound_var(source, depth, var_table, limit: limit)
|
273
|
+
else
|
274
|
+
var.type = source.class.to_s
|
275
|
+
limit = deduct_limit limit, var.type.bytesize
|
276
|
+
add_compound_members var, source, depth, limit: limit
|
277
|
+
end
|
278
|
+
var
|
279
|
+
end
|
280
|
+
|
281
|
+
##
|
282
|
+
# @private Determine if a given Ruby variable is a compound variable.
|
283
|
+
def self.compound_var? source
|
284
|
+
((source.is_a?(Hash) || source.is_a?(Array)) && !source.empty?) ||
|
285
|
+
!source.instance_variables.empty?
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# @private Add a shared compound variable to the breakpoint
|
290
|
+
# variable table.
|
291
|
+
def self.add_shared_compound_var source, depth, var_table, limit: nil
|
292
|
+
var = new
|
202
293
|
var.type = source.class.to_s
|
294
|
+
var.source_var = source
|
295
|
+
limit = deduct_limit limit, var.type.bytesize
|
296
|
+
|
297
|
+
table_index = var_table.size
|
298
|
+
var_table.add var
|
299
|
+
|
300
|
+
add_compound_members var, source, depth, var_table, limit: limit
|
203
301
|
|
302
|
+
table_index
|
303
|
+
end
|
304
|
+
|
305
|
+
##
|
306
|
+
# @private Add member variables to a compound variable.
|
307
|
+
def self.add_compound_members var, source, depth, var_table = nil,
|
308
|
+
limit: nil
|
204
309
|
case source
|
205
310
|
when Hash
|
206
|
-
|
207
|
-
from_rb_var
|
311
|
+
add_member_vars var, source, limit: limit do |(k, v), _, lmt|
|
312
|
+
from_rb_var v, name: k, depth: depth - 1, var_table: var_table,
|
313
|
+
limit: lmt
|
208
314
|
end
|
209
315
|
when Array
|
210
|
-
|
211
|
-
from_rb_var
|
316
|
+
add_member_vars var, source, limit: limit do |el, i, lmt|
|
317
|
+
from_rb_var el, name: "[#{i}]", depth: depth - 1,
|
318
|
+
var_table: var_table, limit: lmt
|
212
319
|
end
|
213
320
|
else
|
214
|
-
|
321
|
+
members = source.instance_variables
|
322
|
+
add_member_vars var, members, limit: limit do |var_name, _, lmt|
|
215
323
|
instance_var = source.instance_variable_get var_name
|
216
|
-
from_rb_var
|
324
|
+
from_rb_var instance_var, name: var_name, depth: depth - 1,
|
325
|
+
var_table: var_table, limit: lmt
|
217
326
|
end
|
218
327
|
end
|
219
|
-
var
|
220
328
|
end
|
221
329
|
|
222
330
|
##
|
223
331
|
# @private Help interate through collection of member variables for
|
224
332
|
# compound variables.
|
225
|
-
def self.
|
226
|
-
members.each_with_index do |
|
227
|
-
|
228
|
-
|
229
|
-
|
333
|
+
def self.add_member_vars var, members, limit: nil
|
334
|
+
members.each_with_index do |member, i|
|
335
|
+
member_var = yield(member, i, limit)
|
336
|
+
|
337
|
+
limit = deduct_limit limit, member_var.total_size
|
338
|
+
|
339
|
+
buffer_full = (limit && limit < 0) ||
|
340
|
+
i >= MAX_MEMBERS ||
|
341
|
+
member_var.buffer_full_variable?
|
342
|
+
|
343
|
+
if buffer_full
|
230
344
|
var.members << Variable.new.tap do |last_var|
|
231
|
-
last_var.
|
232
|
-
"
|
345
|
+
last_var.set_error_state \
|
346
|
+
"Only first #{i} items were captured. Use in " \
|
347
|
+
"an expression to see all items.",
|
348
|
+
refers_to: StatusMessage::VARIABLE_VALUE
|
233
349
|
end
|
234
350
|
break
|
351
|
+
else
|
352
|
+
var.members << member_var
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# @private Create an empty variable that points to the shared
|
359
|
+
# "Buffer Full" variable in the given variable table (always index 0)
|
360
|
+
# if a variable table is passed in. Otherwise create an error variable
|
361
|
+
# with the buffer full message.
|
362
|
+
def self.buffer_full_variable var_table = nil, name: nil
|
363
|
+
new.tap do |var|
|
364
|
+
var.name = name if name
|
365
|
+
|
366
|
+
if var_table && var_table.first &&
|
367
|
+
var_table.first.buffer_full_variable?
|
368
|
+
var.var_table = var_table
|
369
|
+
var.var_table_index = 0
|
370
|
+
else
|
371
|
+
var.set_error_state BUFFER_FULL_MSG,
|
372
|
+
refers_to: StatusMessage::VARIABLE_VALUE
|
235
373
|
end
|
236
374
|
end
|
237
375
|
end
|
238
376
|
|
377
|
+
##
|
378
|
+
# @private Helper method to calculate bytesize limit deduction.
|
379
|
+
def self.deduct_limit limit, used
|
380
|
+
limit.nil? ? nil : limit - used
|
381
|
+
end
|
382
|
+
|
383
|
+
private_class_method :add_compound_members,
|
384
|
+
:add_shared_compound_var,
|
385
|
+
:add_member_vars, :compound_var?,
|
386
|
+
:deduct_limit
|
387
|
+
|
239
388
|
##
|
240
389
|
# @private New Google::Cloud::Debugger::Breakpoint::Variable
|
241
390
|
# from a Google::Devtools::Clouddebugger::V2::Variable object.
|
@@ -246,6 +395,8 @@ module Google
|
|
246
395
|
o.value = grpc.value
|
247
396
|
o.type = grpc.type
|
248
397
|
o.members = from_grpc_list grpc.members
|
398
|
+
o.var_table_index = var_table_index_from_grpc grpc.var_table_index
|
399
|
+
o.status = Breakpoint::StatusMessage.from_grpc grpc.status
|
249
400
|
end
|
250
401
|
end
|
251
402
|
|
@@ -258,11 +409,18 @@ module Google
|
|
258
409
|
grpc_list.map { |var_grpc| from_grpc var_grpc }
|
259
410
|
end
|
260
411
|
|
412
|
+
##
|
413
|
+
# @private Extract var_table_index from the equivalent GRPC struct
|
414
|
+
def self.var_table_index_from_grpc grpc
|
415
|
+
grpc.nil? ? nil : grpc.value
|
416
|
+
end
|
417
|
+
|
261
418
|
##
|
262
419
|
# @private Limit string to MAX_STRING_LENTH. Replace extra characters
|
263
420
|
# with ellipsis
|
264
|
-
def self.truncate_value str
|
265
|
-
|
421
|
+
def self.truncate_value str, limit = nil
|
422
|
+
limit ||= MAX_STRING_LENGTH
|
423
|
+
str.gsub(/(.{#{limit - 3}}).+/, '\1...')
|
266
424
|
end
|
267
425
|
private_class_method :add_compound_members, :truncate_value
|
268
426
|
|
@@ -272,12 +430,13 @@ module Google
|
|
272
430
|
name.nil? &&
|
273
431
|
value.nil? &&
|
274
432
|
type.nil? &&
|
275
|
-
members.nil?
|
276
|
-
|
433
|
+
members.nil? &&
|
434
|
+
var_table_index.nil? &&
|
435
|
+
status.nil?
|
277
436
|
end
|
278
437
|
|
279
438
|
##
|
280
|
-
#
|
439
|
+
# Exports the Variable to a
|
281
440
|
# Google::Devtools::Clouddebugger::V2::Variable object.
|
282
441
|
def to_grpc
|
283
442
|
return nil if empty?
|
@@ -285,12 +444,125 @@ module Google
|
|
285
444
|
name: name.to_s,
|
286
445
|
value: value.to_s,
|
287
446
|
type: type.to_s,
|
288
|
-
|
447
|
+
var_table_index: var_table_index_to_grpc,
|
448
|
+
members: members_to_grpc || [],
|
449
|
+
status: status_to_grpc
|
289
450
|
)
|
290
451
|
end
|
291
452
|
|
453
|
+
##
|
454
|
+
# Set this variable to an error state by setting the status field
|
455
|
+
def set_error_state message, refers_to: StatusMessage::UNSPECIFIED
|
456
|
+
@status = StatusMessage.new.tap do |s|
|
457
|
+
s.is_error = true
|
458
|
+
s.refers_to = refers_to
|
459
|
+
s.description = message
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
##
|
464
|
+
# Calculate the total bytesize of all the attributes and that of the
|
465
|
+
# member variables, plus references into other variables in the
|
466
|
+
# variable table.
|
467
|
+
#
|
468
|
+
# @return [Integer] The total payload size of this variable in bytes.
|
469
|
+
def total_size
|
470
|
+
unless @total_size
|
471
|
+
vars = [self, *(unique_members || [])]
|
472
|
+
|
473
|
+
@total_size = vars.inject(payload_size) do |sum, var|
|
474
|
+
if var.var_table && var.var_table_index
|
475
|
+
sum + var.var_table[var.var_table_index].total_size
|
476
|
+
else
|
477
|
+
sum
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
@total_size
|
483
|
+
end
|
484
|
+
|
485
|
+
##
|
486
|
+
# Calculate the bytesize of all the attributes and that of the
|
487
|
+
# member variables.
|
488
|
+
#
|
489
|
+
# @return [Integer] The total payload size of this variable in bytes.
|
490
|
+
def payload_size
|
491
|
+
unless @payload_size
|
492
|
+
@payload_size = name.to_s.bytesize +
|
493
|
+
type.to_s.bytesize +
|
494
|
+
value.to_s.bytesize
|
495
|
+
|
496
|
+
unless members.nil?
|
497
|
+
@payload_size = members.inject(@payload_size) do |sum, member|
|
498
|
+
sum + member.payload_size
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
@payload_size
|
504
|
+
end
|
505
|
+
|
506
|
+
##
|
507
|
+
# @private Get a unique array of members that don't reference
|
508
|
+
# same object in variable table
|
509
|
+
def unique_members
|
510
|
+
seen_indices = {}
|
511
|
+
|
512
|
+
members.select do |member|
|
513
|
+
if seen_indices[member.var_table_index]
|
514
|
+
false
|
515
|
+
else
|
516
|
+
seen_indices[member.var_table_index] = true
|
517
|
+
true
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
##
|
523
|
+
# @private Whether this variable is a reference variable into
|
524
|
+
# the shared variable table or not.
|
525
|
+
def reference_variable?
|
526
|
+
value.nil? && members.empty? && !var_table_index.nil?
|
527
|
+
end
|
528
|
+
|
529
|
+
##
|
530
|
+
# @private Check if a given variable is a buffer full variable, or an
|
531
|
+
# reference variable to the shared buffer full variable
|
532
|
+
def buffer_full_variable?
|
533
|
+
if (status &&
|
534
|
+
status.description == BUFFER_FULL_MSG) ||
|
535
|
+
(var_table &&
|
536
|
+
reference_variable? &&
|
537
|
+
var_table_index.zero? &&
|
538
|
+
var_table[0] &&
|
539
|
+
var_table[0].status &&
|
540
|
+
var_table[0].status.description == BUFFER_FULL_MSG)
|
541
|
+
true
|
542
|
+
else
|
543
|
+
false
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
292
547
|
private
|
293
548
|
|
549
|
+
##
|
550
|
+
# @private Exports the Variable status to grpc
|
551
|
+
def status_to_grpc
|
552
|
+
status.nil? ? nil : status.to_grpc
|
553
|
+
end
|
554
|
+
|
555
|
+
##
|
556
|
+
# @private Exports the Variable var_table_index attribute to
|
557
|
+
# an Int32Value gRPC struct
|
558
|
+
def var_table_index_to_grpc
|
559
|
+
if var_table_index
|
560
|
+
Google::Protobuf::Int32Value.new value: var_table_index
|
561
|
+
else
|
562
|
+
nil
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
294
566
|
##
|
295
567
|
# @private Exports the Variable members to an array of
|
296
568
|
# Google::Devtools::Clouddebugger::V2::Variable objects.
|