google-cloud-debugger 0.24.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +8 -0
  3. data/LICENSE +201 -0
  4. data/README.md +56 -0
  5. data/ext/google/cloud/debugger/debugger_c/debugger.c +31 -0
  6. data/ext/google/cloud/debugger/debugger_c/debugger.h +26 -0
  7. data/ext/google/cloud/debugger/debugger_c/evaluator.c +78 -0
  8. data/ext/google/cloud/debugger/debugger_c/evaluator.h +25 -0
  9. data/ext/google/cloud/debugger/debugger_c/extconf.rb +22 -0
  10. data/ext/google/cloud/debugger/debugger_c/tracer.c +478 -0
  11. data/ext/google/cloud/debugger/debugger_c/tracer.h +31 -0
  12. data/lib/google-cloud-debugger.rb +121 -0
  13. data/lib/google/cloud/debugger.rb +379 -0
  14. data/lib/google/cloud/debugger/agent.rb +204 -0
  15. data/lib/google/cloud/debugger/async_actor.rb +290 -0
  16. data/lib/google/cloud/debugger/breakpoint.rb +382 -0
  17. data/lib/google/cloud/debugger/breakpoint/evaluator.rb +1113 -0
  18. data/lib/google/cloud/debugger/breakpoint/source_location.rb +75 -0
  19. data/lib/google/cloud/debugger/breakpoint/stack_frame.rb +109 -0
  20. data/lib/google/cloud/debugger/breakpoint/variable.rb +304 -0
  21. data/lib/google/cloud/debugger/breakpoint_manager.rb +217 -0
  22. data/lib/google/cloud/debugger/credentials.rb +41 -0
  23. data/lib/google/cloud/debugger/debuggee.rb +204 -0
  24. data/lib/google/cloud/debugger/debuggee/app_uniquifier_generator.rb +78 -0
  25. data/lib/google/cloud/debugger/middleware.rb +77 -0
  26. data/lib/google/cloud/debugger/project.rb +135 -0
  27. data/lib/google/cloud/debugger/rails.rb +141 -0
  28. data/lib/google/cloud/debugger/service.rb +130 -0
  29. data/lib/google/cloud/debugger/tracer.rb +165 -0
  30. data/lib/google/cloud/debugger/transmitter.rb +129 -0
  31. data/lib/google/cloud/debugger/v2.rb +15 -0
  32. data/lib/google/cloud/debugger/v2/controller2_client.rb +299 -0
  33. data/lib/google/cloud/debugger/v2/controller2_client_config.json +43 -0
  34. data/lib/google/cloud/debugger/v2/debugger2_client.rb +378 -0
  35. data/lib/google/cloud/debugger/v2/debugger2_client_config.json +53 -0
  36. data/lib/google/cloud/debugger/v2/doc/google/devtools/clouddebugger/v2/data.rb +441 -0
  37. data/lib/google/cloud/debugger/v2/doc/google/devtools/clouddebugger/v2/debugger.rb +151 -0
  38. data/lib/google/cloud/debugger/v2/doc/google/devtools/source/v1/source_context.rb +161 -0
  39. data/lib/google/cloud/debugger/v2/doc/google/protobuf/timestamp.rb +81 -0
  40. data/lib/google/cloud/debugger/version.rb +22 -0
  41. data/lib/google/devtools/clouddebugger/v2/controller_pb.rb +47 -0
  42. data/lib/google/devtools/clouddebugger/v2/controller_services_pb.rb +97 -0
  43. data/lib/google/devtools/clouddebugger/v2/data_pb.rb +105 -0
  44. data/lib/google/devtools/clouddebugger/v2/debugger_pb.rb +74 -0
  45. data/lib/google/devtools/clouddebugger/v2/debugger_services_pb.rb +64 -0
  46. data/lib/google/devtools/source/v1/source_context_pb.rb +89 -0
  47. metadata +300 -0
@@ -0,0 +1,78 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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
+ private
57
+
58
+ ##
59
+ # @private Recursively parse files and directories.
60
+ def self.process_directory sha, path, depth = 1
61
+ return if depth > MAX_DEPTH
62
+
63
+ pathname = Pathname.new path
64
+ pathname.each_child do |entry|
65
+ if entry.directory?
66
+ process_directory sha, entry, depth + 1
67
+ else
68
+ next unless entry.extname == ".rb" ||
69
+ entry.basename.to_s == "Gemfile.lock"
70
+ sha << "#{entry.expand_path}:#{entry.stat.size}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,77 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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
+ # Rack Middleware implementation that supports Stackdriver Debugger Agent
21
+ # in Rack-based Ruby frameworks. It instantiates a new debugger agent if
22
+ # one isn't given already. It helps optimize Debugger Agent Tracer
23
+ # performance by suspend and resume tracer between each request.
24
+ class Middleware
25
+ ##
26
+ # Create a new Debugger Middleware.
27
+ #
28
+ # @param [Rack Application] app Rack application
29
+ # @param [Google::Cloud::Debugger::Project] debugger A debugger to be
30
+ # used by this middleware. If not given, will construct a new one
31
+ # using the other parameters.
32
+ # @param [String] project Project identifier for the Stackdriver
33
+ # Debugger service. Optional if a debugger is given.
34
+ # @param [String, Hash] keyfile Keyfile downloaded from Google Cloud:
35
+ # either the JSON data or the path to a readable file. Optional if
36
+ # a debugger is given.
37
+ # @param [String] module_name Name for the debuggee application.
38
+ # Optional if a debugger is given.
39
+ # @param [String] module_version Version identifier for the debuggee
40
+ # application. Optiona if a debugger is given.
41
+ #
42
+ # @return [Google::Cloud::Debugger::Middleware] A new
43
+ # Google::Cloud::Debugger::Middleware instance
44
+ #
45
+ def initialize app, debugger: nil, module_name:nil, module_version: nil,
46
+ project: nil, keyfile: nil
47
+ @app = app
48
+ @debugger = debugger || Debugger.new(project: project,
49
+ keyfile: keyfile,
50
+ module_name: module_name,
51
+ module_version: module_version)
52
+ @debugger.start
53
+ end
54
+
55
+ ##
56
+ # Rack middleware entry point. In most Rack based frameworks, a request
57
+ # is served by one thread. It enables/resume the debugger breakpoints
58
+ # tracing and stops/pauses the tracing afterwards to help improve
59
+ # debugger performance.
60
+ #
61
+ # @param [Hash] env Rack environment hash
62
+ #
63
+ # @return [Rack::Response] The response from downstream Rack app
64
+ #
65
+ def call env
66
+ # Enable/resume breakpoints tracing
67
+ @debugger.agent.tracer.start
68
+
69
+ @app.call env
70
+ ensure
71
+ # Stop breakpoints tracing beyond this point
72
+ @debugger.agent.tracer.disable_traces_for_thread
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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/env"
18
+ require "google/cloud/debugger/agent"
19
+ require "google/cloud/debugger/credentials"
20
+ require "google/cloud/debugger/middleware"
21
+ require "google/cloud/debugger/service"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Debugger
26
+ ##
27
+ # # Project
28
+ #
29
+ # Projects are top-level containers in Google Cloud Platform. They store
30
+ # information about billing and authorized users, and they control access
31
+ # to Stackdriver Debugger resources. Each project has a friendly name and
32
+ # a unique ID. Projects can be created only in the [Google Developers
33
+ # Console](https://console.developers.google.com).
34
+ #
35
+ # @example
36
+ # require "google/cloud/debugger"
37
+ #
38
+ # debugger = Google::Cloud::Debugger.new
39
+ # debugger.start
40
+ #
41
+ # See Google::Cloud#debugger
42
+ class Project
43
+ ##
44
+ # @private The gRPC Service object.
45
+ attr_accessor :service
46
+
47
+ ##
48
+ # The Stackdriver Debugger Agent object.
49
+ attr_reader :agent
50
+
51
+ ##
52
+ # @private Creates a new Project instance.
53
+ def initialize service, module_name:, module_version:
54
+ @service = service
55
+ @agent = Agent.new service, module_name: module_name,
56
+ module_version: module_version
57
+ end
58
+
59
+ ##
60
+ # The ID of the current project.
61
+ #
62
+ # @return [String] the Google Cloud project ID
63
+ #
64
+ # @example
65
+ # require "google/cloud/debugger"
66
+ #
67
+ # debugger = Google::Cloud::Debugger.new(
68
+ # project: "my-project",
69
+ # keyfile: "/path/to/keyfile.json"
70
+ # )
71
+ #
72
+ # debugger.project #=> "my-project"
73
+ #
74
+ def project
75
+ service.project
76
+ end
77
+
78
+ ##
79
+ # @private Default project.
80
+ def self.default_project
81
+ ENV["DEBUGGER_PROJECT"] ||
82
+ ENV["GOOGLE_CLOUD_PROJECT"] ||
83
+ ENV["GCLOUD_PROJECT"] ||
84
+ Google::Cloud.env.project_id
85
+ end
86
+
87
+ ##
88
+ # @private Default module name identifier.
89
+ def self.default_module_name
90
+ ENV["DEBUGGER_MODULE_NAME"] ||
91
+ Google::Cloud.env.app_engine_service_id ||
92
+ "ruby-app"
93
+ end
94
+
95
+ ##
96
+ # @private Default module version identifier.
97
+ def self.default_module_version
98
+ ENV["DEBUGGER_MODULE_VERSION"] ||
99
+ Google::Cloud.env.app_engine_service_version ||
100
+ ""
101
+ end
102
+
103
+ ##
104
+ # Start the Stackdriver Debugger Agent.
105
+ #
106
+ # @example
107
+ # require "google/cloud/debugger"
108
+ #
109
+ # debugger = Google::Cloud::Debugger.new
110
+ # debugger.start
111
+ #
112
+ # See {Agent#start} for more details.
113
+ def start
114
+ agent.start
115
+ end
116
+ alias_method :attach, :start
117
+
118
+ ##
119
+ # Stop the Stackdriver Debugger Agent.
120
+ #
121
+ # @example
122
+ # require "google/cloud/debugger"
123
+ #
124
+ # debugger = Google::Cloud::Debugger.new
125
+ # debugger.start
126
+ # debugger.stop
127
+ #
128
+ # See {Agent#stop} for more details.
129
+ def stop
130
+ agent.stop
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,141 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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
+ require "google/cloud/debugger"
16
+
17
+ module Google
18
+ module Cloud
19
+ module Debugger
20
+ ##
21
+ # # Railtie
22
+ #
23
+ # Google::Cloud::Debugger::Railtie automatically adds the
24
+ # Google::Cloud::Debugger::Middleware to Rack in a Rails environment.
25
+ #
26
+ # The Middleware is only added when certain conditions are met. See
27
+ # {Railtie.use_debugger?} for detail.
28
+ #
29
+ # When loaded, the Google::Cloud::Debugger::Middleware will be inserted
30
+ # after the Rack::ETag Middleware, which is top of the Rack stack, closest
31
+ # to the application code.
32
+ #
33
+ # The Railtie should also initialize a debugger to be used by the
34
+ # middleware. The debugger can be configured using the following Rails
35
+ # configuration:
36
+ # @example
37
+ # # Explicitly enable or disable Stackdriver Debugger Agent
38
+ # config.google_cloud.use_debugger = true
39
+ # # Shared Google Cloud Platform project identifier
40
+ # config.google_cloud.project_id = "gcloud-project"
41
+ # # Google Cloud Platform project identifier for Stackdriver Debugger
42
+ # config.google_cloud.debugger.project_id = "debugger-project"
43
+ # # Share Google Cloud authentication json file
44
+ # config.google_cloud.keyfile = "/path/to/keyfile.json"
45
+ # # Google Cloud authentication json file for Stackdriver Debugger only
46
+ # config.google_cloud.debugger.keyfile = "/path/to/keyfile.json"
47
+ # # Stackdriver Debugger Agent module name identifier
48
+ # config.google_cloud.debugger.module_name = "my-ruby-app"
49
+ # # Stackdriver Debugger Agent module version identifier
50
+ # config.google_cloud.debugger.module_version = "v1"
51
+ #
52
+ class Railtie < ::Rails::Railtie
53
+ config.google_cloud = ::ActiveSupport::OrderedOptions.new unless
54
+ config.respond_to? :google_cloud
55
+ config.google_cloud[:debugger] = ::ActiveSupport::OrderedOptions.new
56
+ config.google_cloud.define_singleton_method :debugger do
57
+ self[:debugger]
58
+ end
59
+
60
+ initializer "Stackdriver.Debugger" do |app|
61
+ debugger_config = Railtie.parse_rails_config config
62
+
63
+ project_id = debugger_config[:project_id]
64
+ keyfile = debugger_config[:keyfile]
65
+ module_name = debugger_config[:module_name]
66
+ module_version = debugger_config[:module_version]
67
+
68
+ debugger = Google::Cloud::Debugger.new project: project_id,
69
+ keyfile: keyfile,
70
+ module_name: module_name,
71
+ module_version: module_version
72
+
73
+ if self.class.use_debugger? app.config
74
+ app.middleware.insert_after Rack::ETag,
75
+ Google::Cloud::Debugger::Middleware,
76
+ debugger: debugger
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Determine whether to use Stackdriver Debugger or not.
82
+ #
83
+ # Returns true if valid GCP project_id is provided and underneath API is
84
+ # able to authenticate. Also either Rails needs to be in "production"
85
+ # environment or config.stackdriver.use_debugger is explicitly true.
86
+ #
87
+ # @param [Rails::Railtie::Configuration] config The
88
+ # Rails.application.config
89
+ #
90
+ # @return [Boolean] Whether to use Stackdriver Debugger
91
+ #
92
+ def self.use_debugger? config
93
+ debugger_config = parse_rails_config config
94
+
95
+ # Return false if config.stackdriver.use_debugger is explicitly false
96
+ use_debugger = debugger_config[:use_debugger]
97
+ return false if !use_debugger.nil? && !use_debugger
98
+
99
+ # Try authenticate authorize client API. Return false if unable to
100
+ # authorize.
101
+ begin
102
+ Google::Cloud::Debugger::Credentials.credentials_with_scope(
103
+ debugger_config[:keyfile])
104
+ rescue => e
105
+ Rails.log "Google::Cloud::Debugger is not activated due to " \
106
+ "authorization error: #{e.message}"
107
+ return false
108
+ end
109
+
110
+ project_id = debugger_config[:project_id] ||
111
+ Google::Cloud::Debugger::Project.default_project
112
+ if project_id.to_s.empty?
113
+ Rails.log "Google::Cloud::Debugger is not activated due to empty " \
114
+ "project_id"
115
+ return false
116
+ end
117
+
118
+ # Otherwise default to true if Rails is running in production or
119
+ # config.stackdriver.use_debugger is true
120
+ Rails.env.production? || use_debugger
121
+ end
122
+
123
+ ##
124
+ # @private Helper method to parse rails config into a flattened hash
125
+ def self.parse_rails_config config
126
+ gcp_config = config.google_cloud
127
+ debugger_config = gcp_config[:debugger]
128
+ use_debugger =
129
+ gcp_config.key?(:use_debugger) ? gcp_config.use_debugger : nil
130
+ {
131
+ project_id: debugger_config.project_id || gcp_config.project_id,
132
+ keyfile: debugger_config.keyfile || gcp_config.keyfile,
133
+ module_name: debugger_config.module_name,
134
+ module_version: debugger_config.module_version,
135
+ use_debugger: use_debugger
136
+ }
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,130 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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 "google/gax/errors"
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, :host, :timeout, :client_config
29
+
30
+ ##
31
+ # Creates a new Service instance.
32
+ def initialize project, credentials, host: nil, timeout: nil,
33
+ client_config: nil
34
+ @project = project
35
+ @credentials = credentials
36
+ @host = host || V2::Controller2Client::SERVICE_ADDRESS
37
+ @timeout = timeout
38
+ @client_config = client_config || {}
39
+ end
40
+
41
+ def channel
42
+ require "grpc"
43
+ GRPC::Core::Channel.new host, nil, chan_creds
44
+ end
45
+
46
+ def chan_creds
47
+ return credentials if insecure?
48
+ require "grpc"
49
+ GRPC::Core::ChannelCredentials.new.compose \
50
+ GRPC::Core::CallCredentials.new credentials.client.updater_proc
51
+ end
52
+
53
+ def cloud_debugger
54
+ return mocked_debugger if mocked_debugger
55
+ @debugger ||=
56
+ V2::Controller2Client.new(
57
+ service_path: host,
58
+ channel: channel,
59
+ timeout: timeout,
60
+ client_config: client_config,
61
+ lib_name: "gccl",
62
+ lib_version: Google::Cloud::Debugger::VERSION)
63
+ end
64
+ attr_accessor :mocked_debugger
65
+
66
+ def transmitter
67
+ return mocked_transmitter if mocked_transmitter
68
+ @transmitter ||=
69
+ V2::Controller2Client.new(
70
+ service_path: host,
71
+ channel: channel,
72
+ timeout: timeout,
73
+ client_config: client_config,
74
+ lib_name: "gccl",
75
+ lib_version: Google::Cloud::Debugger::VERSION)
76
+ end
77
+ attr_accessor :mocked_transmitter
78
+
79
+ def insecure?
80
+ credentials == :this_channel_is_insecure
81
+ end
82
+
83
+ def register_debuggee debuggee_grpc
84
+ execute do
85
+ cloud_debugger.register_debuggee debuggee_grpc,
86
+ options: default_options
87
+ end
88
+ end
89
+
90
+ def list_active_breakpoints debuggee_id, wait_token
91
+ execute do
92
+ cloud_debugger.list_active_breakpoints debuggee_id.to_s,
93
+ wait_token: wait_token.to_s,
94
+ success_on_timeout: true,
95
+ options: default_options
96
+ end
97
+ end
98
+
99
+ def update_active_breakpoint debuggee_id, breakpoint
100
+ execute do
101
+ transmitter.update_active_breakpoint debuggee_id.to_s,
102
+ breakpoint.to_grpc,
103
+ options: default_options
104
+ end
105
+ end
106
+
107
+ def inspect
108
+ "#{self.class}(#{@project})"
109
+ end
110
+
111
+ protected
112
+
113
+ def default_headers
114
+ { "google-cloud-resource-prefix" => "projects/#{@project}" }
115
+ end
116
+
117
+ def default_options
118
+ Google::Gax::CallOptions.new kwargs: default_headers
119
+ end
120
+
121
+ def execute
122
+ yield
123
+ rescue Google::Gax::GaxError => e
124
+ # GaxError wraps BadStatus, but exposes it as #cause
125
+ raise Google::Cloud::Error.from_error(e.cause)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end