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