Skip to content

Commit

Permalink
Merge pull request #23 from paketo-buildpacks/support-config-via-binding
Browse files Browse the repository at this point in the history
Add config support via binding
  • Loading branch information
dmikusa authored Oct 24, 2022
2 parents 7c50647 + b72a6bd commit 570efe2
Show file tree
Hide file tree
Showing 14 changed files with 279 additions and 59 deletions.
53 changes: 21 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Cloud Native Buildpacks - OpenTelemetry
# Paketo Buildpack for OpenTelemetry

## `gcr.io/paketo-buildpacks/opentelemetry`

The OpenTelemetry Buildpack is a Cloud Native Buildpack that contributes and configures the OpenTelemetry Agent.

Expand All @@ -8,55 +10,42 @@ This buildpack will participate if all the following conditions are met

* The `$BP_OPENTELEMETRY_ENABLED` is set to a truthy value (i.e. `true`, `t`, `1` ignoring case)

The buildpack will do the following for Java applications:

* Contributes the OpenTelemetry Java agent to a layer and configures `$JAVA_TOOL_OPTIONS` to use it

## Testing
At build time, the buildpack will do the following for Java applications:

Given a Java application, you can package it by running the following command from the current folder.
* Contributes the OpenTelemetry Java agent to a layer and configures `$JAVA_TOOL_OPTIONS` to use it.
* By default, the agent is configured to be disabled (`OTEL_JAVAAGENT_ENABLED=false`).
* By default, the metrics exporting feature of the agent is configured to be disabled (`OTEL_METRICS_EXPORTER=none`).

```shell
pack build my-app \
--path <my_app_path> \
--buildpack paketo-buildpacks/java \
--buildpack . \
--builder paketobuildpacks/builder:base \
--verbose --trust-builder \
-e BP_JVM_VERSION=17 -e BP_OPENTELEMETRY_ENABLED=true
```
At run time, the buildpack will do the following for Java applications:

Next, run it as follows.
* If a binding with `type` of `opentelemetry` exists, it uses the config tree from the binding to configure the OpenTelemetry Java agent. This is recommended when the configuration involves secrets of any kind.

```shell
docker run --rm -p 8080:8080 my-app
```

Check the logs and verify the OpenTelemetry Agent was included.
## Usage

```log
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -javaagent:/layers/paketo-buildpacks_opentelemetry/opentelemetry-java/opentelemetry-javaagent.jar -XX:ActiveProcessorCount=3 -XX:MaxDirectMemorySize=10M -Xmx3537385K -XX:MaxMetaspaceSize=98270K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics
Once you enable the OpenTelemetry buildpack at build-time, you can configure it at run-time via environment variables, as described in the [project documentation](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) or by passing configuration properties to the container via a binding.

[otel.javaagent 2022-06-28 21:16:29:365 +0000] [main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 1.15.0
```
By default, the following configuration is applied to the OpenTelemetry Java Agent at run time.

## Usage
* `OTEL_JAVAAGENT_ENABLED=false`
* `OTEL_METRICS_EXPORTER=none`

Once you enable the OpenTelemetry buildpack, you can configure it at run-time via environment variables, as described in the [project documentation](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/).
When using a [binding](https://paketo.io/docs/howto/configuration/#bindings), key/values map directly to OpenTelemetry Java agent configuration properties. Keys can follow the environment variable format or the system property format, as described in the [project documentation](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/).

## Bindings

The buildpack optionally accepts the following bindings:

### Type: `dependency-mapping`
### Type: `opentelemetry`

| Key | Value | Description |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `<dependency-digest>` | `<uri>` | If needed, the buildpack will fetch the dependency with digest `<dependency-digest>` from `<uri>` |
| `<otel-property-key>` | `<otel-property-value>` | Binding key/values map directly to OpenTelemetry Java agent configuration properties. Keys can follow the environment variable format or the system property format, as described in the [project documentation](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/). |

## References
### Type: `dependency-mapping`

This buildpack is based on the same structure used by [Paketo Buildpacks](https://paketo.io).
| Key | Value | Description |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `<dependency-digest>` | `<uri>` | If needed, the buildpack will fetch the dependency with digest `<dependency-digest>` from `<uri>` |

## License

Expand Down
4 changes: 2 additions & 2 deletions buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ api = "0.7"

[buildpack]
description = "A Cloud Native Buildpack that contributes and configures the OpenTelemetry Agent"
homepage = "https://github.com/ThomasVitale/buildpacks-opentelemetry"
homepage = "https://github.com/paketo-buildpacks/opentelemetry"
id = "paketo-buildpacks/opentelemetry"
keywords = ["java", "opentelemetry"]
name = "Paketo OpenTelemetry Buildpack"
Expand All @@ -11,7 +11,7 @@ api = "0.7"

[[buildpack.licenses]]
type = "Apache-2.0"
uri = "https://github.com/ThomasVitale/buildpacks-opentelemetry/blob/main/LICENSE"
uri = "https://github.com/paketo-buildpacks/opentelemetry/blob/main/LICENSE"

[metadata]
include-files = ["LICENSE", "NOTICE", "README.md", "bin/build", "bin/detect", "bin/main", "buildpack.toml"]
Expand Down
46 changes: 46 additions & 0 deletions cmd/helper/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2022 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
*
* https://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.
*/

package main

import (
"fmt"
"os"

"github.com/buildpacks/libcnb"
"github.com/paketo-buildpacks/libpak/bard"
"github.com/paketo-buildpacks/libpak/sherpa"

"github.com/paketo-buildpacks/opentelemetry/helper"
)

func main() {
sherpa.Execute(func() error {
var (
err error
p = helper.Properties{Logger: bard.NewLogger(os.Stdout)}
)

p.Bindings, err = libcnb.NewBindingsFromEnvironment()
if err != nil {
return fmt.Errorf("unable to read bindings from environment\n%w", err)
}

return sherpa.Helpers(map[string]sherpa.ExecD{
"properties": p,
})
})
}
18 changes: 17 additions & 1 deletion cmd/main/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
/*
* Copyright 2022 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
*
* https://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.
*/

package main

import (
"os"

"github.com/ThomasVitale/buildpacks-opentelemetry/opentelemetry"
"github.com/paketo-buildpacks/libpak"
"github.com/paketo-buildpacks/libpak/bard"
"github.com/paketo-buildpacks/opentelemetry/opentelemetry"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/ThomasVitale/buildpacks-opentelemetry
module github.com/paketo-buildpacks/opentelemetry

go 1.18

Expand Down
30 changes: 30 additions & 0 deletions helper/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2022 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
*
* https://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.
*/

package helper_test

import (
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
)

func TestUnit(t *testing.T) {
suite := spec.New("helper", spec.Report(report.Terminal{}))
suite("Properties", testProperties)
suite.Run(t)
}
57 changes: 57 additions & 0 deletions helper/properties.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2022 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
*
* https://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.
*/

package helper

import (
"fmt"
"strings"

"github.com/buildpacks/libcnb"
"github.com/paketo-buildpacks/libpak/bard"
"github.com/paketo-buildpacks/libpak/bindings"
)

type Properties struct {
Bindings libcnb.Bindings
Logger bard.Logger
}

func (p Properties) Execute() (map[string]string, error) {
b, ok, err := bindings.ResolveOne(p.Bindings, bindings.OfType("opentelemetry"))
if err != nil {
return nil, fmt.Errorf("unable to resolve binding opentelemetry\n%w", err)
} else if !ok {
return nil, nil
}

p.Logger.Info("Configuring OpenTelemetry Agent properties")

/*
* Properties are expected to be passed via a configtree format,
* where each key is the name of a file and the value its content.
*/
e := make(map[string]string, len(b.Secret))
for k, v := range b.Secret {
s := strings.ToUpper(k)
s = strings.ReplaceAll(s, "-", "_")
s = strings.ReplaceAll(s, ".", "_")

e[s] = v
}

return e, nil
}
57 changes: 57 additions & 0 deletions helper/properties_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2022 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
*
* https://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.
*/

package helper_test

import (
"testing"

"github.com/buildpacks/libcnb"
. "github.com/onsi/gomega"
"github.com/sclevine/spec"

"github.com/paketo-buildpacks/opentelemetry/helper"
)

func testProperties(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect

p helper.Properties
)

it("does not contribute properties if no binding exists", func() {
Expect(p.Execute()).To(BeNil())
})

it("contributes properties if binding exists as a config tree", func() {
p.Bindings = libcnb.Bindings{
{
Name: "test-binding",
Type: "opentelemetry",
Secret: map[string]string{
"otel.test.my-key": "test-value",
"otel.testagain.my-other-key": "other test value",
},
},
}

Expect(p.Execute()).To(Equal(map[string]string{
"OTEL_TEST_MY_KEY": "test-value",
"OTEL_TESTAGAIN_MY_OTHER_KEY": "other test value",
}))
})
}
12 changes: 10 additions & 2 deletions opentelemetry/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,21 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
if _, ok, err := pr.Resolve("opentelemetry-java"); err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to resolve opentelemetry-java plan entry\n%w", err)
} else if ok {
agentDependency, err := dr.Resolve("opentelemetry-java", "")
dep, err := dr.Resolve("opentelemetry-java", "")
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err)
}

result.Layers = append(result.Layers, NewJavaAgent(agentDependency, dc, b.Logger))
ja, be := NewJavaAgent(context.Buildpack.Path, dep, dc)
ja.Logger = b.Logger
result.Layers = append(result.Layers, ja)
result.BOM.Entries = append(result.BOM.Entries, be)
}

h, be := libpak.NewHelperLayer(context.Buildpack, "properties")
h.Logger = b.Logger
result.Layers = append(result.Layers, h)
result.BOM.Entries = append(result.BOM.Entries, be)

return result, nil
}
Loading

0 comments on commit 570efe2

Please sign in to comment.