Skip to content
Permalink
Browse files
8271186: Add UL option to replace newline char
Reviewed-by: iklam, dholmes
  • Loading branch information
YaSuenag committed Aug 27, 2021
1 parent d732c30 commit b16a04ebf749a93d89fb51b96baceff36fe1d730
Showing 6 changed files with 168 additions and 14 deletions.
@@ -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
@@ -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
}
}
}

}

1 comment on commit b16a04e

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on b16a04e Aug 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.