annotate src/hotspot/share/logging/logConfiguration.cpp @ 49188:e9ba8b40ca6f

8168722: Unified Logging configuration output needs simplifying Reviewed-by: rehn, lfoltan, hseigel
author mlarsson
date Wed, 28 Feb 2018 22:38:53 +0100
parents 268beecd832a
children
rev   line source
mlarsson@33097 1 /*
mlarsson@49015 2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
mlarsson@33097 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mlarsson@33097 4 *
mlarsson@33097 5 * This code is free software; you can redistribute it and/or modify it
mlarsson@33097 6 * under the terms of the GNU General Public License version 2 only, as
mlarsson@33097 7 * published by the Free Software Foundation.
mlarsson@33097 8 *
mlarsson@33097 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mlarsson@33097 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mlarsson@33097 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mlarsson@33097 12 * version 2 for more details (a copy is included in the LICENSE file that
mlarsson@33097 13 * accompanied this code).
mlarsson@33097 14 *
mlarsson@33097 15 * You should have received a copy of the GNU General Public License version
mlarsson@33097 16 * 2 along with this work; if not, write to the Free Software Foundation,
mlarsson@33097 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mlarsson@33097 18 *
mlarsson@33097 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mlarsson@33097 20 * or visit www.oracle.com if you need additional information or have any
mlarsson@33097 21 * questions.
mlarsson@33097 22 *
mlarsson@33097 23 */
mlarsson@33097 24 #include "precompiled.hpp"
coleenp@47765 25 #include "jvm.h"
mlarsson@33097 26 #include "logging/log.hpp"
mlarsson@33097 27 #include "logging/logConfiguration.hpp"
mlarsson@33097 28 #include "logging/logDecorations.hpp"
mlarsson@33097 29 #include "logging/logDecorators.hpp"
mlarsson@33097 30 #include "logging/logDiagnosticCommand.hpp"
mlarsson@33097 31 #include "logging/logFileOutput.hpp"
mlarsson@33097 32 #include "logging/logOutput.hpp"
mlarsson@49016 33 #include "logging/logSelectionList.hpp"
mlarsson@38292 34 #include "logging/logStream.hpp"
mlarsson@33097 35 #include "logging/logTagSet.hpp"
mlarsson@33097 36 #include "memory/allocation.inline.hpp"
mlarsson@33097 37 #include "memory/resourceArea.hpp"
mlarsson@33097 38 #include "runtime/os.inline.hpp"
mlarsson@35228 39 #include "runtime/semaphore.hpp"
mlarsson@33097 40 #include "utilities/globalDefinitions.hpp"
mlarsson@33097 41
mlarsson@33097 42 LogOutput** LogConfiguration::_outputs = NULL;
mlarsson@33097 43 size_t LogConfiguration::_n_outputs = 0;
mlarsson@33097 44
rehn@37108 45 LogConfiguration::UpdateListenerFunction* LogConfiguration::_listener_callbacks = NULL;
rehn@37108 46 size_t LogConfiguration::_n_listener_callbacks = 0;
rehn@37108 47
mlarsson@40902 48 // LogFileOutput is the default type of output, its type prefix should be used if no type was specified
mlarsson@40902 49 static const char* implicit_output_prefix = LogFileOutput::Prefix;
mlarsson@40902 50
mlarsson@35228 51 // Stack object to take the lock for configuring the logging.
mlarsson@35228 52 // Should only be held during the critical parts of the configuration
mlarsson@35228 53 // (when calling configure_output or reading/modifying the outputs array).
mlarsson@35228 54 // Thread must never block when holding this lock.
mlarsson@35228 55 class ConfigurationLock : public StackObj {
mlarsson@35228 56 private:
mlarsson@35228 57 // Semaphore used as lock
mlarsson@35228 58 static Semaphore _semaphore;
mlarsson@35228 59 debug_only(static intx _locking_thread_id;)
mlarsson@35228 60 public:
mlarsson@35228 61 ConfigurationLock() {
mlarsson@35228 62 _semaphore.wait();
mlarsson@35228 63 debug_only(_locking_thread_id = os::current_thread_id());
mlarsson@35228 64 }
mlarsson@35228 65 ~ConfigurationLock() {
mlarsson@35228 66 debug_only(_locking_thread_id = -1);
mlarsson@35228 67 _semaphore.signal();
mlarsson@35228 68 }
mlarsson@35228 69 debug_only(static bool current_thread_has_lock();)
mlarsson@35228 70 };
mlarsson@35228 71
mlarsson@35228 72 Semaphore ConfigurationLock::_semaphore(1);
mlarsson@35228 73 #ifdef ASSERT
mlarsson@35228 74 intx ConfigurationLock::_locking_thread_id = -1;
mlarsson@35228 75 bool ConfigurationLock::current_thread_has_lock() {
mlarsson@35228 76 return _locking_thread_id == os::current_thread_id();
mlarsson@35228 77 }
mlarsson@35228 78 #endif
mlarsson@35228 79
mlarsson@33097 80 void LogConfiguration::post_initialize() {
mlarsson@49181 81 // Reset the reconfigured status of all outputs
mlarsson@49181 82 for (size_t i = 0; i < _n_outputs; i++) {
mlarsson@49181 83 _outputs[i]->_reconfigured = false;
mlarsson@49181 84 }
mlarsson@49181 85
mlarsson@33097 86 LogDiagnosticCommand::registerCommand();
stefank@37242 87 Log(logging) log;
mlarsson@38292 88 if (log.is_info()) {
mlarsson@38292 89 log.info("Log configuration fully initialized.");
mlarsson@38292 90 log_develop_info(logging)("Develop logging is available.");
mlarsson@49180 91
mlarsson@49180 92 LogStream info_stream(log.info());
mlarsson@49180 93 describe_available(&info_stream);
mlarsson@49180 94
mlarsson@49180 95 LogStream debug_stream(log.debug());
mlarsson@49180 96 LogTagSet::list_all_tagsets(&debug_stream);
mlarsson@49180 97
mlarsson@49180 98 ConfigurationLock cl;
mlarsson@49180 99 describe_current_configuration(&info_stream);
mlarsson@33097 100 }
mlarsson@33097 101 }
mlarsson@33097 102
mlarsson@33097 103 void LogConfiguration::initialize(jlong vm_start_time) {
mlarsson@33097 104 LogFileOutput::set_file_name_parameters(vm_start_time);
mlarsson@36174 105 LogDecorations::initialize(vm_start_time);
mlarsson@33097 106 assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
mlarsson@33097 107 _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
mlarsson@42067 108 _outputs[0] = &StdoutLog;
mlarsson@42067 109 _outputs[1] = &StderrLog;
mlarsson@33097 110 _n_outputs = 2;
mlarsson@33097 111 }
mlarsson@33097 112
mlarsson@33097 113 void LogConfiguration::finalize() {
mlarsson@42067 114 for (size_t i = _n_outputs; i > 0; i--) {
mlarsson@42067 115 disable_output(i - 1);
mlarsson@33097 116 }
mlarsson@33097 117 FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
mlarsson@33097 118 }
mlarsson@33097 119
mlarsson@40902 120 // Normalizes the given LogOutput name to type=name form.
mlarsson@40902 121 // For example, foo, "foo", file="foo", will all be normalized to file=foo (no quotes, prefixed).
mlarsson@40902 122 static bool normalize_output_name(const char* full_name, char* buffer, size_t len, outputStream* errstream) {
mlarsson@40902 123 const char* start_quote = strchr(full_name, '"');
mlarsson@40902 124 const char* equals = strchr(full_name, '=');
mlarsson@40902 125 const bool quoted = start_quote != NULL;
mlarsson@40902 126 const bool is_stdout_or_stderr = (strcmp(full_name, "stdout") == 0 || strcmp(full_name, "stderr") == 0);
mlarsson@40902 127
mlarsson@40902 128 // ignore equals sign within quotes
mlarsson@40902 129 if (quoted && equals > start_quote) {
mlarsson@40902 130 equals = NULL;
mlarsson@40902 131 }
mlarsson@40902 132
mlarsson@40902 133 const char* prefix = "";
mlarsson@40902 134 size_t prefix_len = 0;
mlarsson@40902 135 const char* name = full_name;
mlarsson@40902 136 if (equals != NULL) {
mlarsson@40902 137 // split on equals sign
mlarsson@40902 138 name = equals + 1;
mlarsson@40902 139 prefix = full_name;
mlarsson@40902 140 prefix_len = equals - full_name + 1;
mlarsson@40902 141 } else if (!is_stdout_or_stderr) {
mlarsson@40902 142 prefix = implicit_output_prefix;
mlarsson@40902 143 prefix_len = strlen(prefix);
mlarsson@40902 144 }
mlarsson@40902 145 size_t name_len = strlen(name);
mlarsson@40902 146
mlarsson@40902 147 if (quoted) {
mlarsson@40902 148 const char* end_quote = strchr(start_quote + 1, '"');
mlarsson@40902 149 if (end_quote == NULL) {
mlarsson@40902 150 errstream->print_cr("Output name has opening quote but is missing a terminating quote.");
mlarsson@40902 151 return false;
mlarsson@40902 152 }
mlarsson@40902 153 if (start_quote != name || end_quote[1] != '\0') {
mlarsson@40902 154 errstream->print_cr("Output name can not be partially quoted."
mlarsson@40902 155 " Either surround the whole name with quotation marks,"
mlarsson@40902 156 " or do not use quotation marks at all.");
mlarsson@40902 157 return false;
mlarsson@40902 158 }
mlarsson@40902 159 // strip start and end quote
mlarsson@40902 160 name++;
mlarsson@40902 161 name_len -= 2;
mlarsson@40902 162 }
mlarsson@40902 163
mlarsson@40902 164 int ret = jio_snprintf(buffer, len, "%.*s%.*s", prefix_len, prefix, name_len, name);
mlarsson@40902 165 assert(ret > 0, "buffer issue");
mlarsson@40902 166 return true;
mlarsson@40902 167 }
mlarsson@40902 168
mlarsson@33097 169 size_t LogConfiguration::find_output(const char* name) {
mlarsson@33097 170 for (size_t i = 0; i < _n_outputs; i++) {
mlarsson@33097 171 if (strcmp(_outputs[i]->name(), name) == 0) {
mlarsson@33097 172 return i;
mlarsson@33097 173 }
mlarsson@33097 174 }
mlarsson@33097 175 return SIZE_MAX;
mlarsson@33097 176 }
mlarsson@33097 177
mlarsson@40902 178 LogOutput* LogConfiguration::new_output(const char* name,
mlarsson@40902 179 const char* options,
mlarsson@40902 180 outputStream* errstream) {
mlarsson@33097 181 LogOutput* output;
mlarsson@40902 182 if (strncmp(name, LogFileOutput::Prefix, strlen(LogFileOutput::Prefix)) == 0) {
mlarsson@33097 183 output = new LogFileOutput(name);
mlarsson@33097 184 } else {
mlarsson@40902 185 errstream->print_cr("Unsupported log output type: %s", name);
mlarsson@33097 186 return NULL;
mlarsson@33097 187 }
mlarsson@33097 188
mlarsson@37465 189 bool success = output->initialize(options, errstream);
mlarsson@33097 190 if (!success) {
mlarsson@35229 191 errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options);
mlarsson@33097 192 delete output;
mlarsson@33097 193 return NULL;
mlarsson@33097 194 }
mlarsson@33097 195 return output;
mlarsson@33097 196 }
mlarsson@33097 197
mlarsson@33097 198 size_t LogConfiguration::add_output(LogOutput* output) {
mlarsson@33097 199 size_t idx = _n_outputs++;
mlarsson@33097 200 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
mlarsson@33097 201 _outputs[idx] = output;
mlarsson@33097 202 return idx;
mlarsson@33097 203 }
mlarsson@33097 204
mlarsson@33097 205 void LogConfiguration::delete_output(size_t idx) {
mlarsson@33097 206 assert(idx > 1 && idx < _n_outputs,
david@33105 207 "idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT
david@33105 208 " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
mlarsson@33097 209 LogOutput* output = _outputs[idx];
mlarsson@33097 210 // Swap places with the last output and shrink the array
mlarsson@33097 211 _outputs[idx] = _outputs[--_n_outputs];
mlarsson@33097 212 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
mlarsson@33097 213 delete output;
mlarsson@33097 214 }
mlarsson@33097 215
mlarsson@49016 216 void LogConfiguration::configure_output(size_t idx, const LogSelectionList& selections, const LogDecorators& decorators) {
mlarsson@35228 217 assert(ConfigurationLock::current_thread_has_lock(), "Must hold configuration lock to call this function.");
david@33105 218 assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
mlarsson@33097 219 LogOutput* output = _outputs[idx];
mlarsson@34316 220
mlarsson@49181 221 output->_reconfigured = true;
mlarsson@49181 222
mlarsson@49188 223 size_t on_level[LogLevel::Count] = {0};
mlarsson@34316 224
mlarsson@33097 225 bool enabled = false;
mlarsson@33097 226 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
mlarsson@49016 227 LogLevelType level = selections.level_for(*ts);
mlarsson@34316 228
mlarsson@34316 229 // Ignore tagsets that do not, and will not log on the output
mlarsson@34316 230 if (!ts->has_output(output) && (level == LogLevel::NotMentioned || level == LogLevel::Off)) {
mlarsson@49188 231 on_level[LogLevel::Off]++;
mlarsson@34316 232 continue;
mlarsson@34316 233 }
mlarsson@34316 234
mlarsson@34316 235 // Update decorators before adding/updating output level,
mlarsson@34316 236 // so that the tagset will have the necessary decorators when requiring them.
mlarsson@33097 237 if (level != LogLevel::Off) {
mlarsson@34316 238 ts->update_decorators(decorators);
mlarsson@34316 239 }
mlarsson@34316 240
mlarsson@34316 241 // Set the new level, if it changed
mlarsson@34316 242 if (level != LogLevel::NotMentioned) {
mlarsson@34316 243 ts->set_output_level(output, level);
mlarsson@49188 244 } else {
mlarsson@49188 245 // Look up the previously set level for this output on this tagset
mlarsson@49188 246 level = ts->level_for(output);
mlarsson@34316 247 }
mlarsson@34316 248
mlarsson@34316 249 if (level != LogLevel::Off) {
mlarsson@34316 250 // Keep track of whether or not the output is ever used by some tagset
mlarsson@33097 251 enabled = true;
mlarsson@49188 252 }
mlarsson@34316 253
mlarsson@49188 254 // Track of the number of tag sets on each level
mlarsson@49188 255 on_level[level]++;
mlarsson@33097 256 }
mlarsson@33097 257
mlarsson@34316 258 // It is now safe to set the new decorators for the actual output
mlarsson@34316 259 output->set_decorators(decorators);
mlarsson@34316 260
mlarsson@34316 261 // Update the decorators on all tagsets to get rid of unused decorators
mlarsson@34316 262 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
mlarsson@34316 263 ts->update_decorators();
mlarsson@34316 264 }
mlarsson@34316 265
mlarsson@49188 266 if (!enabled && idx > 1) {
mlarsson@49188 267 // Output is unused and should be removed, unless it is stdout/stderr (idx < 2)
mlarsson@33097 268 delete_output(idx);
mlarsson@49188 269 return;
mlarsson@33097 270 }
mlarsson@49188 271
mlarsson@49188 272 output->update_config_string(on_level);
mlarsson@49188 273 assert(strlen(output->config_string()) > 0, "should always have a config description");
mlarsson@33097 274 }
mlarsson@33097 275
mlarsson@33097 276 void LogConfiguration::disable_output(size_t idx) {
mlarsson@40885 277 assert(idx < _n_outputs, "invalid index: " SIZE_FORMAT " (_n_outputs: " SIZE_FORMAT ")", idx, _n_outputs);
mlarsson@33097 278 LogOutput* out = _outputs[idx];
mlarsson@33097 279
mlarsson@33097 280 // Remove the output from all tagsets.
mlarsson@33097 281 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
mlarsson@33097 282 ts->set_output_level(out, LogLevel::Off);
mlarsson@34316 283 ts->update_decorators();
mlarsson@33097 284 }
mlarsson@33097 285
mlarsson@42067 286 // Delete the output unless stdout or stderr (idx 0 or 1)
mlarsson@42067 287 if (idx > 1) {
mlarsson@40885 288 delete_output(idx);
mlarsson@33097 289 } else {
mlarsson@33097 290 out->set_config_string("all=off");
mlarsson@33097 291 }
mlarsson@33097 292 }
mlarsson@33097 293
mlarsson@33097 294 void LogConfiguration::disable_logging() {
mlarsson@35228 295 ConfigurationLock cl;
mlarsson@40885 296 for (size_t i = _n_outputs; i > 0; i--) {
mlarsson@40885 297 disable_output(i - 1);
mlarsson@33097 298 }
rehn@37108 299 notify_update_listeners();
mlarsson@33097 300 }
mlarsson@33097 301
gziemski@48824 302 void LogConfiguration::configure_stdout(LogLevelType level, int exact_match, ...) {
mlarsson@34316 303 size_t i;
mlarsson@34316 304 va_list ap;
mlarsson@49016 305 LogTagType tags[LogTag::MaxTags];
mlarsson@34316 306 va_start(ap, exact_match);
mlarsson@34316 307 for (i = 0; i < LogTag::MaxTags; i++) {
mlarsson@34316 308 LogTagType tag = static_cast<LogTagType>(va_arg(ap, int));
mlarsson@49016 309 tags[i] = tag;
mlarsson@34316 310 if (tag == LogTag::__NO_TAG) {
mlarsson@34316 311 assert(i > 0, "Must specify at least one tag!");
mlarsson@34316 312 break;
mlarsson@34316 313 }
mlarsson@34316 314 }
mlarsson@34316 315 assert(i < LogTag::MaxTags || static_cast<LogTagType>(va_arg(ap, int)) == LogTag::__NO_TAG,
mlarsson@34316 316 "Too many tags specified! Can only have up to " SIZE_FORMAT " tags in a tag set.", LogTag::MaxTags);
mlarsson@34316 317 va_end(ap);
mlarsson@34316 318
mlarsson@49016 319 LogSelection selection(tags, !exact_match, level);
mlarsson@49016 320 assert(selection.tag_sets_selected() > 0,
mlarsson@49016 321 "configure_stdout() called with invalid/non-existing log selection");
mlarsson@49016 322 LogSelectionList list(selection);
mlarsson@34316 323
mlarsson@34316 324 // Apply configuration to stdout (output #0), with the same decorators as before.
mlarsson@35228 325 ConfigurationLock cl;
mlarsson@49016 326 configure_output(0, list, _outputs[0]->decorators());
rehn@37108 327 notify_update_listeners();
mlarsson@34316 328 }
mlarsson@34316 329
mlarsson@33097 330 bool LogConfiguration::parse_command_line_arguments(const char* opts) {
mlarsson@33097 331 char* copy = os::strdup_check_oom(opts, mtLogging);
mlarsson@33097 332
mlarsson@33097 333 // Split the option string to its colon separated components.
mlarsson@35229 334 char* str = copy;
mlarsson@35229 335 char* substrings[4] = {0};
mlarsson@35229 336 for (int i = 0 ; i < 4; i++) {
mlarsson@35229 337 substrings[i] = str;
mlarsson@33097 338
mlarsson@35229 339 // Find the next colon or quote
mlarsson@35229 340 char* next = strpbrk(str, ":\"");
mlarsson@35229 341 while (next != NULL && *next == '"') {
mlarsson@35229 342 char* end_quote = strchr(next + 1, '"');
mlarsson@35229 343 if (end_quote == NULL) {
mlarsson@35229 344 log_error(logging)("Missing terminating quote in -Xlog option '%s'", str);
mlarsson@35229 345 os::free(copy);
mlarsson@35229 346 return false;
mlarsson@33097 347 }
mlarsson@35229 348 // Keep searching after the quoted substring
mlarsson@35229 349 next = strpbrk(end_quote + 1, ":\"");
mlarsson@35229 350 }
mlarsson@35229 351
mlarsson@35229 352 if (next != NULL) {
mlarsson@35229 353 *next = '\0';
mlarsson@35229 354 str = next + 1;
mlarsson@35229 355 } else {
mlarsson@35229 356 break;
mlarsson@33097 357 }
mlarsson@33097 358 }
mlarsson@33097 359
mlarsson@35229 360 // Parse and apply the separated configuration options
mlarsson@35229 361 char* what = substrings[0];
mlarsson@35229 362 char* output = substrings[1];
mlarsson@35229 363 char* decorators = substrings[2];
mlarsson@35229 364 char* output_options = substrings[3];
mlarsson@33097 365 char errbuf[512];
mlarsson@33097 366 stringStream ss(errbuf, sizeof(errbuf));
mlarsson@35229 367 bool success = parse_log_arguments(output, what, decorators, output_options, &ss);
mlarsson@40884 368
mlarsson@40884 369 if (ss.size() > 0) {
mlarsson@40884 370 // If it failed, log the error. If it didn't fail, but something was written
mlarsson@40884 371 // to the stream, log it as a warning.
mlarsson@49180 372 LogLevelType level = success ? LogLevel::Warning : LogLevel::Error;
mlarsson@49180 373
mlarsson@49180 374 Log(logging) log;
mlarsson@49180 375 char* start = errbuf;
mlarsson@49180 376 char* end = strchr(start, '\n');
mlarsson@49180 377 assert(end != NULL, "line must end with newline '%s'", start);
mlarsson@49180 378 do {
mlarsson@49180 379 assert(start < errbuf + sizeof(errbuf) &&
mlarsson@49180 380 end < errbuf + sizeof(errbuf),
mlarsson@49180 381 "buffer overflow");
mlarsson@49180 382 *end = '\0';
mlarsson@49180 383 log.write(level, "%s", start);
mlarsson@49180 384 start = end + 1;
mlarsson@49180 385 end = strchr(start, '\n');
mlarsson@49180 386 assert(end != NULL || *start == '\0', "line must end with newline '%s'", start);
mlarsson@49180 387 } while (end != NULL);
mlarsson@33097 388 }
mlarsson@33097 389
mlarsson@33097 390 os::free(copy);
mlarsson@33097 391 return success;
mlarsson@33097 392 }
mlarsson@33097 393
mlarsson@33097 394 bool LogConfiguration::parse_log_arguments(const char* outputstr,
mlarsson@49016 395 const char* selectionstr,
mlarsson@33097 396 const char* decoratorstr,
mlarsson@33097 397 const char* output_options,
mlarsson@33097 398 outputStream* errstream) {
mlarsson@40924 399 assert(errstream != NULL, "errstream can not be NULL");
mlarsson@33097 400 if (outputstr == NULL || strlen(outputstr) == 0) {
mlarsson@33097 401 outputstr = "stdout";
mlarsson@33097 402 }
mlarsson@33097 403
mlarsson@49016 404 LogSelectionList selections;
mlarsson@49016 405 if (!selections.parse(selectionstr, errstream)) {
mlarsson@35228 406 return false;
mlarsson@35228 407 }
mlarsson@35228 408
mlarsson@35228 409 LogDecorators decorators;
mlarsson@35228 410 if (!decorators.parse(decoratorstr, errstream)) {
mlarsson@35228 411 return false;
mlarsson@35228 412 }
mlarsson@35228 413
mlarsson@35228 414 ConfigurationLock cl;
mlarsson@33097 415 size_t idx;
mlarsson@40902 416 if (outputstr[0] == '#') { // Output specified using index
mlarsson@40902 417 int ret = sscanf(outputstr + 1, SIZE_FORMAT, &idx);
mlarsson@33097 418 if (ret != 1 || idx >= _n_outputs) {
mlarsson@33097 419 errstream->print_cr("Invalid output index '%s'", outputstr);
mlarsson@33097 420 return false;
mlarsson@33097 421 }
mlarsson@40902 422 } else { // Output specified using name
mlarsson@40902 423 // Normalize the name, stripping quotes and ensures it includes type prefix
mlarsson@40902 424 size_t len = strlen(outputstr) + strlen(implicit_output_prefix) + 1;
mlarsson@40902 425 char* normalized = NEW_C_HEAP_ARRAY(char, len, mtLogging);
mlarsson@40902 426 if (!normalize_output_name(outputstr, normalized, len, errstream)) {
mlarsson@40902 427 return false;
mlarsson@40902 428 }
mlarsson@40902 429
mlarsson@40902 430 idx = find_output(normalized);
mlarsson@33097 431 if (idx == SIZE_MAX) {
mlarsson@40902 432 // Attempt to create and add the output
mlarsson@40902 433 LogOutput* output = new_output(normalized, output_options, errstream);
mlarsson@40902 434 if (output != NULL) {
mlarsson@40902 435 idx = add_output(output);
mlarsson@33097 436 }
mlarsson@33097 437 } else if (output_options != NULL && strlen(output_options) > 0) {
mlarsson@33097 438 errstream->print_cr("Output options for existing outputs are ignored.");
mlarsson@33097 439 }
mlarsson@40902 440
mlarsson@40902 441 FREE_C_HEAP_ARRAY(char, normalized);
mlarsson@40902 442 if (idx == SIZE_MAX) {
mlarsson@40902 443 return false;
mlarsson@40902 444 }
mlarsson@33097 445 }
mlarsson@49016 446 configure_output(idx, selections, decorators);
rehn@37108 447 notify_update_listeners();
mlarsson@49016 448 selections.verify_selections(errstream);
mlarsson@33097 449 return true;
mlarsson@33097 450 }
mlarsson@33097 451
mlarsson@49181 452 void LogConfiguration::describe_available(outputStream* out) {
mlarsson@33097 453 out->print("Available log levels:");
mlarsson@33097 454 for (size_t i = 0; i < LogLevel::Count; i++) {
mlarsson@33097 455 out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
mlarsson@33097 456 }
mlarsson@33097 457 out->cr();
mlarsson@33097 458
mlarsson@33097 459 out->print("Available log decorators:");
mlarsson@33097 460 for (size_t i = 0; i < LogDecorators::Count; i++) {
mlarsson@33097 461 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
mlarsson@33097 462 out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
mlarsson@33097 463 }
mlarsson@33097 464 out->cr();
mlarsson@33097 465
mlarsson@33097 466 out->print("Available log tags:");
mlarsson@49015 467 LogTag::list_tags(out);
mlarsson@33097 468
mlarsson@38292 469 LogTagSet::describe_tagsets(out);
mockner@37994 470 }
mockner@37994 471
mlarsson@49181 472 void LogConfiguration::describe_current_configuration(outputStream* out) {
mlarsson@33097 473 out->print_cr("Log output configuration:");
mlarsson@33097 474 for (size_t i = 0; i < _n_outputs; i++) {
mlarsson@49180 475 out->print(" #" SIZE_FORMAT ": ", i);
ysuenaga@39707 476 _outputs[i]->describe(out);
mlarsson@49181 477 if (_outputs[i]->is_reconfigured()) {
mlarsson@49181 478 out->print(" (reconfigured)");
mlarsson@49181 479 }
mlarsson@33097 480 out->cr();
mlarsson@33097 481 }
mlarsson@33097 482 }
mlarsson@33097 483
mockner@37994 484 void LogConfiguration::describe(outputStream* out) {
mockner@37994 485 describe_available(out);
mockner@37994 486 ConfigurationLock cl;
mockner@37994 487 describe_current_configuration(out);
mockner@37994 488 }
mockner@37994 489
mlarsson@49180 490 void LogConfiguration::print_command_line_help(outputStream* out) {
mlarsson@49180 491 out->print_cr("-Xlog Usage: -Xlog[:[selections][:[output][:[decorators][:output-options]]]]");
mlarsson@49180 492 out->print_cr("\t where 'selections' are combinations of tags and levels of the form tag1[+tag2...][*][=level][,...]");
mlarsson@49180 493 out->print_cr("\t NOTE: Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.");
mlarsson@49180 494 out->cr();
mlarsson@33097 495
mlarsson@49180 496 out->print_cr("Available log levels:");
mlarsson@33097 497 for (size_t i = 0; i < LogLevel::Count; i++) {
mlarsson@49180 498 out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
mlarsson@33097 499 }
mlarsson@49180 500 out->cr();
mlarsson@49180 501 out->cr();
mlarsson@33097 502
mlarsson@49180 503 out->print_cr("Available log decorators: ");
mlarsson@33097 504 for (size_t i = 0; i < LogDecorators::Count; i++) {
mlarsson@33097 505 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
mlarsson@49180 506 out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
mlarsson@33097 507 }
mlarsson@49180 508 out->cr();
mlarsson@49180 509 out->print_cr(" Decorators can also be specified as 'none' for no decoration.");
mlarsson@49180 510 out->cr();
mlarsson@33097 511
mlarsson@49180 512 out->print_cr("Available log tags:");
mlarsson@49180 513 LogTag::list_tags(out);
mlarsson@49180 514 out->print_cr(" Specifying 'all' instead of a tag combination matches all tag combinations.");
mlarsson@49180 515 out->cr();
mlarsson@33097 516
mlarsson@49180 517 LogTagSet::describe_tagsets(out);
mlarsson@38292 518
mlarsson@49180 519 out->print_cr("\nAvailable log outputs:");
mlarsson@49180 520 out->print_cr(" stdout/stderr");
mlarsson@49180 521 out->print_cr(" file=<filename>");
mlarsson@49180 522 out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively.");
mlarsson@49180 523 out->print_cr(" Additional output-options for file outputs:");
mlarsson@49180 524 out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)."
mlarsson@49180 525 " If set to 0, log rotation will not trigger automatically,"
mlarsson@49180 526 " but can be performed manually (see the VM.log DCMD).");
mlarsson@49180 527 out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)."
mlarsson@49180 528 " If set to 0, log rotation is disabled."
mlarsson@49180 529 " This will cause existing log files to be overwritten.");
mlarsson@49180 530 out->cr();
mlarsson@33097 531
mlarsson@49180 532 out->print_cr("Some examples:");
mlarsson@49180 533 out->print_cr(" -Xlog");
mlarsson@49183 534 out->print_cr("\t Log all messages up to 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.");
mlarsson@49180 535 out->print_cr("\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).");
mlarsson@49180 536 out->cr();
mlarsson@33097 537
mlarsson@49180 538 out->print_cr(" -Xlog:gc");
mlarsson@49183 539 out->print_cr("\t Log messages tagged with 'gc' tag up to 'info' level to stdout, with default decorations.");
mlarsson@49180 540 out->cr();
mlarsson@33097 541
mlarsson@49180 542 out->print_cr(" -Xlog:gc,safepoint");
mlarsson@49183 543 out->print_cr("\t Log messages tagged either with 'gc' or 'safepoint' tags, both up to 'info' level, to stdout, with default decorations.");
mlarsson@49180 544 out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
mlarsson@49180 545 out->cr();
mlarsson@43417 546
mlarsson@49180 547 out->print_cr(" -Xlog:gc+ref=debug");
mlarsson@49183 548 out->print_cr("\t Log messages tagged with both 'gc' and 'ref' tags, up to 'debug' level, to stdout, with default decorations.");
mlarsson@49180 549 out->print_cr("\t (Messages tagged only with one of the two tags will not be logged.)");
mlarsson@49180 550 out->cr();
mlarsson@43417 551
mlarsson@49180 552 out->print_cr(" -Xlog:gc=debug:file=gc.txt:none");
mlarsson@49183 553 out->print_cr("\t Log messages tagged with 'gc' tag up to 'debug' level to file 'gc.txt' with no decorations.");
mlarsson@49180 554 out->cr();
mlarsson@33097 555
mlarsson@49180 556 out->print_cr(" -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1m");
mlarsson@49183 557 out->print_cr("\t Log messages tagged with 'gc' tag up to 'trace' level to a rotating fileset of 5 files of size 1MB,");
mlarsson@49180 558 out->print_cr("\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.");
mlarsson@49180 559 out->cr();
mlarsson@33097 560
mlarsson@49180 561 out->print_cr(" -Xlog:gc::uptime,tid");
mlarsson@49183 562 out->print_cr("\t Log messages tagged with 'gc' tag up to 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.");
mlarsson@49180 563 out->cr();
mlarsson@33097 564
mlarsson@49180 565 out->print_cr(" -Xlog:gc*=info,safepoint*=off");
mlarsson@49183 566 out->print_cr("\t Log messages tagged with at least 'gc' up to 'info' level, but turn off logging of messages tagged with 'safepoint'.");
mlarsson@49180 567 out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
mlarsson@49180 568 out->cr();
mlarsson@33097 569
mlarsson@49180 570 out->print_cr(" -Xlog:disable -Xlog:safepoint=trace:safepointtrace.txt");
mlarsson@49180 571 out->print_cr("\t Turn off all logging, including warnings and errors,");
mlarsson@49183 572 out->print_cr("\t and then enable messages tagged with 'safepoint' up to 'trace' level to file 'safepointtrace.txt'.");
mlarsson@33097 573 }
ysuenaga@34637 574
ysuenaga@34637 575 void LogConfiguration::rotate_all_outputs() {
mlarsson@35230 576 // Start from index 2 since neither stdout nor stderr can be rotated.
mlarsson@35230 577 for (size_t idx = 2; idx < _n_outputs; idx++) {
mlarsson@35230 578 _outputs[idx]->force_rotate();
ysuenaga@34637 579 }
ysuenaga@34637 580 }
ysuenaga@34637 581
rehn@37108 582 void LogConfiguration::register_update_listener(UpdateListenerFunction cb) {
rehn@37108 583 assert(cb != NULL, "Should not register NULL as listener");
rehn@37108 584 ConfigurationLock cl;
rehn@37108 585 size_t idx = _n_listener_callbacks++;
rehn@37108 586 _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction,
rehn@37108 587 _listener_callbacks,
rehn@37108 588 _n_listener_callbacks,
rehn@37108 589 mtLogging);
rehn@37108 590 _listener_callbacks[idx] = cb;
rehn@37108 591 }
rehn@37108 592
rehn@37108 593 void LogConfiguration::notify_update_listeners() {
rehn@37108 594 assert(ConfigurationLock::current_thread_has_lock(), "notify_update_listeners must be called in ConfigurationLock scope (lock held)");
rehn@37108 595 for (size_t i = 0; i < _n_listener_callbacks; i++) {
rehn@37108 596 _listener_callbacks[i]();
rehn@37108 597 }
rehn@37108 598 }