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 class FileLocker : public StackObj { 97 private: 98 FILE *_file; 99 100 public: 101 FileLocker(FILE *file) : _file(file) { 102 os::flockfile(_file); 103 } 104 105 ~FileLocker() { 106 os::funlockfile(_file); 107 } 108 }; 109 110 bool LogFileStreamOutput::flush() { 111 bool result = true; 112 if (fflush(_stream) != 0) { 113 if (!_write_error_is_shown) { 114 jio_fprintf(defaultStream::error_stream(), 115 "Could not flush log: %s (%s (%d))\n", name(), os::strerror(errno), errno); 116 jio_fprintf(_stream, "\nERROR: Could not flush log (%d)\n", errno); 117 _write_error_is_shown = true; 118 } 119 result = false; 120 } 121 return result; 122 } 123 124 #define WRITE_LOG_WITH_RESULT_CHECK(op, total) \ 125 { \ 126 int result = op; \ 127 if (result < 0) { \ 128 if (!_write_error_is_shown) { \ 129 jio_fprintf(defaultStream::error_stream(), \ 130 "Could not write log: %s\n", name()); \ 131 jio_fprintf(_stream, "\nERROR: Could not write log\n"); \ 132 _write_error_is_shown = true; \ 133 return -1; \ 134 } \ 135 } \ 136 total += result; \ 137 } 138 139 int LogFileStreamOutput::write_internal(const LogDecorations& decorations, const char* msg) { 140 int written = 0; 141 const bool use_decorations = !_decorators.is_empty(); 142 143 if (use_decorations) { 144 WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written); 145 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written); 146 } 147 148 if (!_fold_multilines) { 149 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written); 150 } else { 151 char *dupstr = os::strdup_check_oom(msg, mtLogging); 152 char *cur = dupstr; 153 char *next; 154 do { 155 next = strpbrk(cur, "\n\\"); 156 if (next == NULL) { 157 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", cur), written); 158 } else { 159 const char *found = (*next == '\n') ? "\\n" : "\\\\"; 160 *next = '\0'; 161 WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s%s", cur, found), written); 162 cur = next + 1; 163 } 164 } while (next != NULL); 165 os::free(dupstr); 166 } 167 return written; 168 } 169 170 int LogFileStreamOutput::write_blocking(const LogDecorations& decorations, const char* msg) { 171 int written = write_internal(decorations, msg); 172 return flush() ? written : -1; 173 } 174 175 int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { 176 AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); 177 if (aio_writer != nullptr) { 178 aio_writer->enqueue(*this, decorations, msg); 179 return 0; 180 } 181 182 FileLocker flocker(_stream); 183 int written = write_internal(decorations, msg); 184 185 return flush() ? written : -1; 186 } 187 188 int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) { 189 AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); 190 if (aio_writer != nullptr) { 191 aio_writer->enqueue(*this, msg_iterator); 192 return 0; 193 } 194 195 int written = 0; 196 FileLocker flocker(_stream); 197 for (; !msg_iterator.is_at_end(); msg_iterator++) { 198 written += write_internal(msg_iterator.decorations(), msg_iterator.message()); 199 } 200 201 return flush() ? written : -1; 202 } 203 204 void LogFileStreamOutput::describe(outputStream *out) { 205 LogOutput::describe(out); 206 out->print(" "); 207 208 out->print("foldmultilines=%s", _fold_multilines ? "true" : "false"); 209 }