-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathyour_kit_profiler.go
More file actions
146 lines (120 loc) · 5.11 KB
/
your_kit_profiler.go
File metadata and controls
146 lines (120 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Cloud Foundry Java Buildpack
// Copyright 2013-2025 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.
package frameworks
import (
"fmt"
"github.com/cloudfoundry/java-buildpack/src/java/common"
"os"
"path/filepath"
"github.com/cloudfoundry/libbuildpack"
)
// YourKitProfilerFramework represents the YourKit profiler framework
type YourKitProfilerFramework struct {
context *common.Context
}
// NewYourKitProfilerFramework creates a new YourKitProfilerFramework instance
func NewYourKitProfilerFramework(ctx *common.Context) *YourKitProfilerFramework {
return &YourKitProfilerFramework{context: ctx}
}
// Detect returns the framework name if YourKit is explicitly enabled
func (f *YourKitProfilerFramework) Detect() (string, error) {
// YourKit is disabled by default
// Check for JBP_CONFIG_YOUR_KIT_PROFILER='{enabled: true}'
enabled := os.Getenv("JBP_CONFIG_YOUR_KIT_PROFILER")
if enabled != "" {
// Simple check - if env var contains "enabled" and "true"
if common.ContainsIgnoreCase(enabled, "enabled") && common.ContainsIgnoreCase(enabled, "true") {
return "YourKit Profiler", nil
}
}
return "", nil
}
// Supply downloads and installs the YourKit profiler native library
func (f *YourKitProfilerFramework) Supply() error {
f.context.Log.Debug("YourKit Profiler Supply phase")
// Get version from manifest
dep := libbuildpack.Dependency{Name: "your-kit-profiler", Version: ""}
version, err := f.context.Manifest.DefaultVersion(dep.Name)
if err != nil {
return fmt.Errorf("failed to get default version for your-kit-profiler: %w", err)
}
dep.Version = version.Version
// Install directory
installDir := filepath.Join(f.context.Stager.DepDir(), "your_kit_profiler")
f.context.Log.BeginStep("Installing YourKit Profiler %s", dep.Version)
// Download and extract native library
if err := f.context.Installer.InstallDependency(dep, installDir); err != nil {
return fmt.Errorf("failed to install your-kit-profiler: %w", err)
}
f.context.Log.Info("YourKit Profiler installed successfully")
return nil
}
// findYourKitAgent searches for the YourKit agent library in the install directory
func (f *YourKitProfilerFramework) findYourKitAgent(installDir string) (string, error) {
// YourKit for linux-x86-64 (the buildpack target platform)
// Must filter by architecture to avoid ARM64 version if present
return FindFileInDirectoryWithArchFilter(
installDir,
"libyjpagent.so",
[]string{"bin/linux-x86-64"},
[]string{"linux-x86-64"},
)
}
// Finalize configures the YourKit profiler runtime environment
func (f *YourKitProfilerFramework) Finalize() error {
f.context.Log.Debug("YourKit Profiler Finalize phase")
installDir := filepath.Join(f.context.Stager.DepDir(), "your_kit_profiler")
// Find the native library (libyjpagent.so)
agentPath, err := f.findYourKitAgent(installDir)
if err != nil {
return fmt.Errorf("failed to locate yourkit agent: %w", err)
}
f.context.Log.Debug("Found YourKit agent at: %s", agentPath)
// Get buildpack index for multi-buildpack support
depsIdx := f.context.Stager.DepsIdx()
// Convert staging path to runtime path
relPath, err := filepath.Rel(f.context.Stager.DepDir(), agentPath)
if err != nil {
return fmt.Errorf("failed to compute relative path: %w", err)
}
runtimeAgentPath := filepath.Join(fmt.Sprintf("$DEPS_DIR/%s", depsIdx), relPath)
// Build agent options
// Default options: dir=<home>/yourkit, logdir=<home>/yourkit, port=10001, sessionname=<space>:<app>
runtimeHomeDir := fmt.Sprintf("$DEPS_DIR/%s/yourkit", depsIdx)
// Create home directory at staging time
homeDir := filepath.Join(f.context.Stager.DepDir(), "yourkit")
if err := os.MkdirAll(homeDir, 0755); err != nil {
return fmt.Errorf("failed to create yourkit directory: %w", err)
}
// Get session name from VCAP_APPLICATION (space:app)
sessionName := "cloudfoundry"
// Get port from config (default: 10001)
port := "10001"
portConfig := os.Getenv("JBP_CONFIG_YOUR_KIT_PROFILER")
if portConfig != "" && common.ContainsIgnoreCase(portConfig, "port") {
// Simple extraction (would need proper YAML parsing in production)
// For now, use default
}
// Build agent path with options using runtime paths
agentOptions := fmt.Sprintf("dir=%s,logdir=%s,port=%s,sessionname=%s",
runtimeHomeDir, runtimeHomeDir, port, sessionName)
javaAgent := fmt.Sprintf("-agentpath:%s=%s", runtimeAgentPath, agentOptions)
// Write to .opts file using priority 45
if err := writeJavaOptsFile(f.context, 45, "your_kit_profiler", javaAgent); err != nil {
return fmt.Errorf("failed to write java_opts file: %w", err)
}
f.context.Log.Info("YourKit Profiler configured (priority 45)")
return nil
}