1 /* 2 * Copyright (c) 2016, 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 "logging/logMessage.hpp" 26 #include "memory/allocation.inline.hpp" 27 #include "runtime/thread.inline.hpp" 28 29 template <typename T> 30 static void grow(T*& buffer, size_t& capacity, bool c_heap, size_t minimum_length = 0) { 31 size_t new_size = capacity * 2; 32 if (new_size < minimum_length) { 33 new_size = minimum_length; 34 } 35 if (c_heap) { 36 buffer = REALLOC_C_HEAP_ARRAY(T, buffer, new_size, mtLogging); 37 } else { 38 buffer = REALLOC_RESOURCE_ARRAY(T, buffer, capacity, new_size); 39 } 40 capacity = new_size; 41 } 42 43 LogMessage::LogMessage() : _message_buffer_size(0), 44 _message_buffer_capacity(InitialMessageBufferCapacity), 45 _line_count(0), 46 _line_capacity(InitialLineCapacity), 47 _c_heap_allocated(Thread::current_or_null() == NULL), 48 _prefix_fn(NULL), 49 _least_detailed_level(LogLevel::Off), 50 _used(false) { 51 if (_c_heap_allocated) { 52 _lines = NEW_C_HEAP_ARRAY(LogLine, _message_buffer_capacity, mtLogging); 53 _message_buffer = NEW_C_HEAP_ARRAY(char, InitialMessageBufferCapacity, mtLogging); 54 } else { 55 _lines = NEW_RESOURCE_ARRAY(LogLine, _message_buffer_capacity); 56 _message_buffer = NEW_RESOURCE_ARRAY(char, InitialMessageBufferCapacity); 57 } 58 } 59 60 LogMessage::~LogMessage() { 61 guarantee(_used || _line_count == 0, "log message filled in but never written/used"); 62 if (_c_heap_allocated) { 63 FREE_C_HEAP_ARRAY(LogLine, _lines); 64 FREE_C_HEAP_ARRAY(char, _message_buffer); 65 } else { 66 FREE_RESOURCE_ARRAY(LogLine, _lines, _line_capacity); 67 FREE_RESOURCE_ARRAY(char, _message_buffer, _message_buffer_capacity); 68 } 69 } 70 71 void LogMessage::write(LogLevelType level, const char* fmt, ...) { 72 va_list args; 73 va_start(args, fmt); 74 vwrite(level, fmt, args); 75 va_end(args); 76 } 77 78 void LogMessage::vwrite(LogLevelType level, const char* fmt, va_list args) { 79 80 if (level > _least_detailed_level) { 81 _least_detailed_level = level; 82 } 83 84 size_t written; 85 for (int attempts = 0; attempts < 2; attempts++) { 86 written = 0; 87 size_t remaining_buffer_length = _message_buffer_capacity - _message_buffer_size; 88 char* current_buffer_position = _message_buffer + _message_buffer_size; 89 if (_prefix_fn != NULL) { 90 written += _prefix_fn(current_buffer_position, remaining_buffer_length); 91 current_buffer_position += written; 92 if (remaining_buffer_length < written) { 93 remaining_buffer_length = 0; 94 } else { 95 remaining_buffer_length -= written; 96 } 97 } 98 va_list copy; 99 va_copy(copy, args); 100 written += (size_t)os::log_vsnprintf(current_buffer_position, remaining_buffer_length, fmt, copy) + 1; 101 va_end(copy); 102 if (written > _message_buffer_capacity - _message_buffer_size) { 103 assert(attempts == 0, "Second attempt should always have a sufficiently large buffer (resized to fit)."); 104 grow(_message_buffer, _message_buffer_capacity, _c_heap_allocated, _message_buffer_size + written); 105 continue; 106 } 107 break; 108 } 109 110 if (_line_count == _line_capacity) { 111 grow(_lines, _line_capacity, _c_heap_allocated); 112 } 113 114 _lines[_line_count].level = level; 115 _lines[_line_count].message_offset = _message_buffer_size; 116 _message_buffer_size += written; 117 _line_count++; 118 } 119 120 #define LOG_LEVEL(level, name) \ 121 LogMessage& LogMessage::v##name(const char* fmt, va_list args) { \ 122 vwrite(LogLevel::level, fmt, args); \ 123 return *this; \ 124 } \ 125 LogMessage& LogMessage::name(const char* fmt, ...) { \ 126 va_list args; \ 127 va_start(args, fmt); \ 128 vwrite(LogLevel::level, fmt, args); \ 129 va_end(args); \ 130 return *this; \ 131 } 132 LOG_LEVEL_LIST 133 #undef LOG_LEVEL