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,222 @@
|
|
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 "digest/sha1"
|
17
|
+
require "google/cloud/debugger/backoff"
|
18
|
+
require "google/cloud/debugger/debuggee/app_uniquifier_generator"
|
19
|
+
require "google/cloud/debugger/version"
|
20
|
+
require "google/cloud/env"
|
21
|
+
require "json"
|
22
|
+
|
23
|
+
module Google
|
24
|
+
module Cloud
|
25
|
+
module Debugger
|
26
|
+
##
|
27
|
+
# # Debuggee
|
28
|
+
#
|
29
|
+
# Represent a debuggee application. Contains information that identifies
|
30
|
+
# debuggee applications from each other. Maps to gRPC struct
|
31
|
+
# Google::Cloud::Debugger::V2::Debuggee.
|
32
|
+
#
|
33
|
+
# It also automatically loads source context information generated from
|
34
|
+
# Cloud SDK. See [Stackdriver Debugger
|
35
|
+
# doc](https://cloud.google.com/debugger/docs/source-context#app_engine_standard_python)
|
36
|
+
# for more information on how to generate this source context information
|
37
|
+
# when used on Google Container Engine and Google Compute engine. This
|
38
|
+
# step is taken care of if debuggee application is hosted on Google App
|
39
|
+
# Engine Flexibile.
|
40
|
+
#
|
41
|
+
# To ensure the multiple instances of the application are indeed the same
|
42
|
+
# application, the debuggee also compute a "uniquifier" generated from
|
43
|
+
# source context or application source code.
|
44
|
+
#
|
45
|
+
class Debuggee
|
46
|
+
##
|
47
|
+
# @private The gRPC Service object.
|
48
|
+
attr_reader :service
|
49
|
+
|
50
|
+
##
|
51
|
+
# Name for the debuggee application
|
52
|
+
# @return [String]
|
53
|
+
attr_reader :service_name
|
54
|
+
|
55
|
+
##
|
56
|
+
# Version identifier for the debuggee application
|
57
|
+
# @return [String]
|
58
|
+
attr_reader :service_version
|
59
|
+
|
60
|
+
##
|
61
|
+
# Registered Debuggee ID. Set by Stackdriver Debugger service when
|
62
|
+
# a debuggee application is sucessfully registered.
|
63
|
+
# @return [String]
|
64
|
+
attr_reader :id
|
65
|
+
|
66
|
+
##
|
67
|
+
# @private Construct a new instance of Debuggee
|
68
|
+
def initialize service, service_name:, service_version:
|
69
|
+
@service = service
|
70
|
+
@service_name = service_name
|
71
|
+
@service_version = service_version
|
72
|
+
@env = Google::Cloud.env
|
73
|
+
@computed_uniquifier = nil
|
74
|
+
@id = nil
|
75
|
+
@register_backoff = Google::Cloud::Debugger::Backoff.new
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Register the current application as a debuggee with Stackdriver
|
80
|
+
# Debuggee service.
|
81
|
+
# @return [Boolean] True if registered sucessfully; otherwise false.
|
82
|
+
def register
|
83
|
+
# Wait if backoff applies
|
84
|
+
sleep @register_backoff.interval if @register_backoff.backing_off?
|
85
|
+
|
86
|
+
begin
|
87
|
+
response = service.register_debuggee to_grpc
|
88
|
+
@id = response.debuggee.id
|
89
|
+
rescue StandardError
|
90
|
+
revoke_registration
|
91
|
+
end
|
92
|
+
|
93
|
+
registered = registered?
|
94
|
+
registered ? @register_backoff.succeeded : @register_backoff.failed
|
95
|
+
|
96
|
+
registered
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Check whether this debuggee is currently registered or not
|
101
|
+
# @return [Boolean] True if debuggee is registered; otherwise false.
|
102
|
+
def registered?
|
103
|
+
!id.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Revoke the registration of this debuggee
|
108
|
+
def revoke_registration
|
109
|
+
@id = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Convert this debuggee into a gRPC
|
114
|
+
# Google::Cloud::Debugger::V2::Debuggee struct.
|
115
|
+
def to_grpc
|
116
|
+
source_context = source_context_from_json_file "source-context.json"
|
117
|
+
Google::Cloud::Debugger::V2::Debuggee.new(
|
118
|
+
id: id.to_s,
|
119
|
+
project: project_id_for_request_arg.to_s,
|
120
|
+
description: description.to_s,
|
121
|
+
labels: labels,
|
122
|
+
agent_version: agent_version.to_s
|
123
|
+
).tap do |d|
|
124
|
+
if source_context
|
125
|
+
d.source_contexts << source_context
|
126
|
+
d.ext_source_contexts << ext_source_context_grpc(source_context)
|
127
|
+
end
|
128
|
+
d.uniquifier = compute_uniquifier d
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def source_context_from_json_file file_path
|
135
|
+
json = File.read file_path
|
136
|
+
Devtools::Source::V1::SourceContext.decode_json json
|
137
|
+
rescue StandardError
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def ext_source_context_grpc source_context
|
142
|
+
Devtools::Source::V1::SourceContext.new context: source_context
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# @private Build labels hash for this debuggee
|
147
|
+
def labels
|
148
|
+
{
|
149
|
+
"projectid" => String(project_id),
|
150
|
+
"module" => String(service_name),
|
151
|
+
"version" => String(service_version)
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# @private Build description string for this debuggee. In
|
157
|
+
# "<module name> - <module version>" format. Or just the module
|
158
|
+
# version if module name is missing.
|
159
|
+
#
|
160
|
+
# @return [String] A compact debuggee description.
|
161
|
+
#
|
162
|
+
def description
|
163
|
+
if service_version.nil? || service_version.empty?
|
164
|
+
service_name
|
165
|
+
else
|
166
|
+
"#{service_name} - #{service_version}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# @private Get debuggee project id
|
172
|
+
def project_id
|
173
|
+
service.project
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# @private
|
178
|
+
# Get project to send as a debuggee argument. This is the numeric
|
179
|
+
# project ID if available (and if it matches the project set in the
|
180
|
+
# configuration). Otherwise, use the configured project.
|
181
|
+
def project_id_for_request_arg
|
182
|
+
if project_id == @env.lookup_metadata("project", "project-id")
|
183
|
+
numeric_id = @env.numeric_project_id
|
184
|
+
return numeric_id.to_s if numeric_id
|
185
|
+
end
|
186
|
+
project_id
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# @private Build debuggee agent version identifier
|
191
|
+
def agent_version
|
192
|
+
"google.com/ruby#{RUBY_VERSION}-#{Google::Cloud::Debugger::VERSION}"
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# @private Generate a debuggee uniquifier from source context
|
197
|
+
# information or application source code
|
198
|
+
def compute_uniquifier partial_debuggee
|
199
|
+
return @computed_uniquifier if @computed_uniquifier
|
200
|
+
|
201
|
+
sha = Digest::SHA1.new
|
202
|
+
sha << partial_debuggee.to_s
|
203
|
+
|
204
|
+
if partial_debuggee.source_contexts.empty? &&
|
205
|
+
partial_debuggee.ext_source_contexts.empty?
|
206
|
+
AppUniquifierGenerator.generate_app_uniquifier sha
|
207
|
+
end
|
208
|
+
|
209
|
+
@computed_uniquifier = sha.hexdigest
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# @private Helper method to parse json file
|
214
|
+
def read_app_json_file file_path
|
215
|
+
JSON.parse File.read(file_path), symbolize_names: true
|
216
|
+
rescue StandardError
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,76 @@
|
|
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 "pathname"
|
17
|
+
require "set"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Debugger
|
22
|
+
class Debuggee
|
23
|
+
##
|
24
|
+
# Generates an application debuggee uniquifier by hashing the
|
25
|
+
# application file stats.
|
26
|
+
#
|
27
|
+
module AppUniquifierGenerator
|
28
|
+
##
|
29
|
+
# Max number of directory levels the generator looks into.
|
30
|
+
MAX_DEPTH = 10
|
31
|
+
|
32
|
+
##
|
33
|
+
# Computes the application uniquifier by examine the file stats of
|
34
|
+
# the files in the given application root directory. It only looks at
|
35
|
+
# .rb files and Gemfile.lock
|
36
|
+
#
|
37
|
+
# @param [Digest::SHA] sha A digest SHA object used to add the hashing
|
38
|
+
# values
|
39
|
+
# @param [String] app_path Application root directory where the Ruby
|
40
|
+
# application is located.
|
41
|
+
#
|
42
|
+
# @return [NilClass]
|
43
|
+
#
|
44
|
+
def self.generate_app_uniquifier sha, app_path = nil
|
45
|
+
app_path ||= if defined?(::Rack::Directory)
|
46
|
+
Rack::Directory.new("").root
|
47
|
+
else
|
48
|
+
Dir.getwd
|
49
|
+
end
|
50
|
+
|
51
|
+
process_directory sha, app_path
|
52
|
+
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @private Recursively parse files and directories.
|
58
|
+
def self.process_directory sha, path, depth = 1
|
59
|
+
return if depth > MAX_DEPTH
|
60
|
+
|
61
|
+
pathname = Pathname.new path
|
62
|
+
pathname.each_child do |entry|
|
63
|
+
if entry.directory?
|
64
|
+
process_directory sha, entry, depth + 1
|
65
|
+
else
|
66
|
+
next unless entry.extname == ".rb" ||
|
67
|
+
entry.basename.to_s == "Gemfile.lock"
|
68
|
+
sha << "#{entry.expand_path}:#{entry.stat.size}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,98 @@
|
|
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
|
+
# # Logpoint
|
23
|
+
#
|
24
|
+
# A kind of {Google::Cloud::Debugger::Breakpoint} that can be evaluated
|
25
|
+
# to generate a formatted log string, which later can be submitted to
|
26
|
+
# Stackdriver Logging service
|
27
|
+
#
|
28
|
+
class Logpoint < Breakpoint
|
29
|
+
##
|
30
|
+
# Evaluate the breakpoint unless it's already marked as completed.
|
31
|
+
# Store evaluted expressions and stack frame variables in
|
32
|
+
# `@evaluated_expressions` and `@evaluated_log_message`.
|
33
|
+
#
|
34
|
+
# @param [Array<Binding>] call_stack_bindings An array of Ruby Binding
|
35
|
+
# objects, from the call stack that leads to the triggering of the
|
36
|
+
# breakpoints.
|
37
|
+
#
|
38
|
+
# @return [Boolean] True if evaluated successfully; false otherwise.
|
39
|
+
#
|
40
|
+
def evaluate call_stack_bindings
|
41
|
+
synchronize do
|
42
|
+
binding = call_stack_bindings[0]
|
43
|
+
|
44
|
+
return false if complete? || !check_condition(binding)
|
45
|
+
|
46
|
+
begin
|
47
|
+
evaluate_log_message binding
|
48
|
+
rescue StandardError
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @private Evaluate the expressions and log message. Store the result
|
58
|
+
# in @evaluated_log_message
|
59
|
+
def evaluate_log_message binding
|
60
|
+
evaluated_expressions = expressions.map do |expression|
|
61
|
+
Evaluator.readonly_eval_expression binding, expression
|
62
|
+
end
|
63
|
+
|
64
|
+
@evaluated_log_message =
|
65
|
+
format_message log_message_format, evaluated_expressions
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# @private Format log message by interpolate expressions.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# log_point = Google::Cloud::Debugger::Logpoint.new
|
73
|
+
# log_point.format_message(
|
74
|
+
# "Hello $0", ["World"]) #=> "Hello \"World\""
|
75
|
+
#
|
76
|
+
# @param [String] message_format The message with with
|
77
|
+
# expression placeholders such as `$0`, `$1`, etc.
|
78
|
+
# @param [Array<Google::Cloud::Debugger::Breakpoint::Variable>]
|
79
|
+
# expressions An array of evaluated expression variables to be
|
80
|
+
# placed into message_format's placeholders. The variables need
|
81
|
+
# to have type equal String.
|
82
|
+
#
|
83
|
+
# @return [String] The formatted message string
|
84
|
+
#
|
85
|
+
def format_message message_format, expressions
|
86
|
+
# Substitute placeholders with expressions
|
87
|
+
message = message_format.gsub(/(?<!\$)\$\d+/) do |placeholder|
|
88
|
+
index = placeholder.match(/\$(\d+)/)[1].to_i
|
89
|
+
index < expressions.size ? expressions[index].inspect : ""
|
90
|
+
end
|
91
|
+
|
92
|
+
# Unescape "$" characters
|
93
|
+
message.gsub(/\$\$/, "$")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,200 @@
|
|
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 "set"
|
17
|
+
|
18
|
+
require "google/cloud/logging/logger"
|
19
|
+
require "google/cloud/debugger/request_quota_manager"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
module Debugger
|
24
|
+
##
|
25
|
+
# Rack Middleware implementation that supports Stackdriver Debugger Agent
|
26
|
+
# in Rack-based Ruby frameworks. It instantiates a new debugger agent if
|
27
|
+
# one isn't given already. It helps optimize Debugger Agent Tracer
|
28
|
+
# performance by suspending and resuming the tracer between each request.
|
29
|
+
#
|
30
|
+
# To use this middleware, simply install it in your Rack configuration.
|
31
|
+
# The middleware will take care of registering itself with the
|
32
|
+
# Stackdriver Debugger and activating the debugger agent. The location
|
33
|
+
# of the middleware in the middleware stack matters: breakpoints will be
|
34
|
+
# detected in middleware appearing after but not before this middleware.
|
35
|
+
#
|
36
|
+
# For best results, you should also call {Middleware.start_agents}
|
37
|
+
# during application initialization. See its documentation for details.
|
38
|
+
#
|
39
|
+
class Middleware
|
40
|
+
##
|
41
|
+
# Reset deferred start mechanism.
|
42
|
+
# @private
|
43
|
+
#
|
44
|
+
def self.reset_deferred_start
|
45
|
+
@debuggers_to_start = Set.new
|
46
|
+
end
|
47
|
+
|
48
|
+
reset_deferred_start
|
49
|
+
|
50
|
+
##
|
51
|
+
# Start the debugger. Either adds it to the deferred list, or, if the
|
52
|
+
# deferred list has already been started, starts immediately.
|
53
|
+
#
|
54
|
+
# @param [Google::Cloud::Debugger::Project] debugger
|
55
|
+
#
|
56
|
+
# @private
|
57
|
+
#
|
58
|
+
def self.deferred_start debugger
|
59
|
+
if @debuggers_to_start
|
60
|
+
@debuggers_to_start << debugger
|
61
|
+
else
|
62
|
+
debugger.start
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# This should be called once the application determines that it is safe
|
68
|
+
# to start background threads and open gRPC connections. It informs
|
69
|
+
# the middleware system that it can start debugger agents.
|
70
|
+
#
|
71
|
+
# Generally, this matters if the application forks worker processes;
|
72
|
+
# this method should be called only after workers are forked, since
|
73
|
+
# threads and network connections interact badly with fork. For
|
74
|
+
# example, when running Puma in
|
75
|
+
# [clustered mode](https://github.com/puma/puma#clustered-mode), this
|
76
|
+
# method should be called in an `on_worker_boot` block.
|
77
|
+
#
|
78
|
+
# If the application does no forking, this method can be called any
|
79
|
+
# time early in the application initialization process.
|
80
|
+
#
|
81
|
+
# If {Middleware.start_agents} is never called, the debugger agent will
|
82
|
+
# be started when the first request is received. This should be safe,
|
83
|
+
# but it will probably mean breakpoints will not be recognized during
|
84
|
+
# that first request. For best results, an application should call this
|
85
|
+
# method at the appropriate time.
|
86
|
+
#
|
87
|
+
def self.start_agents
|
88
|
+
return unless @debuggers_to_start
|
89
|
+
@debuggers_to_start.each(&:start)
|
90
|
+
@debuggers_to_start = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Create a new Debugger Middleware.
|
95
|
+
#
|
96
|
+
# @param [Rack Application] app Rack application
|
97
|
+
# @param [Google::Cloud::Debugger::Project] debugger A debugger to be
|
98
|
+
# used by this middleware. If not given, will construct a new one
|
99
|
+
# using the other parameters.
|
100
|
+
# @param [Hash] kwargs Hash of configuration settings. Used for backward
|
101
|
+
# API compatibility. See the [Configuration
|
102
|
+
# Guide](https://googleapis.dev/ruby/stackdriver/latest/file.INSTRUMENTATION_CONFIGURATION.html)
|
103
|
+
# for the prefered way to set configuration parameters.
|
104
|
+
#
|
105
|
+
# @return [Google::Cloud::Debugger::Middleware] A new
|
106
|
+
# Google::Cloud::Debugger::Middleware instance
|
107
|
+
#
|
108
|
+
def initialize app, debugger: nil, **kwargs
|
109
|
+
@app = app
|
110
|
+
|
111
|
+
load_config kwargs
|
112
|
+
|
113
|
+
if debugger
|
114
|
+
@debugger = debugger
|
115
|
+
else
|
116
|
+
@debugger =
|
117
|
+
Debugger.new(project_id: configuration.project_id,
|
118
|
+
credentials: configuration.credentials,
|
119
|
+
service_name: configuration.service_name,
|
120
|
+
service_version: configuration.service_version)
|
121
|
+
|
122
|
+
@debugger.agent.quota_manager =
|
123
|
+
Google::Cloud::Debugger::RequestQuotaManager.new
|
124
|
+
end
|
125
|
+
|
126
|
+
Middleware.deferred_start @debugger
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Rack middleware entry point. In most Rack based frameworks, a request
|
131
|
+
# is served by one thread. It enables/resume the debugger breakpoints
|
132
|
+
# tracing and stops/pauses the tracing afterwards to help improve
|
133
|
+
# debugger performance.
|
134
|
+
#
|
135
|
+
# @param [Hash] env Rack environment hash
|
136
|
+
#
|
137
|
+
# @return [Rack::Response] The response from downstream Rack app
|
138
|
+
#
|
139
|
+
def call env
|
140
|
+
# Ensure the agent is running. (Note the start method is idempotent.)
|
141
|
+
@debugger.start
|
142
|
+
|
143
|
+
# Enable/resume breakpoints tracing
|
144
|
+
@debugger.agent.tracer.start
|
145
|
+
|
146
|
+
# Use Stackdriver Logger for debugger if available
|
147
|
+
if env["rack.logger"].is_a? Google::Cloud::Logging::Logger
|
148
|
+
@debugger.agent.logger = env["rack.logger"]
|
149
|
+
end
|
150
|
+
|
151
|
+
@app.call env
|
152
|
+
ensure
|
153
|
+
# Stop breakpoints tracing beyond this point
|
154
|
+
@debugger.agent.tracer.disable_traces_for_thread
|
155
|
+
|
156
|
+
# Reset quotas after each request finishes.
|
157
|
+
@debugger.agent.quota_manager.reset if @debugger.agent.quota_manager
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
##
|
163
|
+
# Consolidate configurations from various sources. Also set
|
164
|
+
# instrumentation config parameters to default values if not set
|
165
|
+
# already.
|
166
|
+
#
|
167
|
+
def load_config **kwargs
|
168
|
+
project_id = kwargs[:project] || kwargs[:project_id]
|
169
|
+
configuration.project_id = project_id unless project_id.nil?
|
170
|
+
|
171
|
+
creds = kwargs[:credentials] || kwargs[:keyfile]
|
172
|
+
configuration.credentials = creds unless creds.nil?
|
173
|
+
|
174
|
+
service_name = kwargs[:service_name]
|
175
|
+
configuration.service_name = service_name unless service_name.nil?
|
176
|
+
|
177
|
+
service_vers = kwargs[:service_version]
|
178
|
+
configuration.service_version = service_vers unless service_vers.nil?
|
179
|
+
|
180
|
+
init_default_config
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# Fallback to default configuration values if not defined already
|
185
|
+
def init_default_config
|
186
|
+
configuration.project_id ||= Debugger.default_project_id
|
187
|
+
configuration.credentials ||= Debugger.default_credentials
|
188
|
+
configuration.service_name ||= Debugger.default_service_name
|
189
|
+
configuration.service_version ||= Debugger.default_service_version
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# @private Get Google::Cloud::Debugger.configure
|
194
|
+
def configuration
|
195
|
+
Google::Cloud::Debugger.configure
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|