Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 17 additions & 15 deletions src/java/frameworks/java_memory_assistant.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,44 +126,46 @@ func (j *JavaMemoryAssistantFramework) buildAgentConfig() string {
return "" // Don't fail the build
}

// Heap dump folder (default: $PWD or volume service mount point)
heapDumpFolder := j.getHeapDumpFolder()
// Heap dump folder: config value takes priority, then volume service, then $PWD
heapDumpFolder := j.getHeapDumpFolder(config.Agent.HeapDumpFolder)
if heapDumpFolder != "" {
configParts = append(configParts, fmt.Sprintf("-Djma.heap-dump-folder=%s", heapDumpFolder))
configParts = append(configParts, fmt.Sprintf("-Djma.heap_dump_folder=%s", heapDumpFolder))
}

// Check interval (default: 5s)
checkInterval := config.Agent.CheckInterval
configParts = append(configParts, fmt.Sprintf("-Djma.check-interval=%s", checkInterval))
configParts = append(configParts, fmt.Sprintf("-Djma.check_interval=%s", checkInterval))

// Max frequency (default: 1/1m)
maxFrequency := config.Agent.MaxFrequency
configParts = append(configParts, fmt.Sprintf("-Djma.max-frequency=%s", maxFrequency))
configParts = append(configParts, fmt.Sprintf("-Djma.max_frequency=%s", maxFrequency))

// Log level (use buildpack log level if not specified)
logLevel := config.Agent.LogLevel
configParts = append(configParts, fmt.Sprintf("-Djma.log-level=%s", logLevel))
// Log level (only if set)
if logLevel := config.Agent.LogLevel; logLevel != "" {
configParts = append(configParts, fmt.Sprintf("-Djma.log_level=%s", logLevel))
}

// Thresholds (default: old_gen >600MB)
thresholds := config.getThresholds()
for memArea, threshold := range thresholds {
if threshold != "" {
configParts = append(configParts, fmt.Sprintf("-Djma.threshold.%s=%s", memArea, threshold))
configParts = append(configParts, fmt.Sprintf("-Djma.thresholds.%s=%s", memArea, threshold))
}
}

return strings.Join(configParts, " ")
}

// getHeapDumpFolder determines the heap dump folder location
// Checks for volume services named "heap-dump" or tagged with "heap-dump"
func (j *JavaMemoryAssistantFramework) getHeapDumpFolder() string {
// getHeapDumpFolder determines the heap dump folder location.
// Priority: explicit config value > volume service mount > $PWD default.
func (j *JavaMemoryAssistantFramework) getHeapDumpFolder(configuredFolder string) string {
if configuredFolder != "" {
return configuredFolder
}

// Check for volume service mounts
// This is a simplified implementation - in production, parse VCAP_SERVICES
vcapServices := os.Getenv("VCAP_SERVICES")
if vcapServices != "" && contains(vcapServices, "heap-dump") {
// If heap-dump volume service exists, use its mount point
// For now, return a placeholder that would be resolved at runtime
return "$HEAP_DUMP_VOLUME/heapdumps"
}

Expand Down
53 changes: 41 additions & 12 deletions src/java/frameworks/java_memory_assistant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,28 +151,28 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.check-interval=5s"))
Expect(string(content)).To(ContainSubstring("-Djma.check_interval=5s"))
})

It("opts file contains default max frequency", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.max-frequency=1/1m"))
Expect(string(content)).To(ContainSubstring("-Djma.max_frequency=1/1m"))
})

It("opts file contains default old_gen threshold", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.threshold.old_gen=>600MB"))
Expect(string(content)).To(ContainSubstring("-Djma.thresholds.old_gen=>600MB"))
})

It("opts file contains heap dump folder defaulting to $PWD", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.heap-dump-folder=$PWD"))
Expect(string(content)).To(ContainSubstring("-Djma.heap_dump_folder=$PWD"))
})
})

Expand All @@ -186,7 +186,7 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.check-interval=10s"))
Expect(string(content)).To(ContainSubstring("-Djma.check_interval=10s"))
})
})

Expand All @@ -200,7 +200,7 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.max-frequency=2/5m"))
Expect(string(content)).To(ContainSubstring("-Djma.max_frequency=2/5m"))
})
})

Expand All @@ -214,7 +214,7 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.threshold.old_gen=>80%"))
Expect(string(content)).To(ContainSubstring("-Djma.thresholds.old_gen=>80%"))
})
})

Expand All @@ -224,11 +224,11 @@ var _ = Describe("Java Memory Assistant", func() {
os.Setenv("JBP_CONFIG_JAVA_MEMORY_ASSISTANT", "agent:\n thresholds:\n heap: \">90%\"")
})

It("opts file contains -Djma.threshold.heap", func() {
It("opts file contains -Djma.thresholds.heap", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.threshold.heap=>90%"))
Expect(string(content)).To(ContainSubstring("-Djma.thresholds.heap=>90%"))
})
})

Expand All @@ -238,11 +238,11 @@ var _ = Describe("Java Memory Assistant", func() {
os.Setenv("JBP_CONFIG_JAVA_MEMORY_ASSISTANT", "agent:\n log_level: DEBUG")
})

It("opts file contains -Djma.log-level=DEBUG", func() {
It("opts file contains -Djma.log_level=DEBUG", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.log-level=DEBUG"))
Expect(string(content)).To(ContainSubstring("-Djma.log_level=DEBUG"))
})
})

Expand All @@ -256,7 +256,7 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.heap-dump-folder=$HEAP_DUMP_VOLUME/heapdumps"))
Expect(string(content)).To(ContainSubstring("-Djma.heap_dump_folder=$HEAP_DUMP_VOLUME/heapdumps"))
})
})

Expand Down Expand Up @@ -301,5 +301,34 @@ var _ = Describe("Java Memory Assistant", func() {
Expect(err.Error()).To(ContainSubstring("Java Memory Assistant JAR not found"))
})
})

Context("with the exact user config: enabled, heap threshold 80%, heap_dump_folder /home/vcap/, check_interval 5m", func() {
BeforeEach(func() {
installJMAAgent(depsDir, "1.2.3")
os.Setenv("JBP_CONFIG_JAVA_MEMORY_ASSISTANT",
`{enabled : true, agent: { thresholds : { heap: "80%" }, heap_dump_folder: /home/vcap/, check_interval: 5m } }`)
})

It("opts file contains -Djma.thresholds.heap=80%", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.thresholds.heap=80%"))
})

It("opts file contains -Djma.heap_dump_folder=/home/vcap/", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.heap_dump_folder=/home/vcap/"))
})

It("opts file contains -Djma.check_interval=5m", func() {
Expect(fw.Finalize()).To(Succeed())
content, err := os.ReadFile(filepath.Join(depsDir, "0", "java_opts", "28_java_memory_assistant.opts"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(ContainSubstring("-Djma.check_interval=5m"))
})
})
})
})