1 /*
   2  * Copyright (c) 2015, 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/logTagLevelExpression.hpp"
  33 #include "logging/logTagSet.hpp"
  34 #include "memory/allocation.inline.hpp"
  35 #include "memory/resourceArea.hpp"
  36 #include "runtime/os.inline.hpp"
  37 #include "utilities/globalDefinitions.hpp"
  38 #include "utilities/defaultStream.hpp"
  39 
  40 LogOutput** LogConfiguration::_outputs = NULL;
  41 size_t      LogConfiguration::_n_outputs = 0;
  42 
  43 void LogConfiguration::post_initialize() {
  44   assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization");
  45   LogDiagnosticCommand::registerCommand();
  46   LogHandle(logging) log;
  47   log.info("Log configuration fully initialized.");
  48   if (log.is_trace()) {
  49     ResourceMark rm;
  50     MutexLocker ml(LogConfiguration_lock);
  51     describe(log.trace_stream());
  52   }
  53 }
  54 
  55 void LogConfiguration::initialize(jlong vm_start_time) {
  56   LogFileOutput::set_file_name_parameters(vm_start_time);
  57   LogDecorations::set_vm_start_time_millis(vm_start_time);
  58 
  59   assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
  60   _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
  61   _outputs[0] = LogOutput::Stdout;
  62   _outputs[1] = LogOutput::Stderr;
  63   _n_outputs = 2;
  64 }
  65 
  66 void LogConfiguration::finalize() {
  67   for (size_t i = 2; i < _n_outputs; i++) {
  68     delete _outputs[i];
  69   }
  70   FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
  71 }
  72 
  73 size_t LogConfiguration::find_output(const char* name) {
  74   for (size_t i = 0; i < _n_outputs; i++) {
  75     if (strcmp(_outputs[i]->name(), name) == 0) {
  76       return i;
  77     }
  78   }
  79   return SIZE_MAX;
  80 }
  81 
  82 LogOutput* LogConfiguration::new_output(char* name, const char* options) {
  83   const char* type;
  84   char* equals_pos = strchr(name, '=');
  85   if (equals_pos == NULL) {
  86     type = "file";
  87   } else {
  88     *equals_pos = '\0';
  89     type = name;
  90     name = equals_pos + 1;
  91   }
  92 
  93   LogOutput* output;
  94   if (strcmp(type, "file") == 0) {
  95     output = new LogFileOutput(name);
  96   } else {
  97     // unsupported log output type
  98     return NULL;
  99   }
 100 
 101   bool success = output->initialize(options);
 102   if (!success) {
 103     delete output;
 104     return NULL;
 105   }
 106   return output;
 107 }
 108 
 109 size_t LogConfiguration::add_output(LogOutput* output) {
 110   size_t idx = _n_outputs++;
 111   _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
 112   _outputs[idx] = output;
 113   return idx;
 114 }
 115 
 116 void LogConfiguration::delete_output(size_t idx) {
 117   assert(idx > 1 && idx < _n_outputs,
 118          "idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT
 119          " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
 120   LogOutput* output = _outputs[idx];
 121   // Swap places with the last output and shrink the array
 122   _outputs[idx] = _outputs[--_n_outputs];
 123   _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
 124   delete output;
 125 }
 126 
 127 void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) {
 128   assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
 129   LogOutput* output = _outputs[idx];
 130   output->set_decorators(decorators);
 131   output->set_config_string(tag_level_expression.to_string());
 132   bool enabled = false;
 133   for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 134     LogLevelType level = tag_level_expression.level_for(*ts);
 135     if (level != LogLevel::Off) {
 136       enabled = true;
 137     }
 138     ts->update_decorators(decorators);
 139     ts->set_output_level(output, level);
 140   }
 141 
 142   // If the output is not used by any tagset it should be removed, unless it is stdout/stderr.
 143   if (!enabled && idx > 1) {
 144     delete_output(idx);
 145   }
 146 }
 147 
 148 void LogConfiguration::disable_output(size_t idx) {
 149   LogOutput* out = _outputs[idx];
 150   LogDecorators empty_decorators;
 151   empty_decorators.clear();
 152 
 153   // Remove the output from all tagsets.
 154   for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
 155     ts->set_output_level(out, LogLevel::Off);
 156     ts->update_decorators(empty_decorators);
 157   }
 158 
 159   // Delete the output unless stdout/stderr
 160   if (out != LogOutput::Stderr && out != LogOutput::Stdout) {
 161     delete_output(find_output(out->name()));
 162   } else {
 163     out->set_config_string("all=off");
 164   }
 165 }
 166 
 167 void LogConfiguration::disable_logging() {
 168   assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
 169          "LogConfiguration lock must be held when calling this function");
 170   for (size_t i = 0; i < _n_outputs; i++) {
 171     disable_output(i);
 172   }
 173 }
 174 
 175 bool LogConfiguration::parse_command_line_arguments(const char* opts) {
 176   char* copy = os::strdup_check_oom(opts, mtLogging);
 177 
 178   // Split the option string to its colon separated components.
 179   char* what = NULL;
 180   char* output_str = NULL;
 181   char* decorators_str = NULL;
 182   char* output_options = NULL;
 183 
 184   what = copy;
 185   char* colon = strchr(what, ':');
 186   if (colon != NULL) {
 187     *colon = '\0';
 188     output_str = colon + 1;
 189     colon = strchr(output_str, ':');
 190     if (colon != NULL) {
 191       *colon = '\0';
 192       decorators_str = colon + 1;
 193       colon = strchr(decorators_str, ':');
 194       if (colon != NULL) {
 195         *colon = '\0';
 196         output_options = colon + 1;
 197       }
 198     }
 199   }
 200 
 201   // Parse each argument
 202   char errbuf[512];
 203   stringStream ss(errbuf, sizeof(errbuf));
 204   bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss);
 205   if (!success) {
 206     errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline.
 207     log_error(logging)("%s", errbuf);
 208   }
 209 
 210   os::free(copy);
 211   return success;
 212 }
 213 
 214 bool LogConfiguration::parse_log_arguments(const char* outputstr,
 215                                            const char* what,
 216                                            const char* decoratorstr,
 217                                            const char* output_options,
 218                                            outputStream* errstream) {
 219   assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
 220          "LogConfiguration lock must be held when calling this function");
 221   if (outputstr == NULL || strlen(outputstr) == 0) {
 222     outputstr = "stdout";
 223   }
 224 
 225   size_t idx;
 226   if (outputstr[0] == '#') {
 227     int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx);
 228     if (ret != 1 || idx >= _n_outputs) {
 229       errstream->print_cr("Invalid output index '%s'", outputstr);
 230       return false;
 231     }
 232   } else {
 233     idx = find_output(outputstr);
 234     if (idx == SIZE_MAX) {
 235       char* tmp = os::strdup_check_oom(outputstr, mtLogging);
 236       LogOutput* output = new_output(tmp, output_options);
 237       os::free(tmp);
 238       if (output == NULL) {
 239         errstream->print("Unable to add output '%s'", outputstr);
 240         if (output_options != NULL && strlen(output_options) > 0) {
 241           errstream->print(" with options '%s'", output_options);
 242         }
 243         errstream->cr();
 244         return false;
 245       }
 246       idx = add_output(output);
 247     } else if (output_options != NULL && strlen(output_options) > 0) {
 248       errstream->print_cr("Output options for existing outputs are ignored.");
 249     }
 250   }
 251 
 252   LogTagLevelExpression expr;
 253   if (!expr.parse(what, errstream)) {
 254     return false;
 255   }
 256 
 257   LogDecorators decorators;
 258   if (!decorators.parse(decoratorstr, errstream)) {
 259     return false;
 260   }
 261 
 262   configure_output(idx, expr, decorators);
 263   return true;
 264 }
 265 
 266 void LogConfiguration::describe(outputStream* out) {
 267   assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
 268          "LogConfiguration lock must be held when calling this function");
 269 
 270   out->print("Available log levels:");
 271   for (size_t i = 0; i < LogLevel::Count; i++) {
 272     out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
 273   }
 274   out->cr();
 275 
 276   out->print("Available log decorators:");
 277   for (size_t i = 0; i < LogDecorators::Count; i++) {
 278     LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
 279     out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
 280   }
 281   out->cr();
 282 
 283   out->print("Available log tags:");
 284   for (size_t i = 1; i < LogTag::Count; i++) {
 285     out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
 286   }
 287   out->cr();
 288 
 289   out->print_cr("Log output configuration:");
 290   for (size_t i = 0; i < _n_outputs; i++) {
 291     out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string());
 292     for (size_t d = 0; d < LogDecorators::Count; d++) {
 293       LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
 294       if (_outputs[i]->decorators().is_decorator(decorator)) {
 295         out->print("%s,", LogDecorators::name(decorator));
 296       }
 297     }
 298     out->cr();
 299   }
 300 }
 301 
 302 void LogConfiguration::print_command_line_help(FILE* out) {
 303   jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n"
 304               "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n"
 305               "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n");
 306 
 307   jio_fprintf(out, "Available log levels:\n");
 308   for (size_t i = 0; i < LogLevel::Count; i++) {
 309     jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
 310   }
 311 
 312   jio_fprintf(out, "\n\nAvailable log decorators: \n");
 313   for (size_t i = 0; i < LogDecorators::Count; i++) {
 314     LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
 315     jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
 316   }
 317   jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n");
 318 
 319   jio_fprintf(out, "Available log tags:\n");
 320   for (size_t i = 1; i < LogTag::Count; i++) {
 321     jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
 322   }
 323   jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n");
 324 
 325   jio_fprintf(out, "Available log outputs:\n"
 326               " stdout, stderr, file=<filename>\n"
 327               " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n"
 328 
 329               "Some examples:\n"
 330               " -Xlog\n"
 331               "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n"
 332               "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n"
 333 
 334               " -Xlog:gc\n"
 335               "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n"
 336 
 337               " -Xlog:gc=debug:file=gc.txt:none\n"
 338               "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n"
 339 
 340               " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\n"
 341               "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n"
 342               "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n"
 343 
 344               " -Xlog:gc::uptime,tid\n"
 345               "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n"
 346 
 347               " -Xlog:gc*=info,rt*=off\n"
 348               "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'rt'.\n"
 349               "\t (Messages tagged with both 'gc' and 'rt' will not be logged.)\n\n"
 350 
 351               " -Xlog:disable -Xlog:rt=trace:rttrace.txt\n"
 352               "\t Turn off all logging, including warnings and errors,\n"
 353               "\t and then enable messages tagged with 'rt' using 'trace' level to file 'rttrace.txt'.\n");
 354 }
 355 
 356 void LogConfiguration::rotate_all_logfile() {
 357   for (size_t idx = 0; idx < _n_outputs; idx++) {
 358     if ((strcmp(_outputs[idx]->name(), "stdout") != 0) &&
 359         (strcmp(_outputs[idx]->name(), "stderr") != 0)) {
 360       LogFileOutput *logger = (LogFileOutput *)_outputs[idx];
 361 
 362       if (logger->get_archive_name() == NULL) {
 363        jio_fprintf(defaultStream::error_stream(),
 364         "Could not rotate log file '%s' because filecount option is not set.\n",
 365                                                                 logger->name());
 366       } else {
 367         logger->rotate();
 368       }
 369     }
 370   }
 371 }
 372 
--- EOF ---