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