1 /* 2 * Copyright (c) 2015, 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/log.hpp" 26 #include "logging/logConfiguration.hpp" 27 #include "logging/logDecorations.hpp" 28 #include "logging/logDecorators.hpp" 29 #include "logging/logDiagnosticCommand.hpp" 30 #include "logging/logFileOutput.hpp" 31 #include "logging/logOutput.hpp" 32 #include "logging/logStream.hpp" 33 #include "logging/logTagLevelExpression.hpp" 34 #include "logging/logTagSet.hpp" 35 #include "memory/allocation.inline.hpp" 36 #include "memory/resourceArea.hpp" 37 #include "runtime/os.inline.hpp" 38 #include "runtime/semaphore.hpp" 39 #include "utilities/globalDefinitions.hpp" 40 41 LogOutput** LogConfiguration::_outputs = NULL; 42 size_t LogConfiguration::_n_outputs = 0; 43 44 LogConfiguration::UpdateListenerFunction* LogConfiguration::_listener_callbacks = NULL; 45 size_t LogConfiguration::_n_listener_callbacks = 0; 46 47 // LogFileOutput is the default type of output, its type prefix should be used if no type was specified 48 static const char* implicit_output_prefix = LogFileOutput::Prefix; 49 50 // Stack object to take the lock for configuring the logging. 51 // Should only be held during the critical parts of the configuration 52 // (when calling configure_output or reading/modifying the outputs array). 53 // Thread must never block when holding this lock. 54 class ConfigurationLock : public StackObj { 55 private: 56 // Semaphore used as lock 57 static Semaphore _semaphore; 58 debug_only(static intx _locking_thread_id;) 59 public: 60 ConfigurationLock() { 61 _semaphore.wait(); 62 debug_only(_locking_thread_id = os::current_thread_id()); 63 } 64 ~ConfigurationLock() { 65 debug_only(_locking_thread_id = -1); 66 _semaphore.signal(); 67 } 68 debug_only(static bool current_thread_has_lock();) 69 }; 70 71 Semaphore ConfigurationLock::_semaphore(1); 72 #ifdef ASSERT 73 intx ConfigurationLock::_locking_thread_id = -1; 74 bool ConfigurationLock::current_thread_has_lock() { 75 return _locking_thread_id == os::current_thread_id(); 76 } 77 #endif 78 79 void LogConfiguration::post_initialize() { 80 LogDiagnosticCommand::registerCommand(); 81 Log(logging) log; 82 if (log.is_info()) { 83 log.info("Log configuration fully initialized."); 84 log_develop_info(logging)("Develop logging is available."); 85 if (log.is_debug()) { 86 LogStream debug_stream(log.debug()); 87 describe(&debug_stream); 88 if (log.is_trace()) { 89 LogStream trace_stream(log.trace()); 90 LogTagSet::list_all_tagsets(&trace_stream); 91 } 92 } 93 } 94 } 95 96 void LogConfiguration::initialize(jlong vm_start_time) { 97 LogFileOutput::set_file_name_parameters(vm_start_time); 98 LogDecorations::initialize(vm_start_time); 99 assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?"); 100 _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging); 101 _outputs[0] = LogOutput::Stdout; 102 _outputs[1] = LogOutput::Stderr; 103 _n_outputs = 2; 104 } 105 106 void LogConfiguration::finalize() { 107 for (size_t i = 2; i < _n_outputs; i++) { 108 delete _outputs[i]; 109 } 110 FREE_C_HEAP_ARRAY(LogOutput*, _outputs); 111 } 112 113 // Normalizes the given LogOutput name to type=name form. 114 // For example, foo, "foo", file="foo", will all be normalized to file=foo (no quotes, prefixed). 115 static bool normalize_output_name(const char* full_name, char* buffer, size_t len, outputStream* errstream) { 116 const char* start_quote = strchr(full_name, '"'); 117 const char* equals = strchr(full_name, '='); 118 const bool quoted = start_quote != NULL; 119 const bool is_stdout_or_stderr = (strcmp(full_name, "stdout") == 0 || strcmp(full_name, "stderr") == 0); 120 121 // ignore equals sign within quotes 122 if (quoted && equals > start_quote) { 123 equals = NULL; 124 } 125 126 const char* prefix = ""; 127 size_t prefix_len = 0; 128 const char* name = full_name; 129 if (equals != NULL) { 130 // split on equals sign 131 name = equals + 1; 132 prefix = full_name; 133 prefix_len = equals - full_name + 1; 134 } else if (!is_stdout_or_stderr) { 135 prefix = implicit_output_prefix; 136 prefix_len = strlen(prefix); 137 } 138 size_t name_len = strlen(name); 139 140 if (quoted) { 141 const char* end_quote = strchr(start_quote + 1, '"'); 142 if (end_quote == NULL) { 143 errstream->print_cr("Output name has opening quote but is missing a terminating quote."); 144 return false; 145 } 146 if (start_quote != name || end_quote[1] != '\0') { 147 errstream->print_cr("Output name can not be partially quoted." 148 " Either surround the whole name with quotation marks," 149 " or do not use quotation marks at all."); 150 return false; 151 } 152 // strip start and end quote 153 name++; 154 name_len -= 2; 155 } 156 157 int ret = jio_snprintf(buffer, len, "%.*s%.*s", prefix_len, prefix, name_len, name); 158 assert(ret > 0, "buffer issue"); 159 return true; 160 } 161 162 size_t LogConfiguration::find_output(const char* name) { 163 for (size_t i = 0; i < _n_outputs; i++) { 164 if (strcmp(_outputs[i]->name(), name) == 0) { 165 return i; 166 } 167 } 168 return SIZE_MAX; 169 } 170 171 LogOutput* LogConfiguration::new_output(const char* name, 172 const char* options, 173 outputStream* errstream) { 174 LogOutput* output; 175 if (strncmp(name, LogFileOutput::Prefix, strlen(LogFileOutput::Prefix)) == 0) { 176 output = new LogFileOutput(name); 177 } else { 178 errstream->print_cr("Unsupported log output type: %s", name); 179 return NULL; 180 } 181 182 bool success = output->initialize(options, errstream); 183 if (!success) { 184 errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options); 185 delete output; 186 return NULL; 187 } 188 return output; 189 } 190 191 size_t LogConfiguration::add_output(LogOutput* output) { 192 size_t idx = _n_outputs++; 193 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); 194 _outputs[idx] = output; 195 return idx; 196 } 197 198 void LogConfiguration::delete_output(size_t idx) { 199 assert(idx > 1 && idx < _n_outputs, 200 "idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT 201 " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); 202 LogOutput* output = _outputs[idx]; 203 // Swap places with the last output and shrink the array 204 _outputs[idx] = _outputs[--_n_outputs]; 205 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); 206 delete output; 207 } 208 209 void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) { 210 assert(ConfigurationLock::current_thread_has_lock(), "Must hold configuration lock to call this function."); 211 assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); 212 LogOutput* output = _outputs[idx]; 213 214 // Clear the previous config description 215 output->clear_config_string(); 216 217 bool enabled = false; 218 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 219 LogLevelType level = tag_level_expression.level_for(*ts); 220 221 // Ignore tagsets that do not, and will not log on the output 222 if (!ts->has_output(output) && (level == LogLevel::NotMentioned || level == LogLevel::Off)) { 223 continue; 224 } 225 226 // Update decorators before adding/updating output level, 227 // so that the tagset will have the necessary decorators when requiring them. 228 if (level != LogLevel::Off) { 229 ts->update_decorators(decorators); 230 } 231 232 // Set the new level, if it changed 233 if (level != LogLevel::NotMentioned) { 234 ts->set_output_level(output, level); 235 } 236 237 if (level != LogLevel::Off) { 238 // Keep track of whether or not the output is ever used by some tagset 239 enabled = true; 240 241 if (level == LogLevel::NotMentioned) { 242 // Look up the previously set level for this output on this tagset 243 level = ts->level_for(output); 244 } 245 246 // Update the config description with this tagset and level 247 output->add_to_config_string(ts, level); 248 } 249 } 250 251 // It is now safe to set the new decorators for the actual output 252 output->set_decorators(decorators); 253 254 // Update the decorators on all tagsets to get rid of unused decorators 255 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 256 ts->update_decorators(); 257 } 258 259 if (enabled) { 260 assert(strlen(output->config_string()) > 0, 261 "Should always have a config description if the output is enabled."); 262 } else if (idx > 1) { 263 // Output is unused and should be removed. 264 delete_output(idx); 265 } else { 266 // Output is either stdout or stderr, which means we can't remove it. 267 // Update the config description to reflect that the output is disabled. 268 output->set_config_string("all=off"); 269 } 270 } 271 272 void LogConfiguration::disable_output(size_t idx) { 273 LogOutput* out = _outputs[idx]; 274 275 // Remove the output from all tagsets. 276 for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { 277 ts->set_output_level(out, LogLevel::Off); 278 ts->update_decorators(); 279 } 280 281 // Delete the output unless stdout/stderr 282 if (out != LogOutput::Stderr && out != LogOutput::Stdout) { 283 delete_output(find_output(out->name())); 284 } else { 285 out->set_config_string("all=off"); 286 } 287 } 288 289 void LogConfiguration::disable_logging() { 290 ConfigurationLock cl; 291 for (size_t i = 0; i < _n_outputs; i++) { 292 disable_output(i); 293 } 294 notify_update_listeners(); 295 } 296 297 void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, ...) { 298 size_t i; 299 va_list ap; 300 LogTagLevelExpression expr; 301 va_start(ap, exact_match); 302 for (i = 0; i < LogTag::MaxTags; i++) { 303 LogTagType tag = static_cast<LogTagType>(va_arg(ap, int)); 304 expr.add_tag(tag); 305 if (tag == LogTag::__NO_TAG) { 306 assert(i > 0, "Must specify at least one tag!"); 307 break; 308 } 309 } 310 assert(i < LogTag::MaxTags || static_cast<LogTagType>(va_arg(ap, int)) == LogTag::__NO_TAG, 311 "Too many tags specified! Can only have up to " SIZE_FORMAT " tags in a tag set.", LogTag::MaxTags); 312 va_end(ap); 313 314 if (!exact_match) { 315 expr.set_allow_other_tags(); 316 } 317 expr.set_level(level); 318 expr.new_combination(); 319 320 // Apply configuration to stdout (output #0), with the same decorators as before. 321 ConfigurationLock cl; 322 configure_output(0, expr, LogOutput::Stdout->decorators()); 323 notify_update_listeners(); 324 } 325 326 bool LogConfiguration::parse_command_line_arguments(const char* opts) { 327 char* copy = os::strdup_check_oom(opts, mtLogging); 328 329 // Split the option string to its colon separated components. 330 char* str = copy; 331 char* substrings[4] = {0}; 332 for (int i = 0 ; i < 4; i++) { 333 substrings[i] = str; 334 335 // Find the next colon or quote 336 char* next = strpbrk(str, ":\""); 337 while (next != NULL && *next == '"') { 338 char* end_quote = strchr(next + 1, '"'); 339 if (end_quote == NULL) { 340 log_error(logging)("Missing terminating quote in -Xlog option '%s'", str); 341 os::free(copy); 342 return false; 343 } 344 // Keep searching after the quoted substring 345 next = strpbrk(end_quote + 1, ":\""); 346 } 347 348 if (next != NULL) { 349 *next = '\0'; 350 str = next + 1; 351 } else { 352 break; 353 } 354 } 355 356 // Parse and apply the separated configuration options 357 char* what = substrings[0]; 358 char* output = substrings[1]; 359 char* decorators = substrings[2]; 360 char* output_options = substrings[3]; 361 char errbuf[512]; 362 stringStream ss(errbuf, sizeof(errbuf)); 363 bool success = parse_log_arguments(output, what, decorators, output_options, &ss); 364 if (!success) { 365 errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline. 366 log_error(logging)("%s", errbuf); 367 } 368 369 os::free(copy); 370 return success; 371 } 372 373 bool LogConfiguration::parse_log_arguments(const char* outputstr, 374 const char* what, 375 const char* decoratorstr, 376 const char* output_options, 377 outputStream* errstream) { 378 if (outputstr == NULL || strlen(outputstr) == 0) { 379 outputstr = "stdout"; 380 } 381 382 LogTagLevelExpression expr; 383 if (!expr.parse(what, errstream)) { 384 return false; 385 } 386 387 LogDecorators decorators; 388 if (!decorators.parse(decoratorstr, errstream)) { 389 return false; 390 } 391 392 ConfigurationLock cl; 393 size_t idx; 394 if (outputstr[0] == '#') { // Output specified using index 395 int ret = sscanf(outputstr + 1, SIZE_FORMAT, &idx); 396 if (ret != 1 || idx >= _n_outputs) { 397 errstream->print_cr("Invalid output index '%s'", outputstr); 398 return false; 399 } 400 } else { // Output specified using name 401 // Normalize the name, stripping quotes and ensures it includes type prefix 402 size_t len = strlen(outputstr) + strlen(implicit_output_prefix) + 1; 403 char* normalized = NEW_C_HEAP_ARRAY(char, len, mtLogging); 404 if (!normalize_output_name(outputstr, normalized, len, errstream)) { 405 return false; 406 } 407 408 idx = find_output(normalized); 409 if (idx == SIZE_MAX) { 410 // Attempt to create and add the output 411 LogOutput* output = new_output(normalized, output_options, errstream); 412 if (output != NULL) { 413 idx = add_output(output); 414 } 415 } else if (output_options != NULL && strlen(output_options) > 0) { 416 errstream->print_cr("Output options for existing outputs are ignored."); 417 } 418 419 FREE_C_HEAP_ARRAY(char, normalized); 420 if (idx == SIZE_MAX) { 421 return false; 422 } 423 } 424 configure_output(idx, expr, decorators); 425 notify_update_listeners(); 426 return true; 427 } 428 429 void LogConfiguration::describe_available(outputStream* out){ 430 out->print("Available log levels:"); 431 for (size_t i = 0; i < LogLevel::Count; i++) { 432 out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i))); 433 } 434 out->cr(); 435 436 out->print("Available log decorators:"); 437 for (size_t i = 0; i < LogDecorators::Count; i++) { 438 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i); 439 out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); 440 } 441 out->cr(); 442 443 out->print("Available log tags:"); 444 for (size_t i = 1; i < LogTag::Count; i++) { 445 out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i))); 446 } 447 out->cr(); 448 449 LogTagSet::describe_tagsets(out); 450 } 451 452 void LogConfiguration::describe_current_configuration(outputStream* out){ 453 out->print_cr("Log output configuration:"); 454 for (size_t i = 0; i < _n_outputs; i++) { 455 out->print("#" SIZE_FORMAT ": ", i); 456 _outputs[i]->describe(out); 457 out->cr(); 458 } 459 } 460 461 void LogConfiguration::describe(outputStream* out) { 462 describe_available(out); 463 ConfigurationLock cl; 464 describe_current_configuration(out); 465 } 466 467 void LogConfiguration::print_command_line_help(FILE* out) { 468 jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" 469 "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" 470 "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); 471 472 jio_fprintf(out, "Available log levels:\n"); 473 for (size_t i = 0; i < LogLevel::Count; i++) { 474 jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i))); 475 } 476 477 jio_fprintf(out, "\n\nAvailable log decorators: \n"); 478 for (size_t i = 0; i < LogDecorators::Count; i++) { 479 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i); 480 jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); 481 } 482 jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n"); 483 484 jio_fprintf(out, "Available log tags:\n"); 485 for (size_t i = 1; i < LogTag::Count; i++) { 486 jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i))); 487 } 488 jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n"); 489 490 fileStream stream(out, false); 491 LogTagSet::describe_tagsets(&stream); 492 493 jio_fprintf(out, "\nAvailable log outputs:\n" 494 " stdout, stderr, file=<filename>\n" 495 " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n" 496 497 "Some examples:\n" 498 " -Xlog\n" 499 "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n" 500 "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n" 501 502 " -Xlog:gc\n" 503 "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" 504 505 " -Xlog:gc=debug:file=gc.txt:none\n" 506 "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" 507 508 " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1m\n" 509 "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n" 510 "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n" 511 512 " -Xlog:gc::uptime,tid\n" 513 "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n" 514 515 " -Xlog:gc*=info,safepoint*=off\n" 516 "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'safepoint'.\n" 517 "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n" 518 519 " -Xlog:disable -Xlog:safepoint=trace:safepointtrace.txt\n" 520 "\t Turn off all logging, including warnings and errors,\n" 521 "\t and then enable messages tagged with 'safepoint' using 'trace' level to file 'safepointtrace.txt'.\n"); 522 } 523 524 void LogConfiguration::rotate_all_outputs() { 525 // Start from index 2 since neither stdout nor stderr can be rotated. 526 for (size_t idx = 2; idx < _n_outputs; idx++) { 527 _outputs[idx]->force_rotate(); 528 } 529 } 530 531 void LogConfiguration::register_update_listener(UpdateListenerFunction cb) { 532 assert(cb != NULL, "Should not register NULL as listener"); 533 ConfigurationLock cl; 534 size_t idx = _n_listener_callbacks++; 535 _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction, 536 _listener_callbacks, 537 _n_listener_callbacks, 538 mtLogging); 539 _listener_callbacks[idx] = cb; 540 } 541 542 void LogConfiguration::notify_update_listeners() { 543 assert(ConfigurationLock::current_thread_has_lock(), "notify_update_listeners must be called in ConfigurationLock scope (lock held)"); 544 for (size_t i = 0; i < _n_listener_callbacks; i++) { 545 _listener_callbacks[i](); 546 } 547 }