Skip to content

Commit

Permalink
Introduce the splunk-otel-java-agent framework.
Browse files Browse the repository at this point in the history
This framework will wire up the splunk distribution of opentelemetry java for auto-instrumentation and direct ingest. It leverages VCAP_SERVICES and the existence of a service binding with a specific name (splunk-o11y).

Signed-off-by: Jason Plumb [email protected]

Resolves issue cloudfoundry#825
  • Loading branch information
breedx-splk committed Sep 19, 2022
1 parent edad6b2 commit 7c46b1d
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ frameworks:
- "JavaBuildpack::Framework::SealightsAgent"
- "JavaBuildpack::Framework::SeekerSecurityProvider"
- "JavaBuildpack::Framework::SpringAutoReconfiguration"
- "JavaBuildpack::Framework::SplunkOtelJavaAgent"
- "JavaBuildpack::Framework::SpringInsight"
- "JavaBuildpack::Framework::SkyWalkingAgent"
- "JavaBuildpack::Framework::YourKitProfiler"
Expand Down
21 changes: 21 additions & 0 deletions config/splunk_otel_java_agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Cloud Foundry Java Buildpack
# Copyright 2013-2020 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 Splunk Distribution of OpenTelemetry Java Instrumentation
# See https://github.com/signalfx/splunk-otel-java for more information
---
version: +
repository_root: https://raw.githubusercontent.com/signalfx/splunk-otel-java/main/deployments/cloudfoundry/

51 changes: 51 additions & 0 deletions docs/framework-splunk_otel_java_agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Splunk Distribution of OpenTelemetry Java Instrumentation

The Splunk OpenTelemetry Java Agent buildpack framework will cause an application to be automatically instrumented
with the [Splunk distribution of OpenTelemetry Java Instrumentation](https://github.com/signalfx/splunk-otel-java).

Trace data will be sent directly to Splunk Observability Cloud.

* **Detection criteria**: Existence of a bound service with the name `splunk-o11y`.
* **Tags**: `splunk-otel-java-agent=<version>` to control which version of the instrumentation agent is used.
* Default = latest available version

## User-Provided Service

Users are currently expected to provide their own "custom user provided service" (cups)
instance and bind it to their application. The service MUST be named `splunk-o11y`.

For example, to create a service named `splunk-o11y` that represents Observability Cloud
realm `us0` and represents a user environment named `cf-demo`, you could use the following
commands:

```
$ cf cups splunk-o11y -p \
'{"splunk.realm": "us0", "splunk.access.token": "<redacted>", "otel.resource.attributes": "deployment.environment=cf-demo"}'
$ cf bind-service myApp splunk-o11y
$ cf restage myApp
```

The `credential` field of the service should provide these entries:

| Name | Required? | Description
|------------------------|-----------| -----------
| `splunk.access.token` | Yes | The Splunk [org access token](https://docs.splunk.com/observability/admin/authentication-tokens/org-tokens.html).
| `splunk.realm` | Yes | The Splunk realm where data will be sent. This is commonly `us0` or `eu0` etc.
| `otel.*` or `splunk.*` | Optional | All additional credentials starting with these prefixes will be appended to the application's JVM arguments as system properties.

### Choosing a version

Most users should skip this and simply use the latest version of the agent available (the default).
To override the default and choose a specific version, you can use the `JBP_CONFIG_*` mechanism
and set the `JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT` environment variable for your application.

For example, to use version 1.16.0 of the Splunk OpenTelemetry Java Instrumentation, you
could run:
```
$ cf set-env testapp JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT '{version: 1.16.0}'
```

# Additional Resources

* [Splunk Observability](https://www.splunk.com/en_us/products/observability.html)
* [Splunk Distribution of OpenTelemetry Java](https://github.com/signalfx/splunk-otel-java) on GitHub
58 changes: 58 additions & 0 deletions lib/java_buildpack/framework/splunk_otel_java_agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2020 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 'java_buildpack/component/versioned_dependency_component'
require 'java_buildpack/framework'

module JavaBuildpack
module Framework

# Main class for adding the Splunk OpenTelemetry instrumentation agent
class SplunkOtelJavaAgent < JavaBuildpack::Component::VersionedDependencyComponent

# (see JavaBuildpack::Component::BaseComponent#compile)
def compile
download_jar
end

# (see JavaBuildpack::Component::BaseComponent#release)
def release
java_opts = @droplet.java_opts
java_opts.add_javaagent(@droplet.sandbox + jar_name)

credentials = @application.services.find_service(REQUIRED_SERVICE_NAME_FILTER)['credentials']
# Add all otel.* and splunk.* credentials from the service bind as jvm system properties
credentials&.each do |key, value|
java_opts.add_system_property(key, value) if key.start_with?('splunk.') || key.start_with?('otel.')
end

app_name = @application.details['application_name']
java_opts.add_system_property('otel.service.name', app_name)
end

protected

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

REQUIRED_SERVICE_NAME_FILTER = /^splunk-o11y$/.freeze

end
end
end
Binary file added spec/fixtures/stub-splunk-otel-javaagent.jar
Binary file not shown.
74 changes: 74 additions & 0 deletions spec/java_buildpack/framework/splunk_otel_java_agent_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

# Cloud Foundry Java Buildpack
# Copyright 2013-2020 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/splunk_otel_java_agent'
require 'java_buildpack/util/tokenized_version'

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

let(:configuration) { { 'version' => '1.16.0' } }
let(:vcap_application) { { 'application_name' => 'GreatServiceTM' } }

it 'does not detect without splunk-o11y service bind' do
expect(component.detect).to be_nil
end

context 'when detected' do

before do
allow(services).to receive(:one_service?).with(/^splunk-o11y$/).and_return(true)
end

it 'detects with splunk-otel-java' do
expect(component.detect).to eq("splunk-otel-java-agent=#{version}")
end

it 'downloads the splunk otel javaagent jar', cache_fixture: 'stub-splunk-otel-javaagent.jar' do

component.compile

expect(sandbox + "splunk_otel_java_agent-#{version}.jar").to exist
end

it 'updates JAVA_OPTS' do
allow(services).to receive(:find_service).and_return('credentials' => { 'splunk.access.token' => 'sekret',
'ignored' => 'not used',
'otel.foo' => 'bar' })
component.release

expect(java_opts).to include(
"-javaagent:$PWD/.java-buildpack/splunk_otel_java_agent/splunk_otel_java_agent-#{version}.jar"
)
expect(java_opts).to include('-Dsplunk.access.token=sekret')
expect(java_opts).to include('-Dotel.foo=bar')
end

it 'sets the service name from the application name' do
allow(services).to receive(:find_service).and_return('credentials' => { 'splunk.access.token' => 'sekret' })
# allow(details).to be( { 'application_name' => 'dick' })

component.release

expect(java_opts).to include('-Dotel.service.name=GreatServiceTM')
end

end

end

0 comments on commit 7c46b1d

Please sign in to comment.