mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-11 08:23:26 +00:00
8271186: Add UL option to replace newline char
Reviewed-by: iklam, dholmes
This commit is contained in:
parent
d732c3091f
commit
b16a04ebf7
@ -564,12 +564,20 @@ void LogConfiguration::print_command_line_help(outputStream* out) {
|
||||
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(" 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(" -Xlog:async");
|
||||
|
||||
@ -195,7 +195,17 @@ bool LogFileOutput::parse_options(const char* options, outputStream* errstream)
|
||||
char* value_str = equals_pos + 1;
|
||||
*equals_pos = '\0';
|
||||
|
||||
if (strcmp(FileCountOptionKey, key) == 0) {
|
||||
if (strcmp(FoldMultilinesOptionKey, key) == 0) {
|
||||
if (strcmp(value_str, "true") == 0) {
|
||||
_fold_multilines = true;
|
||||
} else if (strcmp(value_str, "false") == 0) {
|
||||
_fold_multilines = false;
|
||||
} else {
|
||||
errstream->print_cr("Invalid option '%s' for %s.", value_str, FoldMultilinesOptionKey);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(FileCountOptionKey, key) == 0) {
|
||||
size_t value = parse_value(value_str);
|
||||
if (value > MaxRotationFileCount) {
|
||||
errstream->print_cr("Invalid option: %s must be in range [0, %u]",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,6 +30,8 @@
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
|
||||
const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines";
|
||||
|
||||
static bool initialized;
|
||||
static union {
|
||||
char stdoutmem[sizeof(LogStdoutOutput)];
|
||||
@ -117,6 +119,30 @@ bool LogFileStreamOutput::flush() {
|
||||
total += result; \
|
||||
}
|
||||
|
||||
int LogFileStreamOutput::write_internal(const char* msg) {
|
||||
int written = 0;
|
||||
if (!_fold_multilines) {
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written);
|
||||
} else {
|
||||
char *dupstr = os::strdup_check_oom(msg, mtLogging);
|
||||
char *cur = dupstr;
|
||||
char *next;
|
||||
do {
|
||||
next = strpbrk(cur, "\n\\");
|
||||
if (next == NULL) {
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", cur), written);
|
||||
} else {
|
||||
const char *found = (*next == '\n') ? "\\n" : "\\\\";
|
||||
*next = '\0';
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s%s", cur, found), written);
|
||||
cur = next + 1;
|
||||
}
|
||||
} while (next != NULL);
|
||||
os::free(dupstr);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
|
||||
const bool use_decorations = !_decorators.is_empty();
|
||||
|
||||
@ -126,7 +152,7 @@ int LogFileStreamOutput::write(const LogDecorations& decorations, const char* ms
|
||||
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written);
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
|
||||
}
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written);
|
||||
written += write_internal(msg);
|
||||
|
||||
return flush() ? written : -1;
|
||||
}
|
||||
@ -141,7 +167,7 @@ int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) {
|
||||
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(msg_iterator.decorations()), written);
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
|
||||
}
|
||||
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg_iterator.message()), written);
|
||||
written += write_internal(msg_iterator.message());
|
||||
}
|
||||
|
||||
return flush() ? written : -1;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogDecorations;
|
||||
@ -42,11 +43,15 @@ static LogFileStreamInitializer log_stream_initializer;
|
||||
class LogFileStreamOutput : public LogOutput {
|
||||
private:
|
||||
bool _write_error_is_shown;
|
||||
|
||||
int write_internal(const char* msg);
|
||||
protected:
|
||||
static const char* const FoldMultilinesOptionKey;
|
||||
FILE* _stream;
|
||||
size_t _decorator_padding[LogDecorators::Count];
|
||||
bool _fold_multilines;
|
||||
|
||||
LogFileStreamOutput(FILE *stream) : _write_error_is_shown(false), _stream(stream) {
|
||||
LogFileStreamOutput(FILE *stream) : _write_error_is_shown(false), _stream(stream), _fold_multilines(false) {
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
_decorator_padding[i] = 0;
|
||||
}
|
||||
|
||||
@ -4418,8 +4418,18 @@ selected.
|
||||
\f[I]output\-options\f[R] is
|
||||
.RS
|
||||
.PP
|
||||
\f[CB]filecount=\f[R]\f[I]file\-count\f[R] \f[CB]filesize=\f[R]\f[I]file size
|
||||
with optional K, M or G suffix\f[R]
|
||||
\f[CB]filecount=\f[R]\f[I]file\-count\f[R] \f[CB]filesize=\f[R]\f[I]<file size
|
||||
with optional K, M or G suffix>\f[R] \f[CB]foldmultilines=\f[R]\f[I]<true|false>\f[R]
|
||||
.RE
|
||||
.PP
|
||||
When \f[I]foldmultilines\f[R] is 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.
|
||||
For example, it may incorrectly convert multi-byte sequences in Shift JIS and BIG5.
|
||||
This option is available only for file outputs.
|
||||
.RE
|
||||
.RE
|
||||
.SS Default Configuration
|
||||
|
||||
95
test/hotspot/jtreg/runtime/logging/FoldMultilinesTest.java
Normal file
95
test/hotspot/jtreg/runtime/logging/FoldMultilinesTest.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021 NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8271186
|
||||
* @library /test/lib
|
||||
* @run driver FoldMultilinesTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
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 void analyzeFoldMultilinesOn(ProcessBuilder pb) 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.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void analyzeFoldMultilinesOff(ProcessBuilder pb) 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.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void analyzeFoldMultilinesInvalid(ProcessBuilder pb) throws Exception {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Invalid option 'invalid' for foldmultilines.");
|
||||
output.shouldNotHaveExitValue(0);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String Xlog;
|
||||
ProcessBuilder pb;
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=true";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesOn(pb);
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=false";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesOff(pb);
|
||||
|
||||
Xlog = XLOG_BASE + "::foldmultilines=invalid";
|
||||
pb = ProcessTools.createJavaProcessBuilder(Xlog, InternalClass.class.getName());
|
||||
analyzeFoldMultilinesInvalid(pb);
|
||||
}
|
||||
|
||||
public static class InternalClass {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
throw new RuntimeException("line 1\nline 2\\nstring");
|
||||
} catch (Exception e) {
|
||||
// Do nothing to return exit code 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user