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