1 /* 2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 #include "precompiled.hpp" 25 #include "jvm.h" 26 #include "logging/logAsyncWriter.hpp" 27 #include "logging/logDecorators.hpp" 28 #include "logging/logDecorations.hpp" 29 #include "logging/logFileStreamOutput.hpp" 30 #include "logging/logMessageBuffer.hpp" 31 #include "memory/allocation.inline.hpp" 32 #include "utilities/defaultStream.hpp" 33 34 const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines"; 35 36 static bool initialized; 37 static union { 38 char stdoutmem[sizeof(LogStdoutOutput)]; 39 jlong dummy; 40 } aligned_stdoutmem; 41 static union { 42 char stderrmem[sizeof(LogStderrOutput)]; 43 jlong dummy; 44 } aligned_stderrmem; 45 46 LogStdoutOutput &StdoutLog = reinterpret_cast<LogStdoutOutput&>(aligned_stdoutmem.stdoutmem); 47 LogStderrOutput &StderrLog = reinterpret_cast<LogStderrOutput&>(aligned_stderrmem.stderrmem); 48 49 LogFileStreamInitializer::LogFileStreamInitializer() { 50 if (!initialized) { 51 ::new (&StdoutLog) LogStdoutOutput(); 52 ::new (&StderrLog) LogStderrOutput(); 53 initialized = true; 54 } 55 } 56 57 bool LogFileStreamOutput::set_option(const char* key, const char* value, outputStream* errstream) { 58 bool success = false; 59 if (strcmp(FoldMultilinesOptionKey, key) == 0) { 60 if (strcmp(value, "true") == 0) { 61 _fold_multilines = true; 62 success = true; 63 } else if (strcmp(value, "false") == 0) { 64 _fold_multilines = false; 65 success = true; 66 } else { 67 errstream->print_cr("Invalid option: %s must be 'true' or 'false'.", key); 68 } 69 } 70 return success; 71 } 72 73 int LogFileStreamOutput::write_decorations(const LogDecorations& decorations) { 74 int total_written = 0; 75 char buf[LogDecorations::max_decoration_size + 1]; 76 77 for (uint i = 0; i < LogDecorators::Count; i++) { 78 LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(i); 79 if (!_decorators.is_decorator(decorator)) { 80 continue; 81 } 82 83 int written = jio_fprintf(_stream, "[%-*s]", 84 _decorator_padding[decorator], 85 decorations.decoration(decorator, buf, sizeof(buf))); 86 if (written <= 0) { 87 return -1; 88 } else if (static_cast<size_t>(written - 2) > _decorator_padding[decorator]) { 89 _decorator_padding[decorator] = written - 2; 90 } 91 total_written += written; 92 } 93 return total_written; 94 } 95 96 bool LogFileStreamOutput::flush() { 97 bool result = true; 98 if (fflush(_stream) != 0) { 99 if (!_write_error_is_shown) { 100 jio_fprintf(defaultStream::error_stream(), 101 "Could not flush log: %s (%s (%d))\n", name(), os::strerror(errno), errno); 102 jio_fprintf(_stream, "\nERROR: Could not flush log (%d)\n", errno); 103 _write_error_is_shown = true; 104 } 105 result = false; 106 } 107 return result; 108 } 109 110 #define WRITE_LOG_WITH_RESULT_CHECK(op, total) \ 111 { \ 112 int result = op; \ 113 if (result < 0) { \ 114 if (!_write_error_is_shown) { \ 115 jio_fprintf(defaultStream::error_stream(), \ 116 "Could not write log: %s\n", name()); \ 117 jio_fprintf(_stream, "\nERROR: Could not write log\n"); \ 118 _write_error_is_shown = true; \ 119 return -1; \ 120 } \ 121 } \ 122 total += result; \ 123 } 124 125 int LogFileStreamOutput::write_internal(const LogDecorations& decorations, const char* msg) { 126 int written = 0; 127 const bool use_decorations = !_decorators.is_empty(); 128 129 if (use_decorations) { 130 WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written); 131 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written); 132 } 133 134 if (!_fold_multilines) { 135 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written); 136 } else { 137 char *dupstr = os::strdup_check_oom(msg, mtLogging); 138 char *cur = dupstr; 139 char *next; 140 do { 141 next = strpbrk(cur, "\n\\"); 142 if (next == NULL) { 143 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", cur), written); 144 } else { 145 const char *found = (*next == '\n') ? "\\n" : "\\\\"; 146 *next = '\0'; 147 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s%s", cur, found), written); 148 cur = next + 1; 149 } 150 } while (next != NULL); 151 os::free(dupstr); 152 } 153 return written; 154 } 155 156 int LogFileStreamOutput::write_blocking(const LogDecorations& decorations, const char* msg) { 157 int written = write_internal(decorations, msg); 158 return flush() ? written : -1; 159 } 160 161 int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { 162 AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); 163 if (aio_writer != nullptr) { 164 aio_writer->enqueue(*this, decorations, msg); 165 return 0; 166 } 167 168 FileLocker flocker(_stream); 169 int written = write_internal(decorations, msg); 170 171 return flush() ? written : -1; 172 } 173 174 int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) { 175 AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); 176 if (aio_writer != nullptr) { 177 aio_writer->enqueue(*this, msg_iterator); 178 return 0; 179 } 180 181 int written = 0; 182 FileLocker flocker(_stream); 183 for (; !msg_iterator.is_at_end(); msg_iterator++) { 184 written += write_internal(msg_iterator.decorations(), msg_iterator.message()); 185 } 186 187 return flush() ? written : -1; 188 } 189 190 void LogFileStreamOutput::describe(outputStream *out) { 191 LogOutput::describe(out); 192 out->print(" "); 193 194 out->print("foldmultilines=%s", _fold_multilines ? "true" : "false"); 195 }