diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java index d0b95df8484..516d094b5da 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java @@ -30,7 +30,6 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -288,41 +287,4 @@ abstract class AbstractDCmd { return "/directory/recordings"; } } - - static String expandFilename(String filename) { - if (filename == null || filename.indexOf('%') == -1) { - return filename; - } - - String pid = null; - String time = null; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < filename.length(); i++) { - char c = filename.charAt(i); - if (c == '%' && i < filename.length() - 1) { - char nc = filename.charAt(i + 1); - if (nc == '%') { // %% ==> % - sb.append('%'); - i++; - } else if (nc == 'p') { - if (pid == null) { - pid = JVM.getPid(); - } - sb.append(pid); - i++; - } else if (nc == 't') { - if (time == null) { - time = ValueFormatter.formatDateTime(LocalDateTime.now()); - } - sb.append(time); - i++; - } else { - sb.append('%'); - } - } else { - sb.append(c); - } - } - return sb.toString(); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java index 43a8bb96874..151456745b0 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java @@ -25,14 +25,18 @@ package jdk.jfr.internal.dcmd; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringJoiner; + +import jdk.jfr.internal.JVM; import jdk.jfr.internal.util.SpellChecker; import jdk.jfr.internal.util.TimespanUnit; +import jdk.jfr.internal.util.ValueFormatter; final class ArgumentParser { private final Map options = new HashMap<>(); @@ -226,10 +230,54 @@ final class ArgumentParser { case "BOOLEAN" -> parseBoolean(name, text); case "NANOTIME" -> parseNanotime(name, text); case "MEMORY SIZE" -> parseMemorySize(name, text); + case "FILE" -> text == null ? "" : parseFilename(text); default -> throw new InternalError("Unknown type: " + type); }; } + /** + * Expands filename arguments replacing '%p' with the PID + * and '%t' with the time in 'yyyy_MM_dd_HH_mm_ss' format. + * @param filename a filename to be expanded + * @return filename with expanded arguments + */ + private String parseFilename(String filename) { + if (filename == null || filename.indexOf('%') == -1) { + return filename; + } + + String pid = null; + String time = null; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < filename.length(); i++) { + char c = filename.charAt(i); + if (c == '%' && i < filename.length() - 1) { + char nc = filename.charAt(i + 1); + if (nc == '%') { // %% ==> % + sb.append('%'); + i++; + } else if (nc == 'p') { + if (pid == null) { + pid = JVM.getPid(); + } + sb.append(pid); + i++; + } else if (nc == 't') { + if (time == null) { + time = ValueFormatter.formatDateTime(LocalDateTime.now()); + } + sb.append(time); + i++; + } else { + sb.append('%'); + } + } else { + sb.append(c); + } + } + return sb.toString(); + } + private Long parseLong(String name, String text) { if (text == null) { throw new IllegalArgumentException("Parsing error long value: syntax error, value is null"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java index 30d916b30e5..7f68ba7ee79 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java @@ -55,7 +55,7 @@ final class DCmdDump extends AbstractDCmd { public void execute(ArgumentParser parser) throws DCmdException { parser.checkUnknownArguments(); String name = parser.getOption("name"); - String filename = expandFilename(parser.getOption("filename")); + String filename = parser.getOption("filename"); Long maxAge = parser.getOption("maxage"); Long maxSize = parser.getOption("maxsize"); String begin = parser.getOption("begin"); @@ -230,7 +230,7 @@ final class DCmdDump extends AbstractDCmd { dumped. If no filename is given, a filename is generated from the PID and the current date. The filename may also be a directory in which case, the filename is generated from the PID and the current date in - the specified directory. (STRING, no default value) + the specified directory. (FILE, no default value) Note: If a filename is given, '%%p' in the filename will be replaced by the PID, and '%%t' will be replaced by the time in @@ -284,7 +284,7 @@ final class DCmdDump extends AbstractDCmd { "STRING", false, true, null, false), new Argument("filename", "Copy recording data to file, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, null, false), + "FILE", false, true, null, false), new Argument("maxage", "Maximum duration to dump, in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, true, null, false), diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index 8424fa4a811..26c095541b6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java @@ -80,7 +80,7 @@ final class DCmdStart extends AbstractDCmd { Long delay = parser.getOption("delay"); Long duration = parser.getOption("duration"); Boolean disk = parser.getOption("disk"); - String path = expandFilename(parser.getOption("filename")); + String path = parser.getOption("filename"); Long maxAge = parser.getOption("maxage"); Long maxSize = parser.getOption("maxsize"); Long flush = parser.getOption("flush-interval"); @@ -377,7 +377,7 @@ final class DCmdStart extends AbstractDCmd { placed in the directory where the process was started. The filename may also be a directory in which case, the filename is generated from the PID and the current date in the specified - directory. (STRING, no default value) + directory. (FILE, no default value) Note: If a filename is given, '%p' in the filename will be replaced by the PID, and '%t' will be replaced by the time in @@ -501,7 +501,7 @@ final class DCmdStart extends AbstractDCmd { "BOOLEAN", false, true, "true", false), new Argument("filename", "Resulting recording filename, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, "hotspot-pid-xxxxx-id-y-YYYY_MM_dd_HH_mm_ss.jfr", false), + "FILE", false, true, "hotspot-pid-xxxxx-id-y-YYYY_MM_dd_HH_mm_ss.jfr", false), new Argument("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, true, "0", false), diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java index 92d2d28b472..5cf983645c6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java @@ -44,7 +44,7 @@ final class DCmdStop extends AbstractDCmd { protected void execute(ArgumentParser parser) throws DCmdException { parser.checkUnknownArguments(); String name = parser.getOption("name"); - String filename = expandFilename(parser.getOption("filename")); + String filename = parser.getOption("filename"); try { Recording recording = findRecording(name); WriteableUserPath path = PrivateAccess.getInstance().getPlatformRecording(recording).getDestination(); @@ -80,7 +80,7 @@ final class DCmdStop extends AbstractDCmd { filename (Optional) Name of the file to which the recording is written when the recording is stopped. If no path is provided, the data from the recording - is discarded. (STRING, no default value) + is discarded. (FILE, no default value) Note: If a path is given, '%%p' in the path will be replaced by the PID, and '%%t' will be replaced by the time in 'yyyy_MM_dd_HH_mm_ss' format. @@ -107,7 +107,7 @@ final class DCmdStop extends AbstractDCmd { "STRING", true, true, null, false), new Argument("filename", "Copy recording data to file, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, null, false) + "FILE", false, true, null, false) }; } }