Skip to content

Commit

Permalink
Google Stackdriver Profiler
Browse files Browse the repository at this point in the history
This change adds support for the Google Stackdriver Profiler.
  • Loading branch information
nebhale committed Jul 23, 2018
1 parent 189bcd7 commit 0ef9a59
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .idea/dictionaries/bhale.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ The buildpack supports extension through the use of Git repository forking. The
* [Dynatrace Appmon Agent](docs/framework-dynatrace_appmon_agent.md) ([Configuration](docs/framework-dynatrace_appmon_agent.md#configuration))
* [Dynatrace SaaS/Managed OneAgent](docs/framework-dynatrace_one_agent.md) ([Configuration](docs/framework-dynatrace_one_agent.md#configuration))
* [Google Stackdriver Debugger](docs/framework-google_stackdriver_debugger.md) ([Configuration](docs/framework-google_stackdriver_debugger.md#configuration))
* [Google Stackdriver Profiler](docs/framework-google_stackdriver_profiler.md) ([Configuration](docs/framework-google_stackdriver_profiler.md#configuration))
* [Introscope Agent](docs/framework-introscope_agent.md) ([Configuration](docs/framework-introscope_agent.md#configuration))
* [JaCoCo Agent](docs/framework-jacoco_agent.md) ([Configuration](docs/framework-jacoco_agent.md#configuration))
* [Java Memory Assistant](docs/framework-java_memory_assistant.md) ([Configuration](docs/framework-java_memory_assistant.md#configuration))
Expand Down
1 change: 1 addition & 0 deletions config/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ frameworks:
- "JavaBuildpack::Framework::DynatraceAppmonAgent"
- "JavaBuildpack::Framework::DynatraceOneAgent"
- "JavaBuildpack::Framework::GoogleStackdriverDebugger"
- "JavaBuildpack::Framework::GoogleStackdriverProfiler"
- "JavaBuildpack::Framework::IntroscopeAgent"
- "JavaBuildpack::Framework::JacocoAgent"
- "JavaBuildpack::Framework::JavaMemoryAssistant"
Expand Down
21 changes: 21 additions & 0 deletions config/google_stackdriver_profiler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Cloud Foundry Java Buildpack
# Copyright 2013-2018 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Configuration for the Groovy container
---
version: 0.+
repository_root: "{default.repository.root}/google-stackdriver-profiler/{platform}/{architecture}"
application_name:
application_version:
43 changes: 43 additions & 0 deletions docs/framework-google_stackdriver_profiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Google Stackdriver Profielr Framework
The Google Stackdriver Profiler Framework causes an application to be automatically configured to work with a bound [Google Stackdriver Profiler Service][].

<table>
<tr>
<td><strong>Detection Criterion</strong></td><td>Existence of a single bound Google Stackdriver Profiler service.
<ul>
<li>Existence of a Google Stackdriver Profiler service is defined as the <a href="http://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-SERVICES"><code>VCAP_SERVICES</code></a> payload containing a service who's name, label or tag has <code>google-stackdriver-profiler</code> as a substring.</li>
</ul>
</td>
</tr>
<tr>
<td><strong>Tags</strong></td>
<td><tt>google-stackdriver-profiler=&lt;version&gt;</tt></td>
</tr>
</table>
Tags are printed to standard output by the buildpack detect script

## User-Provided Service (Optional)
Users may optionally provide their own Google Stackdriver Profiler service. A user-provided Google Stackdriver Profiler service must have a name or tag with `google-stackdriver-profiler` in it so that the Google Stackdriver Profiler Agent Framework will automatically configure the application to work with the service.

The credential payload of the service must contain the following entry:

| Name | Description
| ---- | -----------
| `PrivateKeyData` | A Base64 encoded Service Account JSON payload

## Configuration
For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].

The framework can be configured by modifying the [`config/google_stackdriver_profiler.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.

| Name | Description
| ---- | -----------
| `repository_root` | The URL of the Google Stackdriver Profiler repository index ([details][repositories]).
| `version` | The version of Google Stackdriver Profiler to use. Candidate versions can be found in [this listing][].

[Configuration and Extension]: ../README.md#configuration-and-extension
[`config/google_stackdriver_profiler.yml`]: ../config/google_stackdriver_profiler.yml
[Google Stackdriver Profiler Service]: https://cloud.google.com/profiler/
[repositories]: extending-repositories.md
[this listing]: http://download.pivotal.io.s3.amazonaws.com/google-stackdriver-profiler/trusty/x86_64/index.yml
[version syntax]: extending-repositories.md#version-syntax-and-ordering
Empty file modified docs/jre-zulu_jre.md
100755 → 100644
Empty file.
101 changes: 101 additions & 0 deletions lib/java_buildpack/framework/google_stackdriver_profiler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2018 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'base64'
require 'json'
require 'java_buildpack/component/versioned_dependency_component'
require 'java_buildpack/framework'

module JavaBuildpack
module Framework

# Encapsulates the functionality for enabling zero-touch Google Cloud Profiler support.
class GoogleStackdriverProfiler < JavaBuildpack::Component::VersionedDependencyComponent

# (see JavaBuildpack::Component::BaseComponent#compile)
def compile
download_tar false

write_json_file private_key_data
end

# (see JavaBuildpack::Component::BaseComponent#release)
def release
java_opts = @droplet.java_opts

java_opts
.add_agentpath_with_props(@droplet.sandbox + 'profiler_java_agent.so',
'--logtostderr' => 1,
'-cprof_project_id' => project_id,
'-cprof_service' => application_name,
'-cprof_service_version' => application_version)

@droplet.environment_variables.add_environment_variable 'GOOGLE_APPLICATION_CREDENTIALS', json_file
end

protected

# (see JavaBuildpack::Component::VersionedDependencyComponent#supports?)
def supports?
@application.services.one_service? FILTER, PRIVATE_KEY_DATA
end

FILTER = /google-stackdriver-profiler/

PRIVATE_KEY_DATA = 'PrivateKeyData'

private_constant :FILTER, :PRIVATE_KEY_DATA

private

def application_name
@configuration['application_name'] || @application.details['application_name']
end

def application_version
@configuration['application_version'] || @application.details['application_version']
end

def credentials
@application.services.find_service(FILTER, PRIVATE_KEY_DATA)['credentials']
end

def private_key_data
Base64.decode64 credentials[PRIVATE_KEY_DATA]
end

def project_id
JSON.parse(private_key_data)['project_id']
end

def json_file
@droplet.sandbox + 'svc.json'
end

def write_json_file(private_key_data)
FileUtils.mkdir_p json_file.parent
json_file.open(File::CREAT | File::WRONLY) do |f|
f.write "#{private_key_data}\n"
f.sync
f
end
end

end

end
end
1 change: 1 addition & 0 deletions rakelib/versions_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def initialize
'dynatrace_one_agent' => 'Dynatrace OneAgent',
'geode_store' => 'Geode Tomcat Session Store',
'google_stackdriver_debugger' => 'Google Stackdriver Debugger',
'google_stackdriver_profiler' => 'Google Stackdriver Profiler',
'groovy' => 'Groovy',
'introscope_agent' => 'CA Introscope APM Framework',
'jacoco_agent' => 'JaCoCo Agent',
Expand Down
Binary file not shown.
76 changes: 76 additions & 0 deletions spec/java_buildpack/framework/google_stackdriver_profiler_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2018 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'spec_helper'
require 'component_helper'
require 'java_buildpack/framework/google_stackdriver_profiler'

describe JavaBuildpack::Framework::GoogleStackdriverProfiler do
include_context 'with component help'

it 'does not detect without google-stackdriver-profiler service' do
expect(component.detect).to be_nil
end

context do

before do
allow(services).to receive(:one_service?)
.with(/google-stackdriver-profiler/, 'PrivateKeyData').and_return(true)

allow(services).to receive(:find_service).and_return(
'credentials' => {
'PrivateKeyData' => 'eyJwcm9qZWN0X2lkIjoidGVzdC1wcm9qZWN0LWlkIn0='
}
)
end

it 'detects with google-stackdriver-profiler service' do
expect(component.detect).to eq("google-stackdriver-profiler=#{version}")
end

it 'unpacks the google stackdriver debugger tar',
cache_fixture: 'stub-google-stackdriver-profiler.tar.gz' do

component.compile

expect(sandbox + 'profiler_java_agent.so').to exist
end

it 'writes JSON file',
cache_fixture: 'stub-google-stackdriver-profiler.tar.gz' do

component.compile

expect(sandbox + 'svc.json').to exist
expect(File.read(sandbox + 'svc.json')).to eq("{\"project_id\":\"test-project-id\"}\n")
end

it 'updates JAVA_OPTS' do
component.release
expect(java_opts).to include('-agentpath:$PWD/.java-buildpack/google_stackdriver_profiler/' \
'profiler_java_agent.so=--logtostderr=1,-cprof_project_id=test-project-id,' \
'-cprof_service=test-application-name,' \
'-cprof_service_version=test-application-version')

expect(environment_variables).to include('GOOGLE_APPLICATION_CREDENTIALS=' \
'$PWD/.java-buildpack/google_stackdriver_profiler/svc.json')
end

end

end

0 comments on commit 0ef9a59

Please sign in to comment.