Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a1fe6b3
added cf-metrics-exporter agent
stokpop Jan 14, 2026
5c6f905
add default version for cf-metrics-exporter
stokpop Jan 14, 2026
1910ae3
fix agent path for cf-metrics-exporter
stokpop Jan 14, 2026
227d181
fix agent path for cf-metrics-exporter using the proper deps dir and …
stokpop Jan 14, 2026
f9fe4b6
add CF_METRICS_EXPORTER_ENABLED="test" for test purpose
stokpop Jan 14, 2026
81bc438
add CF_METRICS_EXPORTER_ENABLED="test" for test purpose: forgot one c…
stokpop Jan 14, 2026
ac1c778
added fix and test for location of cf-metrics-exporter jar
stokpop Jan 15, 2026
262fd39
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 15, 2026
9fc7670
fix cf-metrics-exporter framework name returned from Detect
stokpop Jan 15, 2026
382deed
add commas to frameworks log, update JMX framework name
stokpop Jan 15, 2026
80dd9d9
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 15, 2026
7b96ebc
remove temp test construct for cf-metrics-exporter
stokpop Jan 16, 2026
36aa0bb
update cf-metrics-exporter docs
stokpop Jan 19, 2026
a25b288
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 19, 2026
aed499d
improve cf-metrics-exporter unit test
stokpop Jan 19, 2026
480957e
fix framework names of cf-metrics-exporter and JMX
stokpop Jan 19, 2026
c80f1c0
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 19, 2026
4566bf5
cf-metrics-exporter: add config logging during supply phase
stokpop Jan 19, 2026
b93dedb
PR comment fix: revert JMX changes
stokpop Jan 20, 2026
9dc0a9c
PR comment fix: download from maven central instead of github
stokpop Jan 20, 2026
5c8d7f7
PR comment fix: simplify cf-metrics-exporter jar download and install
stokpop Jan 20, 2026
68818b4
added spacing for readability
stokpop Jan 20, 2026
911e07e
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 20, 2026
f66336b
Merge remote-tracking branch 'upstream/feature/go-migration' into fea…
stokpop Jan 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/framework-cf_metrics_exporter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# cf-metrics-exporter (Agent Mode)

This framework integrates the [cf-metrics-exporter](https://github.com/rabobank/cf-metrics-exporter) as a Java agent in the Java buildpack.

## Enabling the Exporter

Set the following environment variable in the cloud foundry env to enable the agent (via manifest.yml or `cf set-env`):

```
CF_METRICS_EXPORTER_ENABLED=true
```

## Configuration

- **CF_METRICS_EXPORTER_ENABLED**: Set to `true` to enable the agent (default: disabled).
- **CF_METRICS_EXPORTER_PROPS**: (Optional) Properties string to pass to the agent, e.g. `enableLogEmitter,rpsType=tomcat-bean`.

## How it Works

- The agent JAR is downloaded during the buildpack supply phase.
- The agent is injected into the JVM at runtime using the `-javaagent` option.
- If `CF_METRICS_EXPORTER_PROPS` is set, its value is appended to the `-javaagent` option.

## Example

```
CF_METRICS_EXPORTER_ENABLED=true
CF_METRICS_EXPORTER_PROPS="enableLogEmitter,rpsType=tomcat-bean"
```

## Version

- Default version: 0.7.1
- Default download URI: https://github.com/rabobank/cf-metrics-exporter/releases/download/0.7.1/cf-metrics-exporter-0.7.1.jar

## Notes

- The agent is injected with priority 43 in JAVA_OPTS (after other APM agents).


10 changes: 10 additions & 0 deletions manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ default_versions:
version: 7.x
- name: newrelic
version: 8.x
- name: cf-metrics-exporter
version: 0.7.x

url_to_dependency_map:
- match: openjdk-jre-(\d+\.\d+\.\d+)
Expand Down Expand Up @@ -544,6 +546,14 @@ dependencies:
cf_stacks:
- cflinuxfs4

# cf-metrics-exporter Agent
- name: cf-metrics-exporter
version: 0.7.1
uri: https://repo1.maven.org/maven2/io/github/rabobank/cf-metrics-exporter/0.7.1/cf-metrics-exporter-0.7.1.jar
sha256: 7ebabd3ffd812082cf92a513c8d2ac52906f5b42cd952cbe740bd5d5b086e79b
cf_stacks:
- cflinuxfs4

# Container Security Provider
# Note: Always enabled by default, provides container-specific security context
- name: container-security-provider
Expand Down
6 changes: 4 additions & 2 deletions src/java/finalize/finalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package finalize

import (
"fmt"
"github.com/cloudfoundry/java-buildpack/src/java/common"
"os"
"path/filepath"
"strings"

"github.com/cloudfoundry/java-buildpack/src/java/common"

"github.com/cloudfoundry/java-buildpack/src/java/containers"
"github.com/cloudfoundry/java-buildpack/src/java/frameworks"
Expand Down Expand Up @@ -157,7 +159,7 @@ func (f *Finalizer) finalizeFrameworks() error {
return nil
}

f.Log.Info("Finalizing frameworks: %v", frameworkNames)
f.Log.Info("Finalizing frameworks: %v", strings.Join(frameworkNames, ","))

// Finalize all detected frameworks
for i, framework := range detectedFrameworks {
Expand Down
126 changes: 126 additions & 0 deletions src/java/frameworks/cf_metrics_exporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package frameworks

import (
"fmt"
"os"
"path/filepath"

"github.com/cloudfoundry/java-buildpack/src/java/common"
"github.com/cloudfoundry/libbuildpack"
)

const cfMetricsExporterDependencyName = "cf-metrics-exporter"
const cfMetricsExporterDirName = "cf_metrics_exporter"

// Installer interface for dependency installation
// Allows for mocking in tests
// Only the InstallDependency method is needed for this framework
// (matches the signature of libbuildpack.Installer)
type Installer interface {
InstallDependency(dep libbuildpack.Dependency, outputDir string) error
}

type CfMetricsExporterFramework struct {
context *common.Context
installer Installer
}

func NewCfMetricsExporterFramework(ctx *common.Context) *CfMetricsExporterFramework {
installer := ctx.Installer
if installer == nil {
installer = libbuildpack.NewInstaller(ctx.Manifest)
}
return &CfMetricsExporterFramework{context: ctx, installer: installer}
}

func (f *CfMetricsExporterFramework) Detect() (string, error) {
enabled := os.Getenv("CF_METRICS_EXPORTER_ENABLED")
if enabled == "true" || enabled == "TRUE" {
_, err := f.context.Manifest.DefaultVersion(cfMetricsExporterDependencyName)
if err != nil {
return "", fmt.Errorf("cf-metrics-exporter version not found in manifest: %w", err)
}
return "CF Metrics Exporter", nil
}
return "", nil
}

func (f *CfMetricsExporterFramework) getManifestDependency() (libbuildpack.Dependency, *libbuildpack.ManifestEntry, error) {
dep, err := f.context.Manifest.DefaultVersion(cfMetricsExporterDependencyName)
if err != nil {
return libbuildpack.Dependency{}, nil, fmt.Errorf("cf-metrics-exporter version not found in manifest: %w", err)
}
entry, err := f.context.Manifest.GetEntry(dep)
if err != nil {
return dep, nil, fmt.Errorf("cf-metrics-exporter manifest entry not found: %w", err)
}
return dep, entry, nil
}

func (f *CfMetricsExporterFramework) Supply() error {
enabled := os.Getenv("CF_METRICS_EXPORTER_ENABLED")
if enabled != "true" && enabled != "TRUE" {
return nil
}

dep, _, err := f.getManifestDependency()
if err != nil {
return err
}

agentDir := filepath.Join(f.context.Stager.DepDir(), cfMetricsExporterDirName)
jarName := fmt.Sprintf("cf-metrics-exporter-%s.jar", dep.Version)
jarPath := filepath.Join(agentDir, jarName)

// Ensure agent directory exists
if err := os.MkdirAll(agentDir, 0755); err != nil {
return fmt.Errorf("failed to create agent dir: %w", err)
}

// Download the JAR if not present
if _, err := os.Stat(jarPath); os.IsNotExist(err) {
if err := f.installer.InstallDependency(dep, agentDir); err != nil {
return fmt.Errorf("failed to download cf-metrics-exporter: %w", err)
}
if _, err := os.Stat(jarPath); err != nil {
return fmt.Errorf("expected jar file not found after download: %w", err)
}
}

// Log activation, including properties if set
props := os.Getenv("CF_METRICS_EXPORTER_PROPS")
if props != "" {
f.context.Log.Info("CF Metrics Exporter v%s enabled, with properties: %s", dep.Version, props)
} else {
f.context.Log.Info("CF Metrics Exporter v%s enabled", dep.Version)
}

return nil
}

func (f *CfMetricsExporterFramework) Finalize() error {
enabled := os.Getenv("CF_METRICS_EXPORTER_ENABLED")
if enabled != "true" && enabled != "TRUE" {
return nil
}

dep, _, err := f.getManifestDependency()
if err != nil {
return err
}

jarName := fmt.Sprintf("cf-metrics-exporter-%s.jar", dep.Version)
depsIdx := f.context.Stager.DepsIdx()
agentPath := fmt.Sprintf("$DEPS_DIR/%s/cf_metrics_exporter/%s", depsIdx, jarName)

props := os.Getenv("CF_METRICS_EXPORTER_PROPS")
var javaOpt string
if props != "" {
javaOpt = fmt.Sprintf("-javaagent:%s=%s", agentPath, props)
} else {
javaOpt = fmt.Sprintf("-javaagent:%s", agentPath)
}

// Priority 43: after SkyWalking (41), Splunk OTEL (42)
return writeJavaOptsFile(f.context, 43, cfMetricsExporterDirName, javaOpt)
}
Loading