1 /* 2 * Copyright (c) 2015, 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/logDecorations.hpp" 26 #include "logging/logFileStreamOutput.hpp" 27 #include "logging/logLevel.hpp" 28 #include "logging/logMessageBuffer.hpp" 29 #include "logging/logOutput.hpp" 30 #include "logging/logTag.hpp" 31 #include "logging/logTagSet.hpp" 32 #include "logging/logTagSetDescriptions.hpp" 33 #include "memory/allocation.inline.hpp" 34 #include "utilities/ostream.hpp" 35 36 LogTagSet* LogTagSet::_list = NULL; 37 size_t LogTagSet::_ntagsets = 0; 38 39 // This constructor is called only during static initialization. 40 // See the declaration in logTagSet.hpp for more information. 41 LogTagSet::LogTagSet(PrefixWriter prefix_writer, LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4) 42 : _next(_list), _write_prefix(prefix_writer) { 43 _tag[0] = t0; 44 _tag[1] = t1; 45 _tag[2] = t2; 46 _tag[3] = t3; 47 _tag[4] = t4; 48 for (_ntags = 0; _ntags < LogTag::MaxTags && _tag[_ntags] != LogTag::__NO_TAG; _ntags++) { 49 } 50 _list = this; 51 _ntagsets++; 52 53 // Set the default output to warning and error level for all new tagsets. 54 _output_list.set_output_level(&StdoutLog, LogLevel::Default); 55 } 56 57 void LogTagSet::update_decorators(const LogDecorators& decorator) { 58 LogDecorators new_decorators = decorator; 59 for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { 60 new_decorators.combine_with((*it)->decorators()); 61 } 62 _decorators = new_decorators; 63 } 64 65 bool LogTagSet::has_output(const LogOutput* output) { 66 for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { 67 if (*it == output) { 68 return true; 69 } 70 } 71 return false; 72 } 73 74 void LogTagSet::log(LogLevelType level, const char* msg) { 75 LogDecorations decorations(level, *this, _decorators); 76 for (LogOutputList::Iterator it = _output_list.iterator(level); it != _output_list.end(); it++) { 77 (*it)->write(decorations, msg); 78 } 79 } 80 81 void LogTagSet::log(const LogMessageBuffer& msg) { 82 LogDecorations decorations(LogLevel::Invalid, *this, _decorators); 83 for (LogOutputList::Iterator it = _output_list.iterator(msg.least_detailed_level()); it != _output_list.end(); it++) { 84 (*it)->write(msg.iterator(it.level(), decorations)); 85 } 86 } 87 88 int LogTagSet::label(char* buf, size_t len, const char* separator) const { 89 int tot_written = 0; 90 for (size_t i = 0; i < _ntags; i++) { 91 int written = jio_snprintf(buf + tot_written, len - tot_written, "%s%s", 92 (i == 0 ? "" : separator), 93 LogTag::name(_tag[i])); 94 if (written < 0) { 95 return -1; 96 } 97 tot_written += written; 98 } 99 return tot_written; 100 } 101 102 void LogTagSet::write(LogLevelType level, const char* fmt, ...) { 103 va_list args; 104 va_start(args, fmt); 105 vwrite(level, fmt, args); 106 va_end(args); 107 } 108 109 const size_t vwrite_buffer_size = 512; 110 111 void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { 112 assert(level >= LogLevel::First && level <= LogLevel::Last, "Log level:%d is incorrect", level); 113 char buf[vwrite_buffer_size]; 114 va_list saved_args; // For re-format on buf overflow. 115 va_copy(saved_args, args); 116 size_t prefix_len = _write_prefix(buf, sizeof(buf)); 117 // Check that string fits in buffer; resize buffer if necessary 118 int ret; 119 if (prefix_len < vwrite_buffer_size) { 120 ret = os::log_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args); 121 } else { 122 // Buffer too small. Just call printf to find out the length for realloc below. 123 ret = os::log_vsnprintf(buf, sizeof(buf), fmt, args); 124 } 125 assert(ret >= 0, "Log message buffer issue"); 126 if ((size_t)ret >= sizeof(buf)) { 127 size_t newbuf_len = prefix_len + ret + 1; 128 char* newbuf = NEW_C_HEAP_ARRAY(char, newbuf_len, mtLogging); 129 prefix_len = _write_prefix(newbuf, newbuf_len); 130 ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args); 131 assert(ret >= 0, "Log message buffer issue"); 132 log(level, newbuf); 133 FREE_C_HEAP_ARRAY(char, newbuf); 134 } else { 135 log(level, buf); 136 } 137 va_end(saved_args); 138 } 139 140 static const size_t TagSetBufferSize = 128; 141 142 void LogTagSet::describe_tagsets(outputStream* out) { 143 out->print_cr("Described tag combinations:"); 144 for (const LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) { 145 char buf[TagSetBufferSize]; 146 d->tagset->label(buf, sizeof(buf), "+"); 147 out->print_cr(" %s: %s", buf, d->descr); 148 } 149 } 150 151 static int qsort_strcmp(const void* a, const void* b) { 152 return strcmp((*(const char**)a), (*(const char**)b)); 153 } 154 155 void LogTagSet::list_all_tagsets(outputStream* out) { 156 char** tagset_labels = NEW_C_HEAP_ARRAY(char*, _ntagsets, mtLogging); 157 158 // Generate the list of tagset labels 159 size_t idx = 0; 160 for (LogTagSet* ts = first(); ts != NULL; ts = ts->next()) { 161 char buf[TagSetBufferSize]; 162 ts->label(buf, sizeof(buf), "+"); 163 tagset_labels[idx++] = os::strdup_check_oom(buf, mtLogging); 164 } 165 assert(idx == _ntagsets, "_ntagsets and list of tagsets not in sync"); 166 167 // Sort them lexicographically 168 qsort(tagset_labels, _ntagsets, sizeof(*tagset_labels), qsort_strcmp); 169 170 // Print and then free the labels 171 out->print("All available tag sets: "); 172 for (idx = 0; idx < _ntagsets; idx++) { 173 out->print("%s%s", (idx == 0 ? "" : ", "), tagset_labels[idx]); 174 os::free(tagset_labels[idx]); 175 } 176 out->cr(); 177 FREE_C_HEAP_ARRAY(char*, tagset_labels); 178 } 179