< prev index next >

src/share/vm/logging/logConfiguration.cpp

Print this page
rev 11857 : imported patch 8157948
rev 11858 : [mq]: 8157948.01


  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 };


  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) {


 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();




  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 };


  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) {


 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();


< prev index next >