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