| 1 | /* | 
|---|
| 2 | * Copyright (c) 2016, 2018, 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/logMessageBuffer.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, 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 | buffer = REALLOC_C_HEAP_ARRAY(T, buffer, new_size, mtLogging); | 
|---|
| 36 | capacity = new_size; | 
|---|
| 37 | } | 
|---|
| 38 |  | 
|---|
| 39 | LogMessageBuffer::LogMessageBuffer() : _message_buffer_size(0), | 
|---|
| 40 | _message_buffer_capacity(0), | 
|---|
| 41 | _message_buffer(NULL), | 
|---|
| 42 | _line_count(0), | 
|---|
| 43 | _line_capacity(0), | 
|---|
| 44 | _lines(NULL), | 
|---|
| 45 | _allocated(false), | 
|---|
| 46 | _least_detailed_level(LogLevel::Off), | 
|---|
| 47 | _prefix_fn(NULL) { | 
|---|
| 48 | } | 
|---|
| 49 |  | 
|---|
| 50 | LogMessageBuffer::~LogMessageBuffer() { | 
|---|
| 51 | if (_allocated) { | 
|---|
| 52 | FREE_C_HEAP_ARRAY(char, _message_buffer); | 
|---|
| 53 | FREE_C_HEAP_ARRAY(LogLine, _lines); | 
|---|
| 54 | } | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | void LogMessageBuffer::reset() { | 
|---|
| 58 | _message_buffer_size = 0; | 
|---|
| 59 | _line_count = 0; | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | void LogMessageBuffer::initialize_buffers() { | 
|---|
| 63 | assert(!_allocated, "buffer already initialized/allocated"); | 
|---|
| 64 | _allocated = true; | 
|---|
| 65 | _message_buffer = NEW_C_HEAP_ARRAY(char, InitialMessageBufferCapacity, mtLogging); | 
|---|
| 66 | _lines = NEW_C_HEAP_ARRAY(LogLine, InitialLineCapacity, mtLogging); | 
|---|
| 67 | _message_buffer_capacity = InitialMessageBufferCapacity; | 
|---|
| 68 | _line_capacity = InitialLineCapacity; | 
|---|
| 69 | } | 
|---|
| 70 |  | 
|---|
| 71 | void LogMessageBuffer::Iterator::skip_messages_with_finer_level() { | 
|---|
| 72 | for (; _current_line_index < _message._line_count; _current_line_index++) { | 
|---|
| 73 | if (_message._lines[_current_line_index].level >= _level) { | 
|---|
| 74 | break; | 
|---|
| 75 | } | 
|---|
| 76 | } | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | void LogMessageBuffer::write(LogLevelType level, const char* fmt, ...) { | 
|---|
| 80 | va_list args; | 
|---|
| 81 | va_start(args, fmt); | 
|---|
| 82 | vwrite(level, fmt, args); | 
|---|
| 83 | va_end(args); | 
|---|
| 84 | }; | 
|---|
| 85 |  | 
|---|
| 86 | void LogMessageBuffer::vwrite(LogLevelType level, const char* fmt, va_list args) { | 
|---|
| 87 | if (!_allocated) { | 
|---|
| 88 | initialize_buffers(); | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | if (level > _least_detailed_level) { | 
|---|
| 92 | _least_detailed_level = level; | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | size_t written; | 
|---|
| 96 | for (int attempts = 0; attempts < 2; attempts++) { | 
|---|
| 97 | written = 0; | 
|---|
| 98 | size_t remaining_buffer_length = _message_buffer_capacity - _message_buffer_size; | 
|---|
| 99 | char* current_buffer_position = _message_buffer + _message_buffer_size; | 
|---|
| 100 |  | 
|---|
| 101 | if (_prefix_fn != NULL) { | 
|---|
| 102 | written += _prefix_fn(current_buffer_position, remaining_buffer_length); | 
|---|
| 103 | current_buffer_position += written; | 
|---|
| 104 | if (remaining_buffer_length < written) { | 
|---|
| 105 | remaining_buffer_length = 0; | 
|---|
| 106 | } else { | 
|---|
| 107 | remaining_buffer_length -= written; | 
|---|
| 108 | } | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | va_list copy; | 
|---|
| 112 | va_copy(copy, args); | 
|---|
| 113 | written += (size_t)os::vsnprintf(current_buffer_position, remaining_buffer_length, fmt, copy) + 1; | 
|---|
| 114 | va_end(copy); | 
|---|
| 115 | if (written > _message_buffer_capacity - _message_buffer_size) { | 
|---|
| 116 | assert(attempts == 0, "Second attempt should always have a sufficiently large buffer (resized to fit)."); | 
|---|
| 117 | grow(_message_buffer, _message_buffer_capacity, _message_buffer_size + written); | 
|---|
| 118 | continue; | 
|---|
| 119 | } | 
|---|
| 120 | break; | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | if (_line_count == _line_capacity) { | 
|---|
| 124 | grow(_lines, _line_capacity); | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | _lines[_line_count].level = level; | 
|---|
| 128 | _lines[_line_count].message_offset = _message_buffer_size; | 
|---|
| 129 | _message_buffer_size += written; | 
|---|
| 130 | _line_count++; | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | #define LOG_LEVEL(level, name) \ | 
|---|
| 134 | LogMessageBuffer& LogMessageBuffer::v##name(const char* fmt, va_list args) { \ | 
|---|
| 135 | vwrite(LogLevel::level, fmt, args); \ | 
|---|
| 136 | return *this; \ | 
|---|
| 137 | } \ | 
|---|
| 138 | LogMessageBuffer& LogMessageBuffer::name(const char* fmt, ...) { \ | 
|---|
| 139 | va_list args; \ | 
|---|
| 140 | va_start(args, fmt); \ | 
|---|
| 141 | vwrite(LogLevel::level, fmt, args); \ | 
|---|
| 142 | va_end(args); \ | 
|---|
| 143 | return *this; \ | 
|---|
| 144 | } | 
|---|
| 145 | LOG_LEVEL_LIST | 
|---|
| 146 | #undef LOG_LEVEL | 
|---|
| 147 |  | 
|---|