Skip to content

Commit 5d68964

Browse files
committed
Fix JFR start and stop
1 parent 2d523a4 commit 5d68964

File tree

2 files changed

+65
-28
lines changed

2 files changed

+65
-28
lines changed

README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,16 @@ USAGE:
169169
Run a JCMD command on a running Java application via --args, downloads and deletes all files that are created in the current folder, use '--no-download' to prevent this
170170

171171
jfr-start
172-
Start a Java Flight Recorder default recording on a running Java application
172+
Start a Java Flight Recorder default recording on a running Java application (stores in the the container-dir)
173173

174174
jfr-start-profile
175-
Start a Java Flight Recorder profile recording on a running Java application
175+
Start a Java Flight Recorder profile recording on a running Java application (stores in the the container-dir))
176176

177177
jfr-start-gc (recent SapMachine only)
178-
Start a Java Flight Recorder GC recording on a running Java application
178+
Start a Java Flight Recorder GC recording on a running Java application (stores in the the container-dir)
179179

180180
jfr-start-gc-details (recent SapMachine only)
181-
Start a Java Flight Recorder detailed GC recording on a running Java application
181+
Start a Java Flight Recorder detailed GC recording on a running Java application (stores in the the container-dir)
182182

183183
jfr-stop
184184
Stop a Java Flight Recorder recording on a running Java application
@@ -196,7 +196,7 @@ USAGE:
196196
Print vital statistics about the Java Virtual Machine running a Java application
197197

198198
asprof (recent SapMachine only, supports --args)
199-
Run async-profiler commands passed to asprof via --args, copies files in the current folder. Don't use in combination with asprof-* commands. Downloads and deletes all files that are created in the current folder, use '--no-download' to prevent this
199+
Run async-profiler commands passed to asprof via --args, copies files in the current folder. Don't use in combination with asprof-* commands. Downloads and deletes all files that are created in the current folder, if not using 'start' asprof command, use '--no-download' to prevent this.
200200

201201
asprof-start-cpu (recent SapMachine only)
202202
Start an async-profiler CPU-time profile recording on a running Java application
@@ -217,13 +217,13 @@ USAGE:
217217
Get the status of async-profiler on a running Java application
218218

219219
OPTIONS:
220-
-dry-run -n, just output to command line what would be executed
221-
-keep -k, keep the heap dump in the container; by default the heap dump/JFR/... will be deleted from the container's filesystem after been downloaded
222220
-local-dir -ld, the local directory path that the dump/JFR/... file will be saved to, defaults to the current directory
223221
-no-download -nd, don't download the heap dump/JFR/... file to local, only keep it in the container, implies '--keep'
224222
-app-instance-index -i [index], select to which instance of the app to connect
225223
-args -a, Miscellaneous arguments to pass to the command (if supported) in the container, be aware to end it with a space if it is a simple option
226224
-container-dir -cd, the directory path in the container that the heap dump/JFR/... file will be saved to
225+
-dry-run -n, just output to command line what would be executed
226+
-keep -k, keep the heap dump in the container; by default the heap dump/JFR/... will be deleted from the container's filesystem after been downloaded
227227
</pre>
228228

229229
The heap dumps and profiles will be copied to a local file if `-local-dir` is specified as a full folder path. Without providing `-local-dir` the heap dump will only be created in the container and not transferred.

cf_cli_java_plugin.go

+58-21
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,15 @@ func (u uuidGeneratorImpl) Generate() string {
5757

5858
const (
5959
// JavaDetectionCommand is the prologue command to detect on the Garden container if it contains a Java app. Visible for tests
60-
JavaDetectionCommand = "if ! pgrep -x \"java\" > /dev/null; then echo \"No 'java' process found running. Are you sure this is a Java app?\" >&2; exit 1; fi"
60+
JavaDetectionCommand = "if ! pgrep -x \"java\" > /dev/null; then echo \"No 'java' process found running. Are you sure this is a Java app?\" >&2; exit 1; fi"
61+
CheckNoCurrentJFRRecordingCommand = `OUTPUT=$($JCMD_COMMAND $(pidof java) JFR.check 2>&1); if [[ ! "$OUTPUT" == *"No available recording"* ]]; then echo "JFR recording already running. Stop it before starting a new recording."; exit 1; fi;`
62+
FilterJCMDRemoteMessage = `filter_jcmd_remote_message() {
63+
if command -v grep >/dev/null 2>&1; then
64+
grep -v -e "Connected to remote JVM" -e "JVM response code = 0"
65+
else
66+
cat # fallback: just pass through the input unchanged
67+
fi
68+
};`
6169
)
6270

6371
// Run must be implemented by any plugin because it is part of the
@@ -75,7 +83,9 @@ const (
7583
func (c *JavaPlugin) Run(cliConnection plugin.CliConnection, args []string) {
7684
_, err := c.DoRun(&commandExecutorImpl{cliConnection: cliConnection}, &uuidGeneratorImpl{}, utils.CfJavaPluginUtilImpl{}, args)
7785
if err != nil {
78-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
86+
if err.Error() != "unexpected EOF" {
87+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
88+
}
7989
os.Exit(1)
8090
}
8191
}
@@ -87,6 +97,9 @@ func (c *JavaPlugin) DoRun(commandExecutor cmd.CommandExecutor, uuidGenerator uu
8797

8898
output, err := c.execute(commandExecutor, uuidGenerator, util, args)
8999
if err != nil {
100+
if err.Error() == "unexpected EOF" {
101+
return output, err
102+
}
90103
ui.Failed(err.Error())
91104

92105
if _, invalidUsageErr := err.(*InvalidUsageError); invalidUsageErr {
@@ -113,7 +126,7 @@ type Command struct {
113126
RequiredTools []string
114127
GenerateFiles bool
115128
NeedsFileName bool
116-
// use $$FILENAME to get the generated file Name and $$FSPATH to get the path where the file is stored
129+
// use $$FILE_NAME to get the generated file Name and $$FSPATH to get the path where the file is stored
117130
SshCommand string
118131
FilePattern string
119132
FileExtension string
@@ -177,7 +190,7 @@ fi`,
177190
Description: "Print information about the Java Virtual Machine running a Java application",
178191
RequiredTools: []string{"jcmd"},
179192
GenerateFiles: false,
180-
SshCommand: `$JCMD_COMMAND $(pidof java) VM.info`,
193+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) VM.info | filter_jcmd_remote_message`,
181194
},
182195
{
183196
Name: "jcmd",
@@ -188,33 +201,57 @@ fi`,
188201
},
189202
{
190203
Name: "jfr-start",
191-
Description: "Start a Java Flight Recorder default recording on a running Java application",
204+
Description: "Start a Java Flight Recorder default recording on a running Java application (stores in the the container-dir)",
192205
RequiredTools: []string{"jcmd"},
193206
GenerateFiles: false,
194-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.start settings=profile.jfc; echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
207+
NeedsFileName: true,
208+
FileExtension: ".jfr",
209+
FileLabel: "JFR recording",
210+
FileNamePart: "jfr",
211+
SshCommand: FilterJCMDRemoteMessage + CheckNoCurrentJFRRecordingCommand +
212+
`$JCMD_COMMAND $(pidof java) JFR.start settings=default.jfc filename=$$FILE_NAME name=JFR | filter_jcmd_remote_message;
213+
echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
195214
},
196215
{
197216
Name: "jfr-start-profile",
198-
Description: "Start a Java Flight Recorder profile recording on a running Java application",
217+
Description: "Start a Java Flight Recorder profile recording on a running Java application (stores in the the container-dir))",
199218
RequiredTools: []string{"jcmd"},
200219
GenerateFiles: false,
201-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.start settings=profile.jfc; echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
220+
NeedsFileName: true,
221+
FileExtension: ".jfr",
222+
FileLabel: "JFR recording",
223+
FileNamePart: "jfr",
224+
SshCommand: FilterJCMDRemoteMessage + CheckNoCurrentJFRRecordingCommand +
225+
`$JCMD_COMMAND $(pidof java) JFR.start settings=profile.jfc filename=$$FILE_NAME name=JFR | filter_jcmd_remote_message;
226+
echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
202227
},
203228
{
204229
Name: "jfr-start-gc",
205-
Description: "Start a Java Flight Recorder GC recording on a running Java application",
230+
Description: "Start a Java Flight Recorder GC recording on a running Java application (stores in the the container-dir)",
206231
RequiredTools: []string{"jcmd"},
207232
GenerateFiles: false,
208233
OnlyOnRecentSapMachine: true,
209-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.start settings=gc.jfc; echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
234+
NeedsFileName: true,
235+
FileExtension: ".jfr",
236+
FileLabel: "JFR recording",
237+
FileNamePart: "jfr",
238+
SshCommand: FilterJCMDRemoteMessage + CheckNoCurrentJFRRecordingCommand +
239+
`$JCMD_COMMAND $(pidof java) JFR.start settings=gc.jfc filename=$$FILE_NAME name=JFR | filter_jcmd_remote_message;
240+
echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
210241
},
211242
{
212243
Name: "jfr-start-gc-details",
213-
Description: "Start a Java Flight Recorder detailed GC recording on a running Java application",
244+
Description: "Start a Java Flight Recorder detailed GC recording on a running Java application (stores in the the container-dir)",
214245
RequiredTools: []string{"jcmd"},
215246
GenerateFiles: false,
216247
OnlyOnRecentSapMachine: true,
217-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.start settings=gc_details.jfc; echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
248+
NeedsFileName: true,
249+
FileExtension: ".jfr",
250+
FileLabel: "JFR recording",
251+
FileNamePart: "jfr",
252+
SshCommand: FilterJCMDRemoteMessage + CheckNoCurrentJFRRecordingCommand +
253+
`$JCMD_COMMAND $(pidof java) JFR.start settings=gc_details.jfc filename=$$FILE_NAME name=JFR | filter_jcmd_remote_message;
254+
echo "Use 'cf java jfr-stop $$APP_NAME' to copy the file to the local folder"`,
218255
},
219256
{
220257
Name: "jfr-stop",
@@ -224,7 +261,7 @@ fi`,
224261
FileExtension: ".jfr",
225262
FileLabel: "JFR recording",
226263
FileNamePart: "jfr",
227-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.stop filename=$$FILE_NAME; $JCMD_COMMAND $(pidof java) JFR.stop`,
264+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) JFR.stop name=JFR | filter_jcmd_remote_message`,
228265
},
229266
{
230267
Name: "jfr-dump",
@@ -234,28 +271,28 @@ fi`,
234271
FileExtension: ".jfr",
235272
FileLabel: "JFR recording",
236273
FileNamePart: "jfr",
237-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.dump filename=$$FILE_NAME; $JCMD_COMMAND $(pidof java) JFR.stop`,
274+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) JFR.dump | filter_jcmd_remote_message`,
238275
},
239276
{
240277
Name: "jfr-status",
241278
Description: "Check the running Java Flight Recorder recording on a running Java application",
242279
RequiredTools: []string{"jcmd"},
243280
GenerateFiles: false,
244-
SshCommand: `$JCMD_COMMAND $(pidof java) JFR.check`,
281+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) JFR.check | filter_jcmd_remote_message`,
245282
},
246283
{
247284
Name: "vm-version",
248285
Description: "Print the version of the Java Virtual Machine running a Java application",
249286
RequiredTools: []string{"jcmd"},
250287
GenerateFiles: false,
251-
SshCommand: `$JCMD_COMMAND $(pidof java) VM.version`,
288+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) VM.version | filter_jcmd_remote_message`,
252289
},
253290
{
254291
Name: "vm-vitals",
255292
Description: "Print vital statistics about the Java Virtual Machine running a Java application",
256293
RequiredTools: []string{"jcmd"},
257294
GenerateFiles: false,
258-
SshCommand: `$JCMD_COMMAND $(pidof java) VM.vitals`,
295+
SshCommand: FilterJCMDRemoteMessage + `$JCMD_COMMAND $(pidof java) VM.vitals | filter_jcmd_remote_message`,
259296
},
260297
{
261298
Name: "asprof",
@@ -265,7 +302,7 @@ fi`,
265302
GenerateFiles: false,
266303
GenerateArbitraryFiles: true,
267304
GenerateArbitraryFilesFolderName: "asprof",
268-
SshCommand: `$ASPROF_COMMAND $(pidof java) $$ARGS || true`,
305+
SshCommand: `$ASPROF_COMMAND $(pidof java) $$ARGS`,
269306
},
270307
{
271308
Name: "asprof-start-cpu",
@@ -431,7 +468,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
431468
if len(trimmedMiscArgs) > 6 && trimmedMiscArgs[:6] == "start " {
432469
noDownload = true
433470
} else {
434-
noDownload = trimmedMiscArgs == "start";
471+
noDownload = trimmedMiscArgs == "start"
435472
}
436473
}
437474
if !command.HasMiscArgs() && commandFlags.IsSet("args") {
@@ -515,7 +552,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
515552

516553
output, err := commandExecutor.Execute(fullCommand)
517554

518-
if command.GenerateFiles && !noDownload{
555+
if command.GenerateFiles && !noDownload {
519556

520557
finalFile := ""
521558
var err error
@@ -635,7 +672,7 @@ func (c *JavaPlugin) GetMetadata() plugin.PluginMetadata {
635672
Usage: usageText,
636673
Options: map[string]string{
637674
"app-instance-index": "-i [index], select to which instance of the app to connect",
638-
"no-download": "-nd, don't download the heap dump/JFR/... file to local, only keep it in the container, implies '--keep'",
675+
"no-download": "-nd, don't download the heap dump/JFR/... file to local, only keep it in the container, implies '--keep'",
639676
"keep": "-k, keep the heap dump in the container; by default the heap dump/JFR/... will be deleted from the container's filesystem after been downloaded",
640677
"dry-run": "-n, just output to command line what would be executed",
641678
"container-dir": "-cd, the directory path in the container that the heap dump/JFR/... file will be saved to",

0 commit comments

Comments
 (0)