8190346: improve unified JVM logging help message and warnings
Reviewed-by: lfoltan, rehn, hseigel
--- a/src/hotspot/share/logging/logConfiguration.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logConfiguration.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -83,14 +83,15 @@
if (log.is_info()) {
log.info("Log configuration fully initialized.");
log_develop_info(logging)("Develop logging is available.");
- if (log.is_debug()) {
- LogStream debug_stream(log.debug());
- describe(&debug_stream);
- if (log.is_trace()) {
- LogStream trace_stream(log.trace());
- LogTagSet::list_all_tagsets(&trace_stream);
- }
- }
+
+ LogStream info_stream(log.info());
+ describe_available(&info_stream);
+
+ LogStream debug_stream(log.debug());
+ LogTagSet::list_all_tagsets(&debug_stream);
+
+ ConfigurationLock cl;
+ describe_current_configuration(&info_stream);
}
}
@@ -364,14 +365,24 @@
bool success = parse_log_arguments(output, what, decorators, output_options, &ss);
if (ss.size() > 0) {
- errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline
// If it failed, log the error. If it didn't fail, but something was written
// to the stream, log it as a warning.
- if (!success) {
- log_error(logging)("%s", ss.base());
- } else {
- log_warning(logging)("%s", ss.base());
- }
+ LogLevelType level = success ? LogLevel::Warning : LogLevel::Error;
+
+ Log(logging) log;
+ char* start = errbuf;
+ char* end = strchr(start, '\n');
+ assert(end != NULL, "line must end with newline '%s'", start);
+ do {
+ assert(start < errbuf + sizeof(errbuf) &&
+ end < errbuf + sizeof(errbuf),
+ "buffer overflow");
+ *end = '\0';
+ log.write(level, "%s", start);
+ start = end + 1;
+ end = strchr(start, '\n');
+ assert(end != NULL || *start == '\0', "line must end with newline '%s'", start);
+ } while (end != NULL);
}
os::free(copy);
@@ -459,7 +470,7 @@
void LogConfiguration::describe_current_configuration(outputStream* out){
out->print_cr("Log output configuration:");
for (size_t i = 0; i < _n_outputs; i++) {
- out->print("#" SIZE_FORMAT ": ", i);
+ out->print(" #" SIZE_FORMAT ": ", i);
_outputs[i]->describe(out);
out->cr();
}
@@ -471,68 +482,89 @@
describe_current_configuration(out);
}
-void LogConfiguration::print_command_line_help(FILE* out) {
- jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n"
- "\t where 'what' is a combination of tags and levels of the form tag1[+tag2...][*][=level][,...]\n"
- "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n");
+void LogConfiguration::print_command_line_help(outputStream* out) {
+ out->print_cr("-Xlog Usage: -Xlog[:[selections][:[output][:[decorators][:output-options]]]]");
+ out->print_cr("\t where 'selections' are combinations of tags and levels of the form tag1[+tag2...][*][=level][,...]");
+ out->print_cr("\t NOTE: Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.");
+ out->cr();
- jio_fprintf(out, "Available log levels:\n");
+ out->print_cr("Available log levels:");
for (size_t i = 0; i < LogLevel::Count; i++) {
- jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
+ out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
}
+ out->cr();
+ out->cr();
- jio_fprintf(out, "\n\nAvailable log decorators: \n");
+ out->print_cr("Available log decorators: ");
for (size_t i = 0; i < LogDecorators::Count; i++) {
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
- jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
+ out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
}
- jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n");
+ out->cr();
+ out->print_cr(" Decorators can also be specified as 'none' for no decoration.");
+ out->cr();
- fileStream stream(out, false);
- stream.print_cr("Available log tags:");
- LogTag::list_tags(&stream);
- stream.print_cr(" Specifying 'all' instead of a tag combination matches all tag combinations.");
- stream.cr();
+ out->print_cr("Available log tags:");
+ LogTag::list_tags(out);
+ out->print_cr(" Specifying 'all' instead of a tag combination matches all tag combinations.");
+ out->cr();
- LogTagSet::describe_tagsets(&stream);
+ LogTagSet::describe_tagsets(out);
- jio_fprintf(out, "\nAvailable log outputs:\n"
- " stdout, stderr, file=<filename>\n"
- " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n"
+ out->print_cr("\nAvailable log outputs:");
+ out->print_cr(" stdout/stderr");
+ out->print_cr(" file=<filename>");
+ out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively.");
+ out->print_cr(" Additional output-options for file outputs:");
+ out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)."
+ " If set to 0, log rotation will not trigger automatically,"
+ " but can be performed manually (see the VM.log DCMD).");
+ out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)."
+ " If set to 0, log rotation is disabled."
+ " This will cause existing log files to be overwritten.");
+ out->cr();
- "Some examples:\n"
- " -Xlog\n"
- "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n"
- "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n"
-
- " -Xlog:gc\n"
- "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n"
+ out->print_cr("Some examples:");
+ out->print_cr(" -Xlog");
+ out->print_cr("\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.");
+ out->print_cr("\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).");
+ out->cr();
- " -Xlog:gc,safepoint\n"
- "\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.\n"
- "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n"
+ out->print_cr(" -Xlog:gc");
+ out->print_cr("\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.");
+ out->cr();
+
+ out->print_cr(" -Xlog:gc,safepoint");
+ out->print_cr("\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.");
+ out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
+ out->cr();
- " -Xlog:gc+ref=debug\n"
- "\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.\n"
- "\t (Messages tagged only with one of the two tags will not be logged.)\n\n"
+ out->print_cr(" -Xlog:gc+ref=debug");
+ out->print_cr("\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.");
+ out->print_cr("\t (Messages tagged only with one of the two tags will not be logged.)");
+ out->cr();
- " -Xlog:gc=debug:file=gc.txt:none\n"
- "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n"
+ out->print_cr(" -Xlog:gc=debug:file=gc.txt:none");
+ out->print_cr("\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.");
+ out->cr();
- " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1m\n"
- "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n"
- "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n"
+ out->print_cr(" -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1m");
+ out->print_cr("\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,");
+ out->print_cr("\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.");
+ out->cr();
- " -Xlog:gc::uptime,tid\n"
- "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n"
+ out->print_cr(" -Xlog:gc::uptime,tid");
+ out->print_cr("\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.");
+ out->cr();
- " -Xlog:gc*=info,safepoint*=off\n"
- "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'safepoint'.\n"
- "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n"
+ out->print_cr(" -Xlog:gc*=info,safepoint*=off");
+ out->print_cr("\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'safepoint'.");
+ out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
+ out->cr();
- " -Xlog:disable -Xlog:safepoint=trace:safepointtrace.txt\n"
- "\t Turn off all logging, including warnings and errors,\n"
- "\t and then enable messages tagged with 'safepoint' using 'trace' level to file 'safepointtrace.txt'.\n");
+ out->print_cr(" -Xlog:disable -Xlog:safepoint=trace:safepointtrace.txt");
+ out->print_cr("\t Turn off all logging, including warnings and errors,");
+ out->print_cr("\t and then enable messages tagged with 'safepoint' using 'trace' level to file 'safepointtrace.txt'.");
}
void LogConfiguration::rotate_all_outputs() {
--- a/src/hotspot/share/logging/logConfiguration.hpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logConfiguration.hpp Wed Feb 28 09:30:06 2018 +0100
@@ -119,7 +119,7 @@
static void describe(outputStream* out);
// Prints usage help for command line log configuration.
- static void print_command_line_help(FILE* out);
+ static void print_command_line_help(outputStream* out);
// Rotates all LogOutput
static void rotate_all_outputs();
--- a/src/hotspot/share/logging/logFileOutput.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logFileOutput.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -169,6 +169,7 @@
char* equals_pos = strchr(pos, '=');
if (equals_pos == NULL) {
+ errstream->print_cr("Invalid option '%s' for log file output.", pos);
success = false;
break;
}
--- a/src/hotspot/share/logging/logFileOutput.hpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logFileOutput.hpp Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -85,7 +85,7 @@
virtual int write(const LogDecorations& decorations, const char* msg);
virtual int write(LogMessageBuffer::Iterator msg_iterator);
virtual void force_rotate();
- virtual void describe(outputStream *out);
+ virtual void describe(outputStream* out);
virtual const char* name() const {
return _name;
--- a/src/hotspot/share/logging/logOutput.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logOutput.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,15 +84,20 @@
void LogOutput::describe(outputStream *out) {
out->print("%s ", name());
- out->print_raw(config_string());
- out->print(" ");
- char delimiter[2] = {0};
+ out->print_raw(config_string()); // raw printed because length might exceed O_BUFLEN
+
+ bool has_decorator = false;
+ char delimiter = ' ';
for (size_t d = 0; d < LogDecorators::Count; d++) {
LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
if (decorators().is_decorator(decorator)) {
- out->print("%s%s", delimiter, LogDecorators::name(decorator));
- *delimiter = ',';
+ has_decorator = true;
+ out->print("%c%s", delimiter, LogDecorators::name(decorator));
+ delimiter = ',';
}
}
+ if (!has_decorator) {
+ out->print(" none");
+ }
}
--- a/src/hotspot/share/logging/logSelection.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logSelection.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -23,11 +23,13 @@
*/
#include "precompiled.hpp"
#include "utilities/ostream.hpp"
+#include "logging/log.hpp"
#include "logging/logSelection.hpp"
#include "logging/logTagSet.hpp"
#include "runtime/os.inline.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
+#include "utilities/quickSort.hpp"
const LogSelection LogSelection::Invalid;
@@ -211,3 +213,120 @@
tot_written += written;
return tot_written;
}
+
+double LogSelection::similarity(const LogSelection& other) const {
+ // Compute Soerensen-Dice coefficient as the similarity measure
+ size_t intersecting = 0;
+ for (size_t i = 0; i < _ntags; i++) {
+ for (size_t j = 0; j < other._ntags; j++) {
+ if (_tags[i] == other._tags[j]) {
+ intersecting++;
+ break;
+ }
+ }
+ }
+ return 2.0 * intersecting / (_ntags + other._ntags);
+}
+
+// Comparator used for sorting LogSelections based on their similarity to a specific LogSelection.
+// A negative return value means that 'a' is more similar to 'ref' than 'b' is, while a positive
+// return value means that 'b' is more similar.
+// For the sake of giving short and effective suggestions, when two selections have an equal
+// similarity score, the selection with the fewer tags (selecting the most tag sets) is considered
+// more similar.
+class SimilarityComparator {
+ const LogSelection& _ref;
+ public:
+ SimilarityComparator(const LogSelection& ref) : _ref(ref) {
+ }
+ int operator()(const LogSelection& a, const LogSelection& b) const {
+ const double epsilon = 1.0e-6;
+
+ // Sort by similarity (descending)
+ double s = _ref.similarity(b) - _ref.similarity(a);
+ if (fabs(s) > epsilon) {
+ return s < 0 ? -1 : 1;
+ }
+
+ // Then by number of tags (ascending)
+ int t = static_cast<int>(a.ntags() - (int)b.ntags());
+ if (t != 0) {
+ return t;
+ }
+
+ // Lastly by tag sets selected (descending)
+ return static_cast<int>(b.tag_sets_selected() - a.tag_sets_selected());
+ }
+};
+
+static const size_t suggestion_cap = 5;
+static const double similarity_requirement = 0.3;
+void LogSelection::suggest_similar_matching(outputStream* out) const {
+ LogSelection suggestions[suggestion_cap];
+ uint nsuggestions = 0;
+
+ // See if simply adding a wildcard would make the selection match
+ if (!_wildcard) {
+ LogSelection sel(_tags, true, _level);
+ if (sel.tag_sets_selected() > 0) {
+ suggestions[nsuggestions++] = sel;
+ }
+ }
+
+ // Check for matching tag sets with a single tag mismatching (a tag too many or short a tag)
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG };
+ for (size_t i = 0; i < ts->ntags(); i++) {
+ tags[i] = ts->tag(i);
+ }
+
+ // Suggest wildcard selection unless the wildcard doesn't match anything extra
+ LogSelection sel(tags, true, _level);
+ if (sel.tag_sets_selected() == 1) {
+ sel = LogSelection(tags, false, _level);
+ }
+
+ double score = similarity(sel);
+
+ // Ignore suggestions with too low similarity
+ if (score < similarity_requirement) {
+ continue;
+ }
+
+ // Cap not reached, simply add the new suggestion and continue searching
+ if (nsuggestions < suggestion_cap) {
+ suggestions[nsuggestions++] = sel;
+ continue;
+ }
+
+ // Find the least matching suggestion already found, and if the new suggestion is a better match, replace it
+ double min = 1.0;
+ size_t pos = -1;
+ for (size_t i = 0; i < nsuggestions; i++) {
+ double score = similarity(suggestions[i]);
+ if (score < min) {
+ min = score;
+ pos = i;
+ }
+ }
+ if (score > min) {
+ suggestions[pos] = sel;
+ }
+ }
+
+ if (nsuggestions == 0) {
+ // Found no similar enough selections to suggest.
+ return;
+ }
+
+ // Sort found suggestions to suggest the best one first
+ SimilarityComparator sc(*this);
+ QuickSort::sort(suggestions, nsuggestions, sc, false);
+
+ out->print("Did you mean any of the following?");
+ for (size_t i = 0; i < nsuggestions; i++) {
+ char buf[128];
+ suggestions[i].describe_tags(buf, sizeof(buf));
+ out->print(" %s", buf);
+ }
+}
--- a/src/hotspot/share/logging/logSelection.hpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logSelection.hpp Wed Feb 28 09:30:06 2018 +0100
@@ -62,6 +62,12 @@
int describe_tags(char* buf, size_t bufsize) const;
int describe(char* buf, size_t bufsize) const;
+
+ // List similar selections that matches existing tag sets on the given outputstream
+ void suggest_similar_matching(outputStream* out) const;
+
+ // Compute a similarity measure in the range [0, 1], where higher means more similar
+ double similarity(const LogSelection& other) const;
};
#endif // SHARE_VM_LOGGING_LOGSELECTION_HPP
--- a/src/hotspot/share/logging/logSelectionList.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logSelectionList.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -40,19 +40,17 @@
return false;
}
- if (valid) {
- out->print("No tag set matches selection(s):");
- }
+ out->print("No tag set matches selection:");
valid = false;
char buf[256];
_selections[i].describe_tags(buf, sizeof(buf));
- out->print(" %s", buf);
+ out->print(" %s. ", buf);
+
+ _selections[i].suggest_similar_matching(out);
+ out->cr();
}
}
- if (!valid && out != NULL) {
- out->cr();
- }
return valid;
}
--- a/src/hotspot/share/logging/logTagSet.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/logging/logTagSet.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -141,7 +141,7 @@
static const size_t TagSetBufferSize = 128;
void LogTagSet::describe_tagsets(outputStream* out) {
- out->print_cr("Described tag combinations:");
+ out->print_cr("Described tag sets:");
for (const LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) {
char buf[TagSetBufferSize];
d->tagset->label(buf, sizeof(buf), "+");
@@ -169,7 +169,7 @@
qsort(tagset_labels, _ntagsets, sizeof(*tagset_labels), qsort_strcmp);
// Print and then free the labels
- out->print("All available tag sets: ");
+ out->print("Available tag sets: ");
for (idx = 0; idx < _ntagsets; idx++) {
out->print("%s%s", (idx == 0 ? "" : ", "), tagset_labels[idx]);
os::free(tagset_labels[idx]);
--- a/src/hotspot/share/runtime/arguments.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/src/hotspot/share/runtime/arguments.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -3096,7 +3096,8 @@
} else if (match_option(option, "-Xlog", &tail)) {
bool ret = false;
if (strcmp(tail, ":help") == 0) {
- LogConfiguration::print_command_line_help(defaultStream::output_stream());
+ fileStream stream(defaultStream::output_stream());
+ LogConfiguration::print_command_line_help(&stream);
vm_exit(0);
} else if (strcmp(tail, ":disable") == 0) {
LogConfiguration::disable_logging();
@@ -3109,7 +3110,7 @@
}
if (ret == false) {
jio_fprintf(defaultStream::error_stream(),
- "Invalid -Xlog option '-Xlog%s'\n",
+ "Invalid -Xlog option '-Xlog%s', see error log for details.\n",
tail);
return JNI_EINVAL;
}
--- a/test/hotspot/gtest/logging/test_logConfiguration.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/test/hotspot/gtest/logging/test_logConfiguration.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -225,7 +225,7 @@
// Now reconfigure logging on stderr with no decorators
set_log_config("stderr", "all=off", "none");
- EXPECT_TRUE(is_described("#1: stderr all=off \n")) << "Expecting no decorators";
+ EXPECT_TRUE(is_described("#1: stderr all=off none\n")) << "Expecting no decorators";
}
// Test that invalid options cause configuration errors
@@ -383,7 +383,7 @@
bool success = LogConfiguration::parse_log_arguments("stdout", invalid_tagset, NULL, NULL, &ss);
const char* msg = ss.as_string();
EXPECT_TRUE(success) << "Should only cause a warning, not an error";
- EXPECT_TRUE(string_contains_substring(msg, "No tag set matches selection(s):"));
+ EXPECT_TRUE(string_contains_substring(msg, "No tag set matches selection:"));
EXPECT_TRUE(string_contains_substring(msg, invalid_tagset));
}
@@ -413,3 +413,21 @@
ASSERT_NE(-1, ret);
delete_file(buf);
}
+
+TEST_VM_F(LogConfigurationTest, suggest_similar_selection) {
+ static const char* nonexisting_tagset = "logging+start+exit+safepoint+gc";
+
+ ResourceMark rm;
+ stringStream ss;
+ LogConfiguration::parse_log_arguments("stdout", nonexisting_tagset, NULL, NULL, &ss);
+
+ const char* suggestion = ss.as_string();
+ SCOPED_TRACE(suggestion);
+ EXPECT_TRUE(string_contains_substring(ss.as_string(), "Did you mean any of the following?"));
+ EXPECT_TRUE(string_contains_substring(suggestion, "logging") ||
+ string_contains_substring(suggestion, "start") ||
+ string_contains_substring(suggestion, "exit") ||
+ string_contains_substring(suggestion, "safepoint") ||
+ string_contains_substring(suggestion, "gc")) <<
+ "suggestion must contain AT LEAST one of the tags in user supplied selection";
+}
--- a/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp Tue Feb 27 21:29:19 2018 -0800
+++ b/test/hotspot/gtest/logging/test_logTagSetDescriptions.cpp Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,8 @@
const char* filename = "logtagset_descriptions";
FILE* fp = fopen(filename, "w+");
ASSERT_NE((void*)NULL, fp);
- LogConfiguration::print_command_line_help(fp);
+ fileStream stream(fp);
+ LogConfiguration::print_command_line_help(&stream);
fclose(fp);
for (LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) {
--- a/test/hotspot/jtreg/serviceability/logging/TestMultipleXlogArgs.java Tue Feb 27 21:29:19 2018 -0800
+++ b/test/hotspot/jtreg/serviceability/logging/TestMultipleXlogArgs.java Wed Feb 28 09:30:06 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
// -Xlog:logging=trace means that the log configuration will be printed.
- String stdoutConfigLine = "\\[logging *\\] #0: stdout .*";
+ String stdoutConfigLine = "\\[logging *\\] #0: stdout .*";
// Ensure logging=trace has overwritten logging=debug
output.shouldMatch(stdoutConfigLine + "logging=trace").shouldNotMatch(stdoutConfigLine + "logging=debug");
// Make sure safepoint=info is printed exactly once even though we're setting it twice