Skip to content

Commit 7c37c02

Browse files
committed
8244190: JFR: When starting a JVM with -XX:StartFlightRecording, output is written to stdout
Reviewed-by: mgronlun
1 parent 79adc16 commit 7c37c02

File tree

11 files changed

+163
-40
lines changed

11 files changed

+163
-40
lines changed

src/hotspot/share/jfr/dcmd/jfrDcmds.cpp

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
#include "jfr/jni/jfrJavaSupport.hpp"
3131
#include "jfr/recorder/jfrRecorder.hpp"
3232
#include "jfr/recorder/service/jfrOptionSet.hpp"
33+
#include "logging/log.hpp"
34+
#include "logging/logConfiguration.hpp"
35+
#include "logging/logMessage.hpp"
3336
#include "memory/resourceArea.hpp"
37+
#include "oops/objArrayOop.inline.hpp"
3438
#include "oops/oop.inline.hpp"
3539
#include "oops/symbol.hpp"
3640
#include "runtime/handles.inline.hpp"
@@ -128,43 +132,86 @@ static bool invalid_state(outputStream* out, TRAPS) {
128132
return is_disabled(out) || !is_module_available(out, THREAD);
129133
}
130134

131-
static void print_pending_exception(outputStream* output, oop throwable) {
135+
static void handle_pending_exception(outputStream* output, bool startup, oop throwable) {
132136
assert(throwable != NULL, "invariant");
133137

134138
oop msg = java_lang_Throwable::message(throwable);
135-
136-
if (msg != NULL) {
137-
char* text = java_lang_String::as_utf8_string(msg);
138-
output->print_raw_cr(text);
139+
if (msg == NULL) {
140+
return;
141+
}
142+
char* text = java_lang_String::as_utf8_string(msg);
143+
if (text != NULL) {
144+
if (startup) {
145+
log_error(jfr,startup)("%s", text);
146+
} else {
147+
output->print_cr("%s", text);
148+
}
139149
}
140150
}
141151

142-
static void print_message(outputStream* output, const char* message) {
143-
if (message != NULL) {
144-
output->print_raw(message);
152+
static void print_message(outputStream* output, oop content, TRAPS) {
153+
objArrayOop lines = objArrayOop(content);
154+
assert(lines != NULL, "invariant");
155+
assert(lines->is_array(), "must be array");
156+
const int length = lines->length();
157+
for (int i = 0; i < length; ++i) {
158+
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
159+
if (text == NULL) {
160+
// An oome has been thrown and is pending.
161+
break;
162+
}
163+
output->print_cr("%s", text);
145164
}
146165
}
147166

167+
static void log(oop content, TRAPS) {
168+
LogMessage(jfr,startup) msg;
169+
objArrayOop lines = objArrayOop(content);
170+
assert(lines != NULL, "invariant");
171+
assert(lines->is_array(), "must be array");
172+
const int length = lines->length();
173+
for (int i = 0; i < length; ++i) {
174+
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
175+
if (text == NULL) {
176+
// An oome has been thrown and is pending.
177+
break;
178+
}
179+
msg.info("%s", text);
180+
}
181+
}
182+
148183
static void handle_dcmd_result(outputStream* output,
149184
const oop result,
150185
const DCmdSource source,
151186
TRAPS) {
152187
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
153188
assert(output != NULL, "invariant");
189+
const bool startup = DCmd_Source_Internal == source;
154190
if (HAS_PENDING_EXCEPTION) {
155-
print_pending_exception(output, PENDING_EXCEPTION);
191+
handle_pending_exception(output, startup, PENDING_EXCEPTION);
156192
// Don't clear excption on startup, JVM should fail initialization.
157-
if (DCmd_Source_Internal != source) {
193+
if (!startup) {
158194
CLEAR_PENDING_EXCEPTION;
159195
}
160196
return;
161197
}
162198

163199
assert(!HAS_PENDING_EXCEPTION, "invariant");
164200

165-
if (result != NULL) {
166-
const char* result_chars = java_lang_String::as_utf8_string(result);
167-
print_message(output, result_chars);
201+
if (startup) {
202+
if (log_is_enabled(Warning, jfr, startup)) {
203+
// if warning is set, assume user hasn't configured log level
204+
// Log to Info and reset to Warning. This way user can disable
205+
// default output by setting -Xlog:jfr+startup=error/off
206+
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(jfr, startup));
207+
log(result, THREAD);
208+
LogConfiguration::configure_stdout(LogLevel::Warning, true, LOG_TAGS(jfr, startup));
209+
} else {
210+
log(result, THREAD);
211+
}
212+
} else {
213+
// Print output for jcmd or MXBean
214+
print_message(output, result, THREAD);
168215
}
169216
}
170217

@@ -261,7 +308,7 @@ void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
261308

262309
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdDump";
263310
static const char method[] = "execute";
264-
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
311+
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)[Ljava/lang/String;";
265312

266313
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
267314
execute_args.set_receiver(h_dcmd_instance);
@@ -327,7 +374,7 @@ void JfrCheckFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
327374

328375
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdCheck";
329376
static const char method[] = "execute";
330-
static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
377+
static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)[Ljava/lang/String;";
331378

332379
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
333380
execute_args.set_receiver(h_dcmd_instance);
@@ -471,7 +518,7 @@ void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
471518
static const char method[] = "execute";
472519
static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
473520
"Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
474-
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
521+
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)[Ljava/lang/String;";
475522

476523
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
477524
execute_args.set_receiver(h_dcmd_instance);
@@ -541,7 +588,7 @@ void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
541588

542589
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop";
543590
static const char method[] = "execute";
544-
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
591+
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;";
545592

546593
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
547594
execute_args.set_receiver(h_dcmd_instance);
@@ -654,7 +701,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
654701
static const char method[] = "execute";
655702
static const char signature[] = "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
656703
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
657-
"Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
704+
"Ljava/lang/Long;Ljava/lang/Boolean;)[Ljava/lang/String;";
658705

659706
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
660707
execute_args.set_receiver(h_dcmd_instance);

src/hotspot/share/logging/logTag.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
LOG_TAG(stacktrace) \
166166
LOG_TAG(stackwalk) \
167167
LOG_TAG(start) \
168+
LOG_TAG(startup) \
168169
LOG_TAG(startuptime) \
169170
LOG_TAG(state) \
170171
LOG_TAG(stats) \

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
package jdk.jfr.internal.dcmd;
2626

2727
import java.io.IOException;
28-
import java.io.PrintWriter;
29-
import java.io.StringWriter;
3028
import java.nio.file.Files;
3129
import java.nio.file.InvalidPathException;
3230
import java.nio.file.Path;
@@ -50,20 +48,15 @@
5048
*/
5149
abstract class AbstractDCmd {
5250

53-
private final StringWriter result;
54-
private final PrintWriter log;
55-
56-
protected AbstractDCmd() {
57-
result = new StringWriter();
58-
log = new PrintWriter(result);
59-
}
51+
private final StringBuilder currentLine = new StringBuilder(80);
52+
private final List<String> lines = new ArrayList<>();
6053

6154
protected final FlightRecorder getFlightRecorder() {
6255
return FlightRecorder.getFlightRecorder();
6356
}
6457

65-
public final String getResult() {
66-
return result.toString();
58+
public final String[] getResult() {
59+
return lines.toArray(new String[lines.size()]);
6760
}
6861

6962
public String getPid() {
@@ -136,15 +129,16 @@ static String quoteIfNeeded(String text) {
136129
}
137130

138131
protected final void println() {
139-
log.println();
132+
lines.add(currentLine.toString());
133+
currentLine.setLength(0);
140134
}
141135

142136
protected final void print(String s) {
143-
log.print(s);
137+
currentLine.append(s);
144138
}
145139

146140
protected final void print(String s, Object... args) {
147-
log.printf(s, args);
141+
currentLine.append(String.format(s, args));
148142
}
149143

150144
protected final void println(String s, Object... args) {

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ final class DCmdCheck extends AbstractDCmd {
5858
*
5959
* @throws DCmdException if the check could not be completed.
6060
*/
61-
public String execute(String recordingText, Boolean verbose) throws DCmdException {
61+
public String[] execute(String recordingText, Boolean verbose) throws DCmdException {
6262
executeInternal(recordingText, verbose);
6363
return getResult();
6464
}

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ final class DCmdConfigure extends AbstractDCmd {
5959
* @throws DCmdException
6060
* if the dump could not be completed
6161
*/
62-
public String execute
62+
public String[] execute
6363
(
6464
boolean verbose,
6565
String repositoryPath,
@@ -177,7 +177,7 @@ final class DCmdConfigure extends AbstractDCmd {
177177
updated = true;
178178
}
179179
if (!verbose) {
180-
return "";
180+
return new String[0];
181181
}
182182
if (!updated) {
183183
println("Current configuration:");

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ final class DCmdDump extends AbstractDCmd {
6969
*
7070
* @throws DCmdException if the dump could not be completed
7171
*/
72-
public String execute(String name, String filename, Long maxAge, Long maxSize, String begin, String end, Boolean pathToGcRoots) throws DCmdException {
72+
public String[] execute(String name, String filename, Long maxAge, Long maxSize, String begin, String end, Boolean pathToGcRoots) throws DCmdException {
7373
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
7474
Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG,
7575
"Executing DCmdDump: name=" + name +

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ final class DCmdStart extends AbstractDCmd {
8282
* @throws DCmdException if recording could not be started
8383
*/
8484
@SuppressWarnings("resource")
85-
public String execute(String name, String[] settings, Long delay, Long duration, Boolean disk, String path, Long maxAge, Long maxSize, Long flush, Boolean dumpOnExit, Boolean pathToGcRoots) throws DCmdException {
85+
public String[] execute(String name, String[] settings, Long delay, Long duration, Boolean disk, String path, Long maxAge, Long maxSize, Long flush, Boolean dumpOnExit, Boolean pathToGcRoots) throws DCmdException {
8686
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
8787
Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG, "Executing DCmdStart: name=" + name +
8888
", settings=" + Arrays.asList(settings) +

src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final class DCmdStop extends AbstractDCmd {
5555
*
5656
* @throws DCmdException if recording could not be stopped
5757
*/
58-
public String execute(String name, String filename) throws DCmdException {
58+
public String[] execute(String name, String filename) throws DCmdException {
5959
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
6060
Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG, "Executing DCmdStart: name=" + name + ", filename=" + filename);
6161
}

test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndCP_JFR.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
public class ModulePathAndCP_JFR {
3636
public static void main(String... args) throws Exception {
37-
ModulePathAndCP.run("-XX:StartFlightRecording=dumponexit=true", "-Xlog:cds+jvmti=debug");
37+
ModulePathAndCP.run("-XX:StartFlightRecording=dumponexit=true", "-Xlog:cds+jvmti=debug,jfr+startup=off");
3838
}
3939
}
4040

test/jdk/jdk/jfr/jcmd/JcmdAsserts.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
public class JcmdAsserts {
3737

38-
private static final String NEW_LINE = System.getProperty("line.separator");
38+
private static final String NEW_LINE = "\n";
3939

4040
public static void assertJfrNotUsed(OutputAnalyzer output) {
4141
output.shouldMatch("Flight Recorder has not been used");

0 commit comments

Comments
 (0)