8273471: Add foldmultilines to UL for stdout/err
Reviewed-by: dholmes, iklam
This commit is contained in:
parent
c54a918a0e
commit
8d73ee684a
src
hotspot/share/logging
java.base/share/man
test/hotspot
@ -404,7 +404,40 @@ bool LogConfiguration::parse_command_line_arguments(const char* opts) {
|
||||
char* output_options = substrings[3];
|
||||
char errbuf[512];
|
||||
stringStream ss(errbuf, sizeof(errbuf));
|
||||
bool success = parse_log_arguments(output, what, decorators, output_options, &ss);
|
||||
bool success = true;
|
||||
|
||||
// output options for stdout/err should be applied just once.
|
||||
static bool stdout_configured = false;
|
||||
static bool stderr_configured = false;
|
||||
|
||||
// Normally options can't be used to change an existing output
|
||||
// (parse_log_arguments() will report an error), and
|
||||
// both StdoutLog and StderrLog are created by static initializers,
|
||||
// so we have to process their options (e.g. foldmultilines) directly first.
|
||||
if (output == NULL || strlen(output) == 0 ||
|
||||
strcmp("stdout", output) == 0 || strcmp("#0", output) == 0) {
|
||||
if (!stdout_configured) {
|
||||
success = StdoutLog.parse_options(output_options, &ss);
|
||||
stdout_configured = true;
|
||||
// We no longer need to pass output options to parse_log_arguments().
|
||||
output_options = NULL;
|
||||
}
|
||||
// else - fall-through to normal option processing which will be rejected
|
||||
// with a warning
|
||||
} else if (strcmp("stderr", output) == 0 || strcmp("#1", output) == 0) {
|
||||
if (!stderr_configured) {
|
||||
success = StderrLog.parse_options(output_options, &ss);
|
||||
stderr_configured = true;
|
||||
// We no longer need to pass output options to parse_log_arguments().
|
||||
output_options = NULL;
|
||||
}
|
||||
// else - fall-through to normal option processing which will be rejected
|
||||
// with a warning
|
||||
}
|
||||
|
||||
if (success) {
|
||||
success = parse_log_arguments(output, what, decorators, output_options, &ss);
|
||||
}
|
||||
|
||||
if (ss.size() > 0) {
|
||||
// If it failed, log the error. If it didn't fail, but something was written
|
||||
@ -558,28 +591,34 @@ void LogConfiguration::print_command_line_help(outputStream* out) {
|
||||
out->cr();
|
||||
|
||||
LogTagSet::describe_tagsets(out);
|
||||
out->cr();
|
||||
|
||||
out->print_cr("\nAvailable log outputs:");
|
||||
out->print_cr("Available log outputs:");
|
||||
out->print_cr(" stdout/stderr");
|
||||
out->print_cr(" file=<filename>");
|
||||
out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively.");
|
||||
out->print_cr(" Additional output-options for file outputs:");
|
||||
out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)."
|
||||
" If set to 0, log rotation will not trigger automatically,"
|
||||
" but can be performed manually (see the VM.log DCMD).");
|
||||
out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)."
|
||||
" If set to 0, log rotation is disabled."
|
||||
" This will cause existing log files to be overwritten.");
|
||||
out->print_cr(" foldmultilines=.. - If set to true, a log event that consists of multiple lines"
|
||||
" will be folded into a single line by replacing newline characters"
|
||||
" with the sequence '\\' and 'n' in the output."
|
||||
" Existing single backslash characters will also be replaced"
|
||||
" with a sequence of two backslashes so that the conversion can be reversed."
|
||||
" This option is safe to use with UTF-8 character encodings,"
|
||||
" but other encodings may not work.");
|
||||
|
||||
out->cr();
|
||||
out->print_cr("\nAsynchronous logging (off by default):");
|
||||
|
||||
out->print_cr("Available log output options:");
|
||||
out->print_cr(" foldmultilines=.. - If set to true, a log event that consists of multiple lines"
|
||||
" will be folded into a single line by replacing newline characters"
|
||||
" with the sequence '\\' and 'n' in the output."
|
||||
" Existing single backslash characters will also be replaced"
|
||||
" with a sequence of two backslashes so that the conversion can be reversed."
|
||||
" This option is safe to use with UTF-8 character encodings,"
|
||||
" but other encodings may not work.");
|
||||
out->cr();
|
||||
|
||||
out->print_cr("Additional file output options:");
|
||||
out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)."
|
||||
" If set to 0, log rotation will not trigger automatically,"
|
||||
" but can be performed manually (see the VM.log DCMD).");
|
||||
out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)."
|
||||
" If set to 0, log rotation is disabled."
|
||||
" This will cause existing log files to be overwritten.");
|
||||
out->cr();
|
||||
|
||||
out->print_cr("Asynchronous logging (off by default):");
|
||||
out->print_cr(" -Xlog:async");
|
||||
out->print_cr(" All log messages are written to an intermediate buffer first and will then be flushed"
|
||||
" to the corresponding log outputs by a standalone thread. Write operations at logsites are"
|
||||
|
@ -457,10 +457,8 @@ char* LogFileOutput::make_file_name(const char* file_name,
|
||||
}
|
||||
|
||||
void LogFileOutput::describe(outputStream *out) {
|
||||
LogOutput::describe(out);
|
||||
out->print(" ");
|
||||
|
||||
out->print("filecount=%u,filesize=" SIZE_FORMAT "%s,async=%s", _file_count,
|
||||
LogFileStreamOutput::describe(out);
|
||||
out->print(",filecount=%u,filesize=" SIZE_FORMAT "%s,async=%s", _file_count,
|
||||
byte_size_in_proper_unit(_rotate_size),
|
||||
proper_unit_for_byte_size(_rotate_size),
|
||||
LogConfiguration::is_async_mode() ? "true" : "false");
|
||||
|
@ -188,3 +188,10 @@ int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) {
|
||||
|
||||
return flush() ? written : -1;
|
||||
}
|
||||
|
||||
void LogFileStreamOutput::describe(outputStream *out) {
|
||||
LogOutput::describe(out);
|
||||
out->print(" ");
|
||||
|
||||
out->print("foldmultilines=%s", _fold_multilines ? "true" : "false");
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ class LogFileStreamOutput : public LogOutput {
|
||||
virtual bool set_option(const char* key, const char* value, outputStream* errstream);
|
||||
virtual int write(const LogDecorations& decorations, const char* msg);
|
||||
virtual int write(LogMessageBuffer::Iterator msg_iterator);
|
||||
virtual void describe(outputStream* out);
|
||||
};
|
||||
|
||||
class LogStdoutOutput : public LogFileStreamOutput {
|
||||
|
@ -4433,7 +4433,6 @@ This option is safe to use with UTF\-8 character encodings, but other
|
||||
encodings may not work.
|
||||
For example, it may incorrectly convert multi\-byte sequences in Shift
|
||||
JIS and BIG5.
|
||||
This option is available only for file outputs.
|
||||
.RE
|
||||
.SS Default Configuration
|
||||
.PP
|
||||
|
@ -226,7 +226,7 @@ TEST_VM_F(LogConfigurationTest, reconfigure_decorators) {
|
||||
|
||||
// Now reconfigure logging on stderr with no decorators
|
||||
set_log_config("stderr", "all=off", "none");
|
||||
EXPECT_TRUE(is_described("#1: stderr all=off none (reconfigured)\n")) << "Expecting no decorators";
|
||||
EXPECT_TRUE(is_described("#1: stderr all=off none foldmultilines=false (reconfigured)\n")) << "Expecting no decorators";
|
||||
}
|
||||
|
||||
class ConcurrentLogsite : public TestRunnable {
|
||||
|
@ -24,38 +24,47 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8271186
|
||||
* @bug 8271186 8273471
|
||||
* @library /test/lib
|
||||
* @run driver FoldMultilinesTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Pattern;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class FoldMultilinesTest {
|
||||
|
||||
private static Path EXCEPTION_LOG_FILE = Path.of("exceptions.log");
|
||||
private static String XLOG_BASE = "-Xlog:exceptions=info:file=" + EXCEPTION_LOG_FILE.toString();
|
||||
private static String EXCEPTION_LOG_FILE = "exceptions.log";
|
||||
private static String XLOG_BASE = "-Xlog:exceptions=info:";
|
||||
private static String EXCEPTION_MESSAGE = "line 1\nline 2\\nstring";
|
||||
private static String FOLDED_EXCEPTION_MESSAGE = "line 1\\nline 2\\\\nstring";
|
||||
private static Pattern NEWLINE_LOG_PATTERN = Pattern.compile("line 1\\Rline 2\\\\nstring", Pattern.MULTILINE);
|
||||
|
||||
private static void analyzeFoldMultilinesOn(ProcessBuilder pb) throws Exception {
|
||||
private static String getLog(String out, OutputAnalyzer output) throws Exception {
|
||||
return switch (out) {
|
||||
case "" -> output.getStdout();
|
||||
case "stdout" -> output.getStdout();
|
||||
case "stderr" -> output.getStderr();
|
||||
default -> Files.readString(Path.of(EXCEPTION_LOG_FILE));
|
||||
};
|
||||
}
|
||||
|
||||
private static void analyzeFoldMultilinesOn(ProcessBuilder pb, String out) throws Exception {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
String logs = Files.readString(EXCEPTION_LOG_FILE);
|
||||
if (!logs.contains("line 1\\nline 2\\\\nstring")) {
|
||||
throw new RuntimeException("foldmultilines=true did not work.");
|
||||
if (!getLog(out, output).contains(FOLDED_EXCEPTION_MESSAGE)) {
|
||||
throw new RuntimeException(out + ": foldmultilines=true did not work.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void analyzeFoldMultilinesOff(ProcessBuilder pb) throws Exception {
|
||||
private static void analyzeFoldMultilinesOff(ProcessBuilder pb, String out) throws Exception {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
String logs = Files.readString(EXCEPTION_LOG_FILE);
|
||||
if (!logs.contains("line 1" + System.lineSeparator() + "line 2\\nstring")) {
|
||||
throw new RuntimeException("foldmultilines=false did not work.");
|
||||
if (!NEWLINE_LOG_PATTERN.matcher(getLog(out, output)).find()) {
|
||||
throw new RuntimeException(out + ": foldmultilines=false did not work.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,27 +74,41 @@ public class FoldMultilinesTest {
|
||||
output.shouldNotHaveExitValue(0);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
private static void test(String out) throws Exception {
|
||||
String Xlog;
|
||||
ProcessBuilder pb;
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=true";
|
||||
Xlog = XLOG_BASE + out + "::foldmultilines=true";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesOn(pb);
|
||||
analyzeFoldMultilinesOn(pb, out);
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=false";
|
||||
Xlog = XLOG_BASE + out + "::foldmultilines=false";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesOff(pb);
|
||||
analyzeFoldMultilinesOff(pb, out);
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=invalid";
|
||||
Xlog = XLOG_BASE + out + "::foldmultilines=invalid";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesInvalid(pb);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// -Xlog:exceptions=info:file=exceptions.log::foldmultilines=[true|false|invalid]
|
||||
test("file=" + EXCEPTION_LOG_FILE);
|
||||
|
||||
// -Xlog:exceptions=info:stdout::foldmultilines=[true|false|invalid]
|
||||
test("stdout");
|
||||
|
||||
// -Xlog:exceptions=info:stderr::foldmultilines=[true|false|invalid]
|
||||
test("stderr");
|
||||
|
||||
// -Xlog:exceptions=info:::foldmultilines=[true|false|invalid]
|
||||
test("");
|
||||
}
|
||||
|
||||
public static class InternalClass {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
throw new RuntimeException("line 1\nline 2\\nstring");
|
||||
throw new RuntimeException(EXCEPTION_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
// Do nothing to return exit code 0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user