google-cloud-debugger 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,110 @@
|
|
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/errors"
|
17
|
+
require "google/cloud/debugger/agent"
|
18
|
+
require "google/cloud/debugger/credentials"
|
19
|
+
require "google/cloud/debugger/middleware"
|
20
|
+
require "google/cloud/debugger/service"
|
21
|
+
|
22
|
+
module Google
|
23
|
+
module Cloud
|
24
|
+
module Debugger
|
25
|
+
##
|
26
|
+
# # Project
|
27
|
+
#
|
28
|
+
# Projects are top-level containers in Google Cloud Platform. They store
|
29
|
+
# information about billing and authorized users, and they control access
|
30
|
+
# to Stackdriver Debugger resources. Each project has a friendly name and
|
31
|
+
# a unique ID. Projects can be created only in the [Google Developers
|
32
|
+
# Console](https://console.developers.google.com).
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require "google/cloud/debugger"
|
36
|
+
#
|
37
|
+
# debugger = Google::Cloud::Debugger.new
|
38
|
+
# debugger.start
|
39
|
+
#
|
40
|
+
# See Google::Cloud#debugger
|
41
|
+
class Project
|
42
|
+
##
|
43
|
+
# @private The gRPC Service object.
|
44
|
+
attr_accessor :service
|
45
|
+
|
46
|
+
##
|
47
|
+
# The Stackdriver Debugger Agent object.
|
48
|
+
attr_reader :agent
|
49
|
+
|
50
|
+
##
|
51
|
+
# @private Creates a new Project instance.
|
52
|
+
def initialize service, service_name:, service_version:
|
53
|
+
@service = service
|
54
|
+
@agent = Agent.new service, service_name: service_name,
|
55
|
+
service_version: service_version
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# The ID of the current project.
|
60
|
+
#
|
61
|
+
# @return [String] the Google Cloud project ID
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# require "google/cloud/debugger"
|
65
|
+
#
|
66
|
+
# debugger = Google::Cloud::Debugger.new(
|
67
|
+
# project_id: "my-project",
|
68
|
+
# credentials: "/path/to/keyfile.json"
|
69
|
+
# )
|
70
|
+
#
|
71
|
+
# debugger.project_id #=> "my-project"
|
72
|
+
#
|
73
|
+
def project_id
|
74
|
+
service.project
|
75
|
+
end
|
76
|
+
alias project project_id
|
77
|
+
|
78
|
+
##
|
79
|
+
# Start the Stackdriver Debugger Agent.
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# require "google/cloud/debugger"
|
83
|
+
#
|
84
|
+
# debugger = Google::Cloud::Debugger.new
|
85
|
+
# debugger.start
|
86
|
+
#
|
87
|
+
# See {Agent#start} for more details.
|
88
|
+
def start
|
89
|
+
agent.start
|
90
|
+
end
|
91
|
+
alias attach start
|
92
|
+
|
93
|
+
##
|
94
|
+
# Stop the Stackdriver Debugger Agent.
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# require "google/cloud/debugger"
|
98
|
+
#
|
99
|
+
# debugger = Google::Cloud::Debugger.new
|
100
|
+
# debugger.start
|
101
|
+
# debugger.stop
|
102
|
+
#
|
103
|
+
# See {Agent#stop} for more details.
|
104
|
+
def stop
|
105
|
+
agent.stop
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,174 @@
|
|
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"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Debugger
|
21
|
+
##
|
22
|
+
# # Railtie
|
23
|
+
#
|
24
|
+
# Google::Cloud::Debugger::Railtie automatically adds the
|
25
|
+
# Google::Cloud::Debugger::Middleware to Rack in a Rails environment.
|
26
|
+
#
|
27
|
+
# The Middleware is only added when the
|
28
|
+
# `Google::Cloud.configure.use_debugger` setting is true or Rails is
|
29
|
+
# in the production environment.
|
30
|
+
#
|
31
|
+
# When loaded, the Google::Cloud::Debugger::Middleware will be inserted
|
32
|
+
# after the Rack::ETag Middleware, which is top of the Rack stack, closest
|
33
|
+
# to the application code.
|
34
|
+
#
|
35
|
+
# The Railtie should also initialize a debugger to be used by the
|
36
|
+
# Middleware. See the [Configuration
|
37
|
+
# Guide](https://googleapis.dev/ruby/stackdriver/latest/file.INSTRUMENTATION_CONFIGURATION.html)
|
38
|
+
# on how to configure the Railtie and Middleware.
|
39
|
+
#
|
40
|
+
class Railtie < ::Rails::Railtie
|
41
|
+
##
|
42
|
+
# Inform the Railtie that it is safe to start debugger agents.
|
43
|
+
# This simply calls {Google::Cloud::Debugger::Middleware.start_agents}.
|
44
|
+
# See its documentation for more information.
|
45
|
+
#
|
46
|
+
def self.start_agents
|
47
|
+
Google::Cloud::Debugger::Middleware.start_agents
|
48
|
+
end
|
49
|
+
|
50
|
+
config.google_cloud = ::ActiveSupport::OrderedOptions.new unless
|
51
|
+
config.respond_to? :google_cloud
|
52
|
+
config.google_cloud[:debugger] = ::ActiveSupport::OrderedOptions.new
|
53
|
+
config.google_cloud.define_singleton_method :debugger do
|
54
|
+
self[:debugger]
|
55
|
+
end
|
56
|
+
|
57
|
+
initializer "Stackdriver.Debugger" do |app|
|
58
|
+
self.class.consolidate_rails_config app.config
|
59
|
+
|
60
|
+
self.class.init_middleware app if Cloud.configure.use_debugger
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# @private Init Debugger integration for Rails. Setup configuration and
|
65
|
+
# insert the Middleware.
|
66
|
+
def self.init_middleware app
|
67
|
+
app.middleware.insert_after Rack::ETag,
|
68
|
+
Google::Cloud::Debugger::Middleware
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# @private Consolidate Rails configuration into Debugger instrumentation
|
73
|
+
# configuration. Also consolidate the `use_debugger` setting by
|
74
|
+
# verifying credentials and Rails environment. The `use_debugger`
|
75
|
+
# setting will be true if credentials are valid, and the setting is
|
76
|
+
# manually set to true or Rails is in the production environment.
|
77
|
+
#
|
78
|
+
# @param [Rails::Railtie::Configuration] config The
|
79
|
+
# Rails.application.config
|
80
|
+
#
|
81
|
+
def self.consolidate_rails_config config
|
82
|
+
merge_rails_config config
|
83
|
+
|
84
|
+
init_default_config
|
85
|
+
|
86
|
+
# Done if Google::Cloud.configure.use_debugger is explicitly
|
87
|
+
# false
|
88
|
+
return if Google::Cloud.configure.use_debugger == false
|
89
|
+
|
90
|
+
# Verify credentials and set use_debugger to false if
|
91
|
+
# credentials are invalid
|
92
|
+
unless valid_credentials? Debugger.configure.project_id,
|
93
|
+
Debugger.configure.credentials
|
94
|
+
Cloud.configure.use_debugger = false
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
# Otherwise set use_debugger to true if Rails is running in
|
99
|
+
# the production environment
|
100
|
+
Google::Cloud.configure.use_debugger ||= ::Rails.env.production?
|
101
|
+
end
|
102
|
+
|
103
|
+
# rubocop:disable all
|
104
|
+
|
105
|
+
##
|
106
|
+
# @private Merge Rails configuration into Debugger instrumentation
|
107
|
+
# configuration.
|
108
|
+
def self.merge_rails_config rails_config
|
109
|
+
gcp_config = rails_config.google_cloud
|
110
|
+
dbg_config = gcp_config.debugger
|
111
|
+
|
112
|
+
if Cloud.configure.use_debugger.nil?
|
113
|
+
Cloud.configure.use_debugger = gcp_config.use_debugger
|
114
|
+
end
|
115
|
+
Debugger.configure do |config|
|
116
|
+
config.project_id ||= begin
|
117
|
+
config.project || dbg_config.project_id || dbg_config.project
|
118
|
+
gcp_config.project_id || gcp_config.project
|
119
|
+
end
|
120
|
+
config.credentials ||= begin
|
121
|
+
config.keyfile || dbg_config.credentials || dbg_config.keyfile
|
122
|
+
gcp_config.credentials || gcp_config.keyfile
|
123
|
+
end
|
124
|
+
config.service_name ||= \
|
125
|
+
(dbg_config.service_name || gcp_config.service_name)
|
126
|
+
config.service_version ||= \
|
127
|
+
(dbg_config.service_version || gcp_config.service_version)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# rubocop:enable all
|
132
|
+
|
133
|
+
##
|
134
|
+
# Fallback to default config values if config parameters not provided.
|
135
|
+
def self.init_default_config
|
136
|
+
config = Debugger.configure
|
137
|
+
config.project_id ||= Debugger.default_project_id
|
138
|
+
config.service_name ||= Debugger.default_service_name
|
139
|
+
config.service_version ||= Debugger.default_service_version
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# @private Verify credentials
|
144
|
+
def self.valid_credentials? project_id, credentials
|
145
|
+
begin
|
146
|
+
# if credentials is nil, get default
|
147
|
+
credentials ||= Debugger::Credentials.default
|
148
|
+
# only create a new Credentials object if the val isn't one already
|
149
|
+
unless credentials.is_a? Google::Auth::Credentials
|
150
|
+
# if credentials is not a Credentials object, create one
|
151
|
+
Debugger::Credentials.new credentials
|
152
|
+
end
|
153
|
+
rescue StandardError => e
|
154
|
+
STDOUT.puts "Note: Google::Cloud::Debugger is disabled because " \
|
155
|
+
"it failed to authorize with the service. (#{e.message})"
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
|
159
|
+
if project_id.to_s.empty?
|
160
|
+
STDOUT.puts "Note: Google::Cloud::Debugger is disabled because " \
|
161
|
+
"the project ID could not be determined."
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
private_class_method :merge_rails_config,
|
169
|
+
:init_default_config,
|
170
|
+
:valid_credentials?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,95 @@
|
|
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
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Debugger
|
19
|
+
##
|
20
|
+
# # RequestQuotaManager
|
21
|
+
#
|
22
|
+
# Tracking object used by debugger agent to manage quota in
|
23
|
+
# request-based applications. This class tracks the amount of time
|
24
|
+
# and number of breakpoints to evaluation in a single session.
|
25
|
+
#
|
26
|
+
# The debugger agent doesn't have use a quota manager by default, which
|
27
|
+
# means it will evaluate all breakpoints encountered and takes as much
|
28
|
+
# time as needed. This class is utilized by
|
29
|
+
# {Google::Cloud::Debugger::Middleware} class to limit latency overhead
|
30
|
+
# when used in Rack-based applications.
|
31
|
+
#
|
32
|
+
class RequestQuotaManager
|
33
|
+
# Default Total time allowed to consume, in seconds
|
34
|
+
DEFAULT_TIME_QUOTA = 0.05
|
35
|
+
|
36
|
+
# Default max number of breakpoints to evaluate
|
37
|
+
DEFAULT_COUNT_QUOTA = 10
|
38
|
+
|
39
|
+
##
|
40
|
+
# The time quota for this manager
|
41
|
+
attr_accessor :time_quota
|
42
|
+
|
43
|
+
##
|
44
|
+
# The count quota for this manager
|
45
|
+
attr_accessor :count_quota
|
46
|
+
|
47
|
+
##
|
48
|
+
# The time quota used
|
49
|
+
attr_accessor :time_used
|
50
|
+
|
51
|
+
##
|
52
|
+
# The count quota used
|
53
|
+
attr_accessor :count_used
|
54
|
+
|
55
|
+
##
|
56
|
+
# Construct a new RequestQuotaManager instance
|
57
|
+
#
|
58
|
+
# @param [Float] time_quota The max quota for time consumed.
|
59
|
+
# @param [Integer] count_quota The max quota for count usage.
|
60
|
+
def initialize time_quota: DEFAULT_TIME_QUOTA,
|
61
|
+
count_quota: DEFAULT_COUNT_QUOTA
|
62
|
+
@time_quota = time_quota
|
63
|
+
@time_used = 0
|
64
|
+
@count_quota = count_quota
|
65
|
+
@count_used = 0
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Check if there's more quota left.
|
70
|
+
#
|
71
|
+
# @return [Boolean] True if there's more quota; false otherwise.
|
72
|
+
def more?
|
73
|
+
(time_used < time_quota) && (count_used < count_quota)
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Reset all the quota usage.
|
78
|
+
def reset
|
79
|
+
@time_used = 0
|
80
|
+
@count_used = 0
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Notify the quota manager some resource has been consumed. Each time
|
85
|
+
# called increases the count quota usage.
|
86
|
+
#
|
87
|
+
# @param [Float] time Amount of time to deduct from the time quota.
|
88
|
+
def consume time: 0
|
89
|
+
@time_used += time
|
90
|
+
@count_used += 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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/errors"
|
17
|
+
require "google/cloud/debugger/version"
|
18
|
+
require "google/cloud/debugger/v2"
|
19
|
+
require "uri"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
module Debugger
|
24
|
+
##
|
25
|
+
# @private Represents the gRPC Debugger service, including all the API
|
26
|
+
# methods.
|
27
|
+
class Service
|
28
|
+
attr_accessor :project, :credentials, :timeout, :host
|
29
|
+
|
30
|
+
##
|
31
|
+
# Creates a new Service instance.
|
32
|
+
def initialize project, credentials, timeout: nil, host: nil
|
33
|
+
@project = project
|
34
|
+
@credentials = credentials
|
35
|
+
@timeout = timeout
|
36
|
+
@host = host
|
37
|
+
end
|
38
|
+
|
39
|
+
def cloud_debugger
|
40
|
+
return mocked_debugger if mocked_debugger
|
41
|
+
@cloud_debugger ||=
|
42
|
+
V2::Controller::Client.new do |config|
|
43
|
+
config.credentials = credentials if credentials
|
44
|
+
config.timeout = timeout if timeout
|
45
|
+
config.endpoint = host if host
|
46
|
+
config.lib_name = "gccl"
|
47
|
+
config.lib_version = Google::Cloud::Debugger::VERSION
|
48
|
+
config.metadata = { "google-cloud-resource-prefix" => "projects/#{@project}" }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
attr_accessor :mocked_debugger
|
52
|
+
|
53
|
+
def transmitter
|
54
|
+
return mocked_transmitter if mocked_transmitter
|
55
|
+
@transmitter ||=
|
56
|
+
V2::Controller::Client.new do |config|
|
57
|
+
config.credentials = credentials if credentials
|
58
|
+
config.timeout = timeout if timeout
|
59
|
+
config.endpoint = host if host
|
60
|
+
config.lib_name = "gccl"
|
61
|
+
config.lib_version = Google::Cloud::Debugger::VERSION
|
62
|
+
config.metadata = { "google-cloud-resource-prefix" => "projects/#{@project}" }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
attr_accessor :mocked_transmitter
|
66
|
+
|
67
|
+
def register_debuggee debuggee_grpc
|
68
|
+
cloud_debugger.register_debuggee debuggee: debuggee_grpc
|
69
|
+
end
|
70
|
+
|
71
|
+
def list_active_breakpoints debuggee_id, wait_token
|
72
|
+
cloud_debugger.list_active_breakpoints debuggee_id: debuggee_id.to_s,
|
73
|
+
wait_token: wait_token.to_s,
|
74
|
+
success_on_timeout: true
|
75
|
+
end
|
76
|
+
|
77
|
+
def update_active_breakpoint debuggee_id, breakpoint
|
78
|
+
transmitter.update_active_breakpoint debuggee_id: debuggee_id.to_s,
|
79
|
+
breakpoint: breakpoint.to_grpc
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
"#{self.class}(#{@project})"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|