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