Skip to content

Commit fbe08ec

Browse files
committed
Stream heap dumps through hprof-redact
1 parent c95cdd4 commit fbe08ec

12 files changed

Lines changed: 546 additions & 153 deletions

File tree

‎.github/workflows/build-and-snapshot.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ jobs:
231231
```sh
232232
# on Mac arm64
233233
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-macos-arm64
234-
# on Windows x86
234+
# on Windows amd64
235235
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-windows-amd64
236-
# on Linux x86
236+
# on Linux amd64
237237
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-linux-amd64
238238
```
239239

‎.gitignore‎

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ _testmain.go
2626
# Tools
2727
counterfeiter
2828

29-
# Built binaries
29+
# Build output directories
3030
build/
3131
pkg/
3232

@@ -49,11 +49,54 @@ test/snapshots/
4949
# Heap dump files
5050
*.hprof
5151

52-
# Build artifacts
52+
# Embedded/downloaded build artifacts
5353
dist
5454

55-
# go
56-
pkg
55+
# Local project binaries
56+
requires
57+
58+
# OS/editor/local tooling
59+
.DS_Store
60+
.claude/
61+
.playwright-mcp/
62+
.test_success_cache.json
63+
*.log
64+
*.tmp
65+
*.bak
66+
*~
67+
68+
# Python local caches / coverage
69+
.coverage
70+
htmlcov/
71+
.mypy_cache/
72+
.ruff_cache/
73+
74+
# Local investigation / scratch artifacts
75+
BUG*.md
76+
FIX*.md
77+
*_REPORT.md
78+
*analysis*.py
79+
append_*.py
80+
discover*.py
81+
investigate*.py
82+
*_test_output.txt
83+
*_results.txt
84+
*.out
85+
out.zip
86+
87+
# Local runtime artifacts
88+
sapmachine21-status/
89+
sapmachine21-status.zip
90+
sapmachine21-heapdump-*.hprof.gz
91+
sapmachine21-heapdump-*-redacted.hprof.gz
92+
93+
# Local ad-hoc test helpers/artifacts
94+
test/doc_bugs_finder.py
95+
test/sapmachine21-status.zip
96+
test/test_bugs.py
97+
test_bugs.sh
98+
test_edge_cases.py
99+
test_fixes.py
57100

58101
# Internal planning docs (superpowers skill artifacts)
59102
docs/superpowers/

‎.tool.yaml‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ tag: ready
22
github_url: https://github.com/SAP/cf-cli-java-plugin
33
tagline: Cloud Foundry CLI plugin to troubleshoot Java apps running on CF without SSH. Trigger heap
44
dumps, thread dumps, and async-profiler or JFR recordings from the cf command line, with results
5-
streamed back to your machine. Also embeds jstall for full JVM inspection via `cf java jstall`.
5+
streamed back to your machine. Heap dumps can be redacted during download, kept compressed, or
6+
opened directly in hprof-analyzer. Also embeds jstall for full JVM inspection via `cf java jstall`.
67
tagline_short: Trigger heap dumps, thread dumps, and profiles from the CF CLI — no SSH needed.
78
when_to_use:
89
- You run Java apps on Cloud Foundry and need heap dumps, thread dumps, or CPU profiles
@@ -24,6 +25,7 @@ install:
2425
# Pick the binary for your platform:
2526
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/latest/download/cf-cli-java-plugin-macos-arm64
2627
# linux-amd64 / linux-arm64 / windows-amd64 / windows-arm64 also available
28+
# macOS requires Apple Silicon; macOS Intel (darwin/amd64) is not supported
2729
- label: CF Community
2830
lang: bash
2931
code: |
@@ -34,8 +36,19 @@ usage:
3436
lang: bash
3537
code: |
3638
cf java heap-dump my-app
39+
cf java heap-dump my-app --redact --open
40+
cf java heap-dump my-app --redact --compress
3741
cf java thread-dump my-app
3842
cf java jstall my-app
43+
features:
44+
- title: Stream heap dumps directly to your machine
45+
body: Capture heap dumps and thread dumps from Cloud Foundry apps without manual SSH sessions.
46+
- title: Redact sensitive heap-dump data during download
47+
body: Use `--redact` or `--redact-complete` to zero sensitive primitive data while the dump is being streamed, so an unredacted heap dump is never written locally.
48+
- title: Keep dumps compressed or open them immediately
49+
body: Use `--compress` to save `.hprof.gz` files directly, or `--open` / `--open-url` to inspect the heap dump in hprof-analyzer right after download.
50+
- title: Run bundled jstall diagnostics
51+
body: Inspect deadlocks, hot threads, flame graphs, and more via `cf java jstall` without separately installing jstall.
3952
how_to:
4053
- title: My CF app is not responding — find what it is stuck on
4154
body: |
@@ -201,6 +214,23 @@ how_to:
201214
```
202215
The unredacted dump is never written to disk — redaction happens in-memory during download.
203216
217+
- title: Capture a safer heap dump for sharing or browser analysis
218+
body: |
219+
If you need to inspect a heap dump locally or share it with others, combine redaction,
220+
compression, and browser opening as needed:
221+
```bash
222+
# Redact sensitive values and keep the dump compressed:
223+
cf java heap-dump $APP_NAME --redact --compress
224+
225+
# Redact and open immediately in hprof-analyzer:
226+
cf java heap-dump $APP_NAME --redact --open
227+
228+
# Use complete redaction for maximum privacy:
229+
cf java heap-dump $APP_NAME --redact-complete --compress
230+
```
231+
Use `--redact-keep-on-error` only if you explicitly want to keep a partially written redacted
232+
file when local redaction fails.
233+
204234
- title: Open a heap dump in hprof-analyzer
205235
body: |
206236
After downloading, the plugin can spin up a temporary local server and open

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- macOS plugin support now requires Apple Silicon. macOS Intel (`darwin/amd64`) is not supported.
13+
1014
### Added
1115

1216
- Bundle [jstall](https://github.com/parttimenerd/jstall) (jstall-minimal.jar) for one-shot JVM inspection via

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ endif
3838
# Downloaded at compile time from hprof-analyzer GitHub releases.
3939
# Uses musl-static Linux builds so the binary runs in CF containers without
4040
# glibc version constraints.
41-
HPROF_REDACT_BASE = https://github.com/parttimenerd/hprof-analyzer/releases/latest/download
41+
HPROF_REDACT_BASE = https://github.com/parttimenerd/hprof-analyzer/releases/download/nightly
4242

4343
dist/hprof-redact-linux-amd64:
4444
mkdir -p dist

‎README.md‎

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ Currently, it allows you to:
1515
([SapMachine](https://sapmachine.io) only) profiles
1616
- Run [jstall](https://github.com/parttimenerd/jstall) for one-shot JVM inspection (deadlock detection, hot threads,
1717
dependency graphs, and more): bundled directly in the plugin, requires Java 17+ locally
18-
- Redact heap dumps before saving to remove sensitive data (`--redact`, `--redact-complete`)
18+
- Redact heap dumps before saving to remove sensitive data (`--redact`, `--redact-complete`) using the bundled
19+
[`hprof-redact`](https://github.com/parttimenerd/hprof-analyzer) binary from the
20+
[`hprof-analyzer`](https://github.com/parttimenerd/hprof-analyzer) project
1921
- Automatically compress heap dump transfers over SSH on JDK 17+ containers;
2022
use `--compress` to keep the local file as `.hprof.gz`
21-
- Open heap dumps directly in the [hprof-analyzer](https://parttimenerd.github.io/hprof-analyzer) web app
22-
after downloading (`--open`)
23+
- Open heap dumps directly in the hosted
24+
[`hprof-analyzer`](https://parttimenerd.github.io/hprof-analyzer) web app after downloading (`--open`) or point the
25+
plugin at another `hprof-analyzer` instance via `--open-url`
2326

2427
## Installation
2528

@@ -44,16 +47,18 @@ Download the latest release from [GitHub](https://github.com/SAP/cf-cli-java-plu
4447
To install a new version of the plugin, run the following:
4548

4649
```sh
47-
# on Mac arm64
50+
# on Mac arm64 (Apple Silicon only)
4851
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/latest/download/cf-cli-java-plugin-macos-arm64
49-
# on Windows x64
52+
# on Windows amd64
5053
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/latest/download/cf-cli-java-plugin-windows-amd64
51-
# on Linux x64
54+
# on Linux amd64
5255
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/latest/download/cf-cli-java-plugin-linux-amd64
5356
# on Linux arm64
5457
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/latest/download/cf-cli-java-plugin-linux-arm64
5558
```
5659

60+
macOS plugin binaries currently require Apple Silicon; macOS Intel (`darwin/amd64`) is not supported.
61+
5762
You can verify that the plugin is successfully installed by looking for `java` in the output of `cf plugins`.
5863

5964
### Manual Installation of Snapshot Release
@@ -64,16 +69,18 @@ This is intended for experimentation and might fail.
6469
To install a new version of the plugin, run the following:
6570

6671
```sh
67-
# on Mac arm64
72+
# on Mac arm64 (Apple Silicon only)
6873
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-macos-arm64
69-
# on Windows x64
74+
# on Windows amd64
7075
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-windows-amd64
71-
# on Linux x64
76+
# on Linux amd64
7277
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-linux-amd64
7378
# on Linux arm64
7479
cf install-plugin https://github.com/SAP/cf-cli-java-plugin/releases/download/snapshot/cf-cli-java-plugin-linux-arm64
7580
```
7681

82+
macOS snapshot binaries currently require Apple Silicon; macOS Intel (`darwin/amd64`) is not supported.
83+
7784
## Common Tasks
7885

7986
### My CF app is not responding — find what it is stuck on
@@ -224,10 +231,15 @@ cf java heap-dump $APP_NAME --open --redact --compress
224231
cf java heap-dump $APP_NAME --open-url http://localhost:8080
225232
```
226233

234+
The browser integration uses the [`hprof-analyzer`](https://github.com/parttimenerd/hprof-analyzer) project. By
235+
default, `--open` launches the hosted web app at <https://parttimenerd.github.io/hprof-analyzer>. Use `--open-url` if
236+
you run your own local or internal `hprof-analyzer` deployment.
237+
227238
> **macOS note:** On macOS with the Application Firewall enabled, a dialog will appear asking
228239
> *"Do you want the application 'cf-cli-java-plugin' to accept incoming network connections?"*
229240
> Click **Allow** — the plugin binds a temporary local server on `127.0.0.1` to serve the file
230-
> to the browser. The server shuts down automatically after the browser fetches the file once.
241+
> to the browser. The server serves only the exact one-time heap-dump URL generated for that download,
242+
> rejects alternate paths or query parameters, and shuts down automatically after one successful fetch.
231243

232244
Getting a thread dump:
233245

@@ -359,6 +371,22 @@ cf java thread-dump [my_app] -i [my_instance_index] > thread-dump.txt
359371

360372
The `--keep` flag is not applicable to commands that stream output directly (e.g., `thread-dump`).
361373

374+
Heap dumps support additional local post-processing and analysis options:
375+
376+
- `--redact`: lean redaction mode; streams the heap dump through `hprof-redact` and zeros primitive arrays such as
377+
`byte[]`, `char[]`, and similar bulk buffers
378+
- `--redact-complete`: complete redaction mode; streams the heap dump through `hprof-redact` and zeros primitive arrays
379+
and individual primitive fields
380+
- `--redact-keep-on-error`: keeps a partially written redacted output file if local redaction fails; otherwise failed
381+
redaction leaves no local heap dump behind
382+
- `--compress`: keeps the local output as `.hprof.gz` instead of transparently decompressing it
383+
- `--open`: starts a temporary local HTTP server on `127.0.0.1`, serves the downloaded heap dump once, and opens
384+
[`hprof-analyzer`](https://parttimenerd.github.io/hprof-analyzer) automatically in your browser
385+
- `--open-url <URL>`: same as `--open`, but targets a custom hosted or self-managed `hprof-analyzer` instance
386+
387+
These features can be combined, for example: `cf java heap-dump APP --redact --compress --open`.
388+
`--open` requires a local file and therefore cannot be used with `--no-download`.
389+
362390
### Heap Dump Privacy
363391

364392
Heap dumps contain the full in-memory state of a JVM, including strings, byte arrays, and field values, which can
@@ -373,11 +401,14 @@ use `--redact` or `--redact-complete` to zero out sensitive values.
373401
Both modes preserve the full object graph (class names, references, instance counts), so the dump remains useful for
374402
memory analysis. The two flags are mutually exclusive.
375403

376-
The redacted file is saved locally with a `-redacted` suffix; the original unredacted file is deleted automatically.
404+
The redacted file is saved to the requested local heap-dump path with no extra suffix. When redaction is enabled, the
405+
heap dump is streamed directly into `hprof-redact` exactly as downloaded, including gzip-compressed `.hprof.gz`
406+
streams, so the unredacted dump is never written to local disk.
377407
Use `--redact --compress` to also compress the output (produces a `.hprof.gz`).
378408

379-
Redaction runs locally via the bundled [hprof-redact](https://github.com/parttimenerd/hprof-analyzer) binary after
380-
the dump is downloaded. Supported platforms: Linux (x86_64, arm64), macOS (Apple Silicon), Windows (x86_64, arm64).
409+
Redaction runs locally via the bundled [hprof-redact](https://github.com/parttimenerd/hprof-analyzer) binary while the
410+
dump is being downloaded. The binary is embedded from the
411+
[`hprof-analyzer`](https://github.com/parttimenerd/hprof-analyzer) project, so no separate installation is required.
381412

382413
### Compressed Transfer
383414

@@ -391,6 +422,17 @@ Without `--compress`, the plugin still uses `gz=1` automatically when the remote
391422
compressed but the local file is transparently decompressed to a plain `.hprof`. This is the default behaviour
392423
starting from JDK 17 and costs nothing from the user's perspective.
393424

425+
### Opening a Heap Dump in hprof-analyzer
426+
427+
Use `--open` to inspect the downloaded heap dump immediately in
428+
[`hprof-analyzer`](https://github.com/parttimenerd/hprof-analyzer), either via the hosted instance at
429+
<https://parttimenerd.github.io/hprof-analyzer> or via your own deployment with `--open-url`.
430+
431+
For safety, the plugin does **not** expose an arbitrary local directory. Instead, it starts a temporary local HTTP
432+
server bound to `127.0.0.1`, serves only the exact generated heap-dump for that one download, rejects alternate
433+
paths and query parameters, and shuts the server down automatically after one successful browser fetch or after a
434+
timeout if the browser never connects.
435+
394436
## Limitations
395437

396438
Some commands depend on writable filesystem space inside the application container. In particular, `cf java heap-dump`,

0 commit comments

Comments
 (0)