google-cloud-debugger 0.40.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 +7 -0
- data/.yardopts +18 -0
- data/AUTHENTICATION.md +178 -0
- data/CHANGELOG.md +233 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +188 -0
- data/INSTRUMENTATION.md +115 -0
- data/LICENSE +201 -0
- data/LOGGING.md +32 -0
- data/OVERVIEW.md +266 -0
- data/TROUBLESHOOTING.md +31 -0
- data/ext/google/cloud/debugger/debugger_c/debugger.c +31 -0
- data/ext/google/cloud/debugger/debugger_c/debugger.h +26 -0
- data/ext/google/cloud/debugger/debugger_c/evaluator.c +115 -0
- data/ext/google/cloud/debugger/debugger_c/evaluator.h +25 -0
- data/ext/google/cloud/debugger/debugger_c/extconf.rb +22 -0
- data/ext/google/cloud/debugger/debugger_c/tracer.c +542 -0
- data/ext/google/cloud/debugger/debugger_c/tracer.h +25 -0
- data/lib/google-cloud-debugger.rb +181 -0
- data/lib/google/cloud/debugger.rb +259 -0
- data/lib/google/cloud/debugger/agent.rb +255 -0
- data/lib/google/cloud/debugger/backoff.rb +70 -0
- data/lib/google/cloud/debugger/breakpoint.rb +443 -0
- data/lib/google/cloud/debugger/breakpoint/evaluator.rb +1099 -0
- data/lib/google/cloud/debugger/breakpoint/source_location.rb +74 -0
- data/lib/google/cloud/debugger/breakpoint/stack_frame.rb +109 -0
- data/lib/google/cloud/debugger/breakpoint/status_message.rb +93 -0
- data/lib/google/cloud/debugger/breakpoint/validator.rb +92 -0
- data/lib/google/cloud/debugger/breakpoint/variable.rb +595 -0
- data/lib/google/cloud/debugger/breakpoint/variable_table.rb +96 -0
- data/lib/google/cloud/debugger/breakpoint_manager.rb +311 -0
- data/lib/google/cloud/debugger/credentials.rb +50 -0
- data/lib/google/cloud/debugger/debuggee.rb +222 -0
- data/lib/google/cloud/debugger/debuggee/app_uniquifier_generator.rb +76 -0
- data/lib/google/cloud/debugger/logpoint.rb +98 -0
- data/lib/google/cloud/debugger/middleware.rb +200 -0
- data/lib/google/cloud/debugger/project.rb +110 -0
- data/lib/google/cloud/debugger/rails.rb +174 -0
- data/lib/google/cloud/debugger/request_quota_manager.rb +95 -0
- data/lib/google/cloud/debugger/service.rb +88 -0
- data/lib/google/cloud/debugger/snappoint.rb +208 -0
- data/lib/google/cloud/debugger/tracer.rb +137 -0
- data/lib/google/cloud/debugger/transmitter.rb +199 -0
- data/lib/google/cloud/debugger/version.rb +22 -0
- metadata +353 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
# Copyright 2017 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/debugger/breakpoint"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Debugger
|
21
|
+
##
|
22
|
+
# # Snappoint
|
23
|
+
#
|
24
|
+
# A kind of {Google::Cloud::Debugger::Breakpoint} that can be evaluated
|
25
|
+
# to capture the state of the program at time of evaluation. This is
|
26
|
+
# essentially a {Google::Cloud::Debugger::Breakpoint} with action attrubte
|
27
|
+
# set to `:CAPTURE`
|
28
|
+
#
|
29
|
+
class Snappoint < Breakpoint
|
30
|
+
##
|
31
|
+
# Max number of top stacks to collect local variables information
|
32
|
+
STACK_EVAL_DEPTH = 5
|
33
|
+
|
34
|
+
##
|
35
|
+
# Max size of payload a Snappoint collects
|
36
|
+
MAX_PAYLOAD_SIZE = 32768 # 32KB
|
37
|
+
|
38
|
+
##
|
39
|
+
# @private Max size an evaluated expression variable is allowed to be
|
40
|
+
MAX_EXPRESSION_LIMIT = 32768 # 32KB
|
41
|
+
|
42
|
+
##
|
43
|
+
# @private Max size a normal evaluated variable is allowed to be
|
44
|
+
MAX_VAR_LIMIT = 1024 # 1KB
|
45
|
+
|
46
|
+
##
|
47
|
+
# @private Construct a new Snappoint instance.
|
48
|
+
def initialize *args
|
49
|
+
super
|
50
|
+
|
51
|
+
init_var_table
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# @private Initialize the variable table by inserting a buffer full
|
56
|
+
# variable at index 0. This variable will be shared by other variable
|
57
|
+
# evaluations if this Snappoint exceeds size limit.
|
58
|
+
def init_var_table
|
59
|
+
return if @variable_table[0] &&
|
60
|
+
@variable_table[0].buffer_full_variable?
|
61
|
+
|
62
|
+
buffer_full_var = Variable.buffer_full_variable
|
63
|
+
@variable_table.variables.unshift buffer_full_var
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Evaluate the breakpoint unless it's already marked as completed.
|
68
|
+
# Store evaluted expressions and stack frame variables in
|
69
|
+
# @evaluated_expressions, @stack_frames. Mark breakpoint complete if
|
70
|
+
# successfully evaluated.
|
71
|
+
#
|
72
|
+
# @param [Array<Binding>] call_stack_bindings An array of Ruby Binding
|
73
|
+
# objects, from the call stack that leads to the triggering of the
|
74
|
+
# breakpoints.
|
75
|
+
#
|
76
|
+
# @return [Boolean] True if evaluated successfully; false otherwise.
|
77
|
+
#
|
78
|
+
def evaluate call_stack_bindings
|
79
|
+
synchronize do
|
80
|
+
top_binding = call_stack_bindings[0]
|
81
|
+
|
82
|
+
return false if complete? || !check_condition(top_binding)
|
83
|
+
|
84
|
+
begin
|
85
|
+
eval_expressions top_binding
|
86
|
+
eval_call_stack call_stack_bindings
|
87
|
+
|
88
|
+
complete
|
89
|
+
rescue StandardError
|
90
|
+
return false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# @private Evaluates the breakpoint expressions at the point that
|
99
|
+
# triggered the breakpoint. The expressions subject to the read-only
|
100
|
+
# rules. If the expressions do any write operations, the evaluations
|
101
|
+
# abort and show an error message in place of the real result.
|
102
|
+
#
|
103
|
+
# @param [Binding] bind The binding object from the context
|
104
|
+
#
|
105
|
+
def eval_expressions bind
|
106
|
+
@evaluated_expressions = []
|
107
|
+
|
108
|
+
expressions.each do |expression|
|
109
|
+
eval_result = Evaluator.readonly_eval_expression bind, expression
|
110
|
+
|
111
|
+
if eval_result.is_a?(Exception) &&
|
112
|
+
eval_result.instance_variable_get(:@mutation_cause)
|
113
|
+
evaluated_var = Variable.new
|
114
|
+
evaluated_var.name = expression
|
115
|
+
evaluated_var.set_error_state \
|
116
|
+
"Error: #{eval_result.message}",
|
117
|
+
refers_to: StatusMessage::VARIABLE_VALUE
|
118
|
+
else
|
119
|
+
evaluated_var = convert_variable eval_result,
|
120
|
+
name: expression,
|
121
|
+
limit: MAX_EXPRESSION_LIMIT
|
122
|
+
end
|
123
|
+
|
124
|
+
@evaluated_expressions << evaluated_var
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# @private Evaluates call stack. Collects function name and location of
|
130
|
+
# each frame from given binding objects. Collects local variable
|
131
|
+
# information from top frames.
|
132
|
+
#
|
133
|
+
# @param [Array<Binding>] call_stack_bindings A list of binding
|
134
|
+
# objects that come from each of the call stack frames.
|
135
|
+
# @return [Array<Google::Cloud::Debugger::Breakpoint::StackFrame>]
|
136
|
+
# A list of StackFrame objects that represent state of the
|
137
|
+
# call stack
|
138
|
+
#
|
139
|
+
def eval_call_stack call_stack_bindings
|
140
|
+
@stack_frames = []
|
141
|
+
|
142
|
+
call_stack_bindings.each_with_index do |frame_binding, i|
|
143
|
+
frame_info = StackFrame.new.tap do |sf|
|
144
|
+
sf.function = frame_binding.eval("__method__").to_s
|
145
|
+
sf.location = SourceLocation.new.tap do |l|
|
146
|
+
l.path =
|
147
|
+
frame_binding.eval "::File.absolute_path(__FILE__)"
|
148
|
+
l.line = frame_binding.eval "__LINE__"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
@stack_frames << frame_info
|
153
|
+
|
154
|
+
next if i >= STACK_EVAL_DEPTH
|
155
|
+
|
156
|
+
frame_binding.local_variables.each do |local_var_name|
|
157
|
+
local_var = frame_binding.local_variable_get local_var_name
|
158
|
+
var = convert_variable local_var, name: local_var_name,
|
159
|
+
limit: MAX_VAR_LIMIT
|
160
|
+
|
161
|
+
frame_info.locals << var
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
##
|
169
|
+
# @private Compute the total size of all the evaluated variables in
|
170
|
+
# this breakpoint.
|
171
|
+
def calculate_total_size
|
172
|
+
result = evaluated_expressions.inject 0 do |sum, exp|
|
173
|
+
sum + exp.payload_size
|
174
|
+
end
|
175
|
+
|
176
|
+
stack_frames.each do |stack_frame|
|
177
|
+
result = stack_frame.locals.inject result do |sum, local|
|
178
|
+
sum + local.payload_size
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
result = variable_table.variables.inject result do |sum, var|
|
183
|
+
sum + var.payload_size
|
184
|
+
end
|
185
|
+
|
186
|
+
result
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# @private Translate a Ruby variable into a {Breakpoint::Variable}.
|
191
|
+
# If the existing evaluated variables already exceed maximum allowed
|
192
|
+
# size, then return a buffer full warning variable instead.
|
193
|
+
def convert_variable source, name: nil, limit: nil
|
194
|
+
current_total_size = calculate_total_size
|
195
|
+
var = Variable.from_rb_var source, name: name, limit: limit,
|
196
|
+
var_table: variable_table
|
197
|
+
|
198
|
+
if (current_total_size + var.payload_size <= MAX_PAYLOAD_SIZE) ||
|
199
|
+
var.reference_variable?
|
200
|
+
var
|
201
|
+
else
|
202
|
+
Breakpoint::Variable.buffer_full_variable variable_table, name: name
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Copyright 2017 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "binding_of_caller"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Debugger
|
21
|
+
##
|
22
|
+
# # Tracer
|
23
|
+
#
|
24
|
+
# When active breakpoints are set for the debugger, the tracer monitors
|
25
|
+
# the running Ruby application and triggers evaluation when the code is
|
26
|
+
# executed at the breakpoint locations.
|
27
|
+
#
|
28
|
+
# The tracer tracks the running application using several Ruby TracePoints
|
29
|
+
# and C level Ruby debugging API.
|
30
|
+
#
|
31
|
+
class Tracer
|
32
|
+
##
|
33
|
+
# The debugger agent this tracer belongs to
|
34
|
+
# @return [Google::Cloud::Debugger::Agent]
|
35
|
+
attr_reader :agent
|
36
|
+
|
37
|
+
##
|
38
|
+
# @private File tracing point that enables line tracing when program
|
39
|
+
# counter enters a file that contains breakpoints
|
40
|
+
attr_reader :file_tracepoint
|
41
|
+
|
42
|
+
##
|
43
|
+
# @private Fiber tracing point that enables line tracing when program
|
44
|
+
# counter enters a file that contains breakpoints through fiber
|
45
|
+
# switching
|
46
|
+
attr_reader :fiber_tracepoint
|
47
|
+
|
48
|
+
##
|
49
|
+
# @private A nested hash structure represent all the active breakpoints.
|
50
|
+
# The structure is optimized for fast access. For example:
|
51
|
+
# {
|
52
|
+
# "path/to/file.rb" => { # The absolute file path
|
53
|
+
# 123 => [ # The line number in file
|
54
|
+
# <Google::Cloud::Debugger::Breakpoint> # List of breakpoints
|
55
|
+
# ]
|
56
|
+
# }
|
57
|
+
# }
|
58
|
+
attr_reader :breakpoints_cache
|
59
|
+
|
60
|
+
##
|
61
|
+
# @private Construct a new instance of Tracer
|
62
|
+
def initialize agent
|
63
|
+
@agent = agent
|
64
|
+
@file_tracepoint = nil
|
65
|
+
@fiber_tracepoint = nil
|
66
|
+
@breakpoints_cache = {}
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Update tracer's private breakpoints cache with the list of active
|
71
|
+
# breakpoints from BreakpointManager.
|
72
|
+
#
|
73
|
+
# This methood is atomic for thread safety purpose.
|
74
|
+
def update_breakpoints_cache
|
75
|
+
active_breakpoints = agent.breakpoint_manager.active_breakpoints.dup
|
76
|
+
breakpoints_hash = {}
|
77
|
+
|
78
|
+
active_breakpoints.each do |active_breakpoint|
|
79
|
+
breakpoint_line = active_breakpoint.line
|
80
|
+
breakpoint_path = active_breakpoint.full_path
|
81
|
+
breakpoints_hash[breakpoint_path] ||= {}
|
82
|
+
breakpoints_hash[breakpoint_path][breakpoint_line] ||= []
|
83
|
+
breakpoints_hash[breakpoint_path][breakpoint_line].push(
|
84
|
+
active_breakpoint
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Tracer is explicitly designed to not have a lock. This should be the
|
89
|
+
# only place writing @breakpoints_cache to ensure thread safety.
|
90
|
+
@breakpoints_cache = breakpoints_hash
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Callback function when a set of breakpoints are hit. Handover the hit
|
95
|
+
# breakpoint to breakpoint_manager to be evaluated.
|
96
|
+
def breakpoints_hit breakpoints, call_stack_bindings
|
97
|
+
breakpoints.each do |breakpoint|
|
98
|
+
# Stop evaluating breakpoints if we have quotas and the quotas are
|
99
|
+
# met.
|
100
|
+
break if agent.quota_manager && !agent.quota_manager.more?
|
101
|
+
|
102
|
+
next if breakpoint.nil? || breakpoint.complete?
|
103
|
+
|
104
|
+
time_begin = Time.now
|
105
|
+
|
106
|
+
agent.breakpoint_manager.breakpoint_hit breakpoint,
|
107
|
+
call_stack_bindings
|
108
|
+
|
109
|
+
# Report time and resource consumption to quota manager
|
110
|
+
if agent.quota_manager.respond_to? :consume
|
111
|
+
agent.quota_manager.consume time: Time.now - time_begin
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
update_breakpoints_cache
|
116
|
+
|
117
|
+
# Disable all trace points and tracing if all breakpoints are complete
|
118
|
+
disable_traces if @breakpoints_cache.empty?
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Get the sync the breakpoints cache with BreakpointManager. Start
|
123
|
+
# tracing and monitoring if there are any breakpoints.
|
124
|
+
def start
|
125
|
+
update_breakpoints_cache
|
126
|
+
enable_traces unless breakpoints_cache.empty?
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Stops all tracing.
|
131
|
+
def stop
|
132
|
+
disable_traces
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# Copyright 2017 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "concurrent"
|
17
|
+
require "google/cloud/errors"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Debugger
|
22
|
+
##
|
23
|
+
# # TransmitterError
|
24
|
+
#
|
25
|
+
# Used to indicate a problem submitting breakpoints. This can occur when
|
26
|
+
# there are not enough resources allocated for the amount of usage, or
|
27
|
+
# when the calling the API returns an error.
|
28
|
+
#
|
29
|
+
class TransmitterError < Google::Cloud::Error
|
30
|
+
# @!attribute [r] breakpoint
|
31
|
+
# @return [Array<Google::Cloud::Debugger::Breakpoint>] The
|
32
|
+
# individual error event that was not submitted to Stackdriver
|
33
|
+
# Debugger service.
|
34
|
+
attr_reader :breakpoint
|
35
|
+
|
36
|
+
def initialize message, breakpoint = nil
|
37
|
+
super message
|
38
|
+
@breakpoint = breakpoint
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# # Transmitter
|
44
|
+
#
|
45
|
+
# Responsible for submit evaluated breakpoints back to Stackdriver
|
46
|
+
# Debugger service asynchronously. It maintains a thread pool.
|
47
|
+
#
|
48
|
+
# The transmitter is controlled by the debugger agent it belongs to.
|
49
|
+
# Debugger agent submits evaluated breakpoint asynchronously, and the
|
50
|
+
# transmitter submits the breakpoints to Stackdriver Debugger service.
|
51
|
+
#
|
52
|
+
class Transmitter
|
53
|
+
##
|
54
|
+
# @private The gRPC Service object and thread pool.
|
55
|
+
attr_reader :service, :thread_pool
|
56
|
+
|
57
|
+
##
|
58
|
+
# The debugger agent this transmiter belongs to
|
59
|
+
# @return [Google::Cloud::Debugger::Agent]
|
60
|
+
attr_accessor :agent
|
61
|
+
|
62
|
+
##
|
63
|
+
# Maximum backlog size for this transmitter's queue
|
64
|
+
attr_accessor :max_queue
|
65
|
+
alias max_queue_size max_queue
|
66
|
+
alias max_queue_size= max_queue=
|
67
|
+
|
68
|
+
##
|
69
|
+
# Maximum threads used in the thread pool
|
70
|
+
attr_accessor :threads
|
71
|
+
|
72
|
+
##
|
73
|
+
# @private Creates a new Transmitter instance.
|
74
|
+
def initialize agent, service, max_queue: 1000, threads: 10
|
75
|
+
@agent = agent
|
76
|
+
@service = service
|
77
|
+
|
78
|
+
@max_queue = max_queue
|
79
|
+
@threads = threads
|
80
|
+
|
81
|
+
@thread_pool = Concurrent::ThreadPoolExecutor.new \
|
82
|
+
max_threads: @threads, max_queue: @max_queue
|
83
|
+
|
84
|
+
@error_callbacks = []
|
85
|
+
|
86
|
+
# Make sure all queued calls are completed when process exits.
|
87
|
+
at_exit { stop }
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Enqueue an evaluated breakpoint to be submitted by the transmitter.
|
92
|
+
#
|
93
|
+
# @raise [TransmitterError] if there are no resources available to make
|
94
|
+
# queue the API call on the thread pool.
|
95
|
+
def submit breakpoint
|
96
|
+
Concurrent::Promises.future_on @thread_pool, breakpoint do |bp|
|
97
|
+
submit_sync bp
|
98
|
+
end
|
99
|
+
rescue Concurrent::RejectedExecutionError => e
|
100
|
+
raise TransmitterError.new(
|
101
|
+
"Error asynchronously submitting breakpoint: #{e.message}",
|
102
|
+
breakpoint
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Starts the transmitter and its thread pool.
|
108
|
+
#
|
109
|
+
# @return [Transmitter] returns self so calls can be chained.
|
110
|
+
def start
|
111
|
+
# no-op
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Stops the transmitter and its thread pool. Once stopped, cannot be
|
117
|
+
# started again.
|
118
|
+
#
|
119
|
+
# @return [Transmitter] returns self so calls can be chained.
|
120
|
+
def stop timeout = nil
|
121
|
+
if @thread_pool
|
122
|
+
@thread_pool.shutdown
|
123
|
+
@thread_pool.wait_for_termination timeout
|
124
|
+
end
|
125
|
+
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Whether the transmitter has been started.
|
131
|
+
#
|
132
|
+
# @return [boolean] `true` when started, `false` otherwise.
|
133
|
+
#
|
134
|
+
def started?
|
135
|
+
@thread_pool.running? if @thread_pool
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Whether the transmitter has been stopped.
|
140
|
+
#
|
141
|
+
# @return [boolean] `true` when stopped, `false` otherwise.
|
142
|
+
#
|
143
|
+
def stopped?
|
144
|
+
!started?
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Register to be notified of errors when raised.
|
149
|
+
#
|
150
|
+
# If an unhandled error has occurred the transmitter will attempt to
|
151
|
+
# recover from the error and resume submitting breakpoints.
|
152
|
+
#
|
153
|
+
# Multiple error handlers can be added.
|
154
|
+
#
|
155
|
+
# @yield [callback] The block to be called when an error is raised.
|
156
|
+
# @yieldparam [Exception] error The error raised.
|
157
|
+
#
|
158
|
+
def on_error &block
|
159
|
+
@error_callbacks << block
|
160
|
+
end
|
161
|
+
|
162
|
+
protected
|
163
|
+
|
164
|
+
# Calls all error callbacks.
|
165
|
+
def error! error
|
166
|
+
error_callbacks = @error_callbacks
|
167
|
+
error_callbacks = default_error_callbacks if error_callbacks.empty?
|
168
|
+
error_callbacks.each { |error_callback| error_callback.call error }
|
169
|
+
end
|
170
|
+
|
171
|
+
def default_error_callbacks
|
172
|
+
# This is memoized to reduce calls to the configuration.
|
173
|
+
@default_error_callbacks ||= begin
|
174
|
+
error_cb = Google::Cloud::Debugger.configure.on_error
|
175
|
+
error_cb ||= Google::Cloud.configure.on_error
|
176
|
+
if error_cb
|
177
|
+
[error_cb]
|
178
|
+
else
|
179
|
+
[]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def submit_sync breakpoint
|
185
|
+
service.update_active_breakpoint agent.debuggee.id, breakpoint
|
186
|
+
rescue StandardError => e
|
187
|
+
sync_error = TransmitterError.new(
|
188
|
+
"Error asynchronously transmitting breakpoint: #{e.message}",
|
189
|
+
breakpoint
|
190
|
+
)
|
191
|
+
# Manually set backtrace so we don't have to raise
|
192
|
+
sync_error.set_backtrace caller
|
193
|
+
|
194
|
+
error! sync_error
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|