8196783: Refactor LogTagLevelExpression into separate classes
Reviewed-by: rehn, pliden
--- a/src/hotspot/share/logging/logConfiguration.cpp Mon Feb 19 09:16:04 2018 +0100
+++ b/src/hotspot/share/logging/logConfiguration.cpp Mon Feb 19 09:46:10 2018 +0100
@@ -30,8 +30,8 @@
#include "logging/logDiagnosticCommand.hpp"
#include "logging/logFileOutput.hpp"
#include "logging/logOutput.hpp"
+#include "logging/logSelectionList.hpp"
#include "logging/logStream.hpp"
-#include "logging/logTagLevelExpression.hpp"
#include "logging/logTagSet.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@@ -207,7 +207,7 @@
delete output;
}
-void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) {
+void LogConfiguration::configure_output(size_t idx, const LogSelectionList& selections, const LogDecorators& decorators) {
assert(ConfigurationLock::current_thread_has_lock(), "Must hold configuration lock to call this function.");
assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
LogOutput* output = _outputs[idx];
@@ -217,7 +217,7 @@
bool enabled = false;
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- LogLevelType level = tag_level_expression.level_for(*ts);
+ LogLevelType level = selections.level_for(*ts);
// Ignore tagsets that do not, and will not log on the output
if (!ts->has_output(output) && (level == LogLevel::NotMentioned || level == LogLevel::Off)) {
@@ -299,11 +299,11 @@
void LogConfiguration::configure_stdout(LogLevelType level, int exact_match, ...) {
size_t i;
va_list ap;
- LogTagLevelExpression expr;
+ LogTagType tags[LogTag::MaxTags];
va_start(ap, exact_match);
for (i = 0; i < LogTag::MaxTags; i++) {
LogTagType tag = static_cast<LogTagType>(va_arg(ap, int));
- expr.add_tag(tag);
+ tags[i] = tag;
if (tag == LogTag::__NO_TAG) {
assert(i > 0, "Must specify at least one tag!");
break;
@@ -313,17 +313,14 @@
"Too many tags specified! Can only have up to " SIZE_FORMAT " tags in a tag set.", LogTag::MaxTags);
va_end(ap);
- if (!exact_match) {
- expr.set_allow_other_tags();
- }
- expr.set_level(level);
- expr.new_combination();
- assert(expr.verify_tagsets(),
- "configure_stdout() called with invalid/non-existing tag set");
+ LogSelection selection(tags, !exact_match, level);
+ assert(selection.tag_sets_selected() > 0,
+ "configure_stdout() called with invalid/non-existing log selection");
+ LogSelectionList list(selection);
// Apply configuration to stdout (output #0), with the same decorators as before.
ConfigurationLock cl;
- configure_output(0, expr, _outputs[0]->decorators());
+ configure_output(0, list, _outputs[0]->decorators());
notify_update_listeners();
}
@@ -382,7 +379,7 @@
}
bool LogConfiguration::parse_log_arguments(const char* outputstr,
- const char* what,
+ const char* selectionstr,
const char* decoratorstr,
const char* output_options,
outputStream* errstream) {
@@ -391,8 +388,8 @@
outputstr = "stdout";
}
- LogTagLevelExpression expr;
- if (!expr.parse(what, errstream)) {
+ LogSelectionList selections;
+ if (!selections.parse(selectionstr, errstream)) {
return false;
}
@@ -433,9 +430,9 @@
return false;
}
}
- configure_output(idx, expr, decorators);
+ configure_output(idx, selections, decorators);
notify_update_listeners();
- expr.verify_tagsets(errstream);
+ selections.verify_selections(errstream);
return true;
}
--- a/src/hotspot/share/logging/logConfiguration.hpp Mon Feb 19 09:16:04 2018 +0100
+++ b/src/hotspot/share/logging/logConfiguration.hpp Mon Feb 19 09:46:10 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
@@ -30,7 +30,7 @@
class LogOutput;
class LogDecorators;
-class LogTagLevelExpression;
+class LogSelectionList;
// Global configuration of logging. Handles parsing and configuration of the logging framework,
// and manages the list of configured log outputs. The actual tag and level configuration is
@@ -75,7 +75,7 @@
static size_t find_output(const char* name);
// Configure output (add or update existing configuration) to log on tag-level combination using specified decorators.
- static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators);
+ static void configure_output(size_t idx, const LogSelectionList& tag_level_expression, const LogDecorators& decorators);
// This should be called after any configuration change while still holding ConfigurationLock
static void notify_update_listeners();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/logging/logSelection.cpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#include "precompiled.hpp"
+#include "utilities/ostream.hpp"
+#include "logging/logSelection.hpp"
+#include "logging/logTagSet.hpp"
+#include "runtime/os.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+
+const LogSelection LogSelection::Invalid;
+
+LogSelection::LogSelection() : _ntags(0), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) {
+}
+
+LogSelection::LogSelection(const LogTagType tags[LogTag::MaxTags], bool wildcard, LogLevelType level)
+ : _ntags(0), _wildcard(wildcard), _level(level), _tag_sets_selected(0) {
+ while (_ntags < LogTag::MaxTags && tags[_ntags] != LogTag::__NO_TAG) {
+ _tags[_ntags] = tags[_ntags];
+ _ntags++;
+ }
+
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ if (selects(*ts)) {
+ _tag_sets_selected++;
+ }
+ }
+}
+
+bool LogSelection::operator==(const LogSelection& ref) const {
+ if (_ntags != ref._ntags ||
+ _wildcard != ref._wildcard ||
+ _level != ref._level ||
+ _tag_sets_selected != ref._tag_sets_selected) {
+ return false;
+ }
+ for (size_t i = 0; i < _ntags; i++) {
+ if (_tags[i] != ref._tags[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LogSelection::operator!=(const LogSelection& ref) const {
+ return !operator==(ref);
+}
+
+static LogSelection parse_internal(char *str, outputStream* errstream) {
+ // Parse the level, if specified
+ LogLevelType level = LogLevel::Unspecified;
+ char* equals = strchr(str, '=');
+ if (equals != NULL) {
+ level = LogLevel::from_string(equals + 1);
+ if (level == LogLevel::Invalid) {
+ if (errstream != NULL) {
+ errstream->print_cr("Invalid level '%s' in log selection.", equals + 1);
+ }
+ return LogSelection::Invalid;
+ }
+ *equals = '\0';
+ }
+
+ size_t ntags = 0;
+ LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG };
+
+ // Parse special tags such as 'all'
+ if (strcmp(str, "all") == 0) {
+ return LogSelection(tags, true, level);
+ }
+
+ // Check for '*' suffix
+ bool wildcard = false;
+ char* asterisk_pos = strchr(str, '*');
+ if (asterisk_pos != NULL && asterisk_pos[1] == '\0') {
+ wildcard = true;
+ *asterisk_pos = '\0';
+ }
+
+ // Parse the tag expression (t1+t2+...+tn)
+ char* plus_pos;
+ char* cur_tag = str;
+ do {
+ plus_pos = strchr(cur_tag, '+');
+ if (plus_pos != NULL) {
+ *plus_pos = '\0';
+ }
+ LogTagType tag = LogTag::from_string(cur_tag);
+ if (tag == LogTag::__NO_TAG) {
+ if (errstream != NULL) {
+ errstream->print_cr("Invalid tag '%s' in log selection.", cur_tag);
+ }
+ return LogSelection::Invalid;
+ }
+ if (ntags == LogTag::MaxTags) {
+ if (errstream != NULL) {
+ errstream->print_cr("Too many tags in log selection '%s' (can only have up to " SIZE_FORMAT " tags).",
+ str, LogTag::MaxTags);
+ }
+ return LogSelection::Invalid;
+ }
+ tags[ntags++] = tag;
+ cur_tag = plus_pos + 1;
+ } while (plus_pos != NULL);
+
+ for (size_t i = 0; i < ntags; i++) {
+ for (size_t j = 0; j < ntags; j++) {
+ if (i != j && tags[i] == tags[j]) {
+ if (errstream != NULL) {
+ errstream->print_cr("Log selection contains duplicates of tag %s.", LogTag::name(tags[i]));
+ }
+ return LogSelection::Invalid;
+ }
+ }
+ }
+
+ return LogSelection(tags, wildcard, level);
+}
+
+LogSelection LogSelection::parse(const char* str, outputStream* error_stream) {
+ char* copy = os::strdup_check_oom(str, mtLogging);
+ LogSelection s = parse_internal(copy, error_stream);
+ os::free(copy);
+ return s;
+}
+
+bool LogSelection::selects(const LogTagSet& ts) const {
+ if (!_wildcard && _ntags != ts.ntags()) {
+ return false;
+ }
+ for (size_t i = 0; i < _ntags; i++) {
+ if (!ts.contains(_tags[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+size_t LogSelection::ntags() const {
+ return _ntags;
+}
+
+LogLevelType LogSelection::level() const {
+ return _level;
+}
+
+size_t LogSelection::tag_sets_selected() const {
+ return _tag_sets_selected;
+}
+
+int LogSelection::describe_tags(char* buf, size_t bufsize) const {
+ int tot_written = 0;
+ for (size_t i = 0; i < _ntags; i++) {
+ int written = jio_snprintf(buf + tot_written, bufsize - tot_written,
+ "%s%s", (i == 0 ? "" : "+"), LogTag::name(_tags[i]));
+ if (written == -1) {
+ return written;
+ }
+ tot_written += written;
+ }
+
+ if (_wildcard) {
+ int written = jio_snprintf(buf + tot_written, bufsize - tot_written, "*");
+ if (written == -1) {
+ return written;
+ }
+ tot_written += written;
+ }
+ return tot_written;
+}
+
+int LogSelection::describe(char* buf, size_t bufsize) const {
+ int tot_written = describe_tags(buf, bufsize);
+
+ int written = jio_snprintf(buf + tot_written, bufsize - tot_written, "=%s", LogLevel::name(_level));
+ if (written == -1) {
+ return -1;
+ }
+ tot_written += written;
+ return tot_written;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/logging/logSelection.hpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGSELECTION_HPP
+#define SHARE_VM_LOGGING_LOGSELECTION_HPP
+
+#include "logging/logLevel.hpp"
+#include "logging/logTag.hpp"
+#include "memory/allocation.hpp"
+
+class LogTagSet;
+
+// Class representing a selection of tags with for a given level.
+// Consists of a set of tags, an optional wildcard flag, and a level, e.g. "tag1+tag2*=level".
+class LogSelection : public StackObj {
+ friend class LogSelectionList;
+
+ private:
+ size_t _ntags;
+ LogTagType _tags[LogTag::MaxTags];
+ bool _wildcard;
+ LogLevelType _level;
+ size_t _tag_sets_selected;
+
+ LogSelection();
+
+ public:
+ static const LogSelection Invalid;
+
+ static LogSelection parse(const char* str, outputStream* error_stream = NULL);
+
+ LogSelection(const LogTagType tags[LogTag::MaxTags], bool wildcard, LogLevelType level);
+
+ bool operator==(const LogSelection& ref) const;
+ bool operator!=(const LogSelection& ref) const;
+
+ size_t ntags() const;
+ LogLevelType level() const;
+ size_t tag_sets_selected() const;
+
+ bool selects(const LogTagSet& ts) const;
+
+ int describe_tags(char* buf, size_t bufsize) const;
+ int describe(char* buf, size_t bufsize) const;
+};
+
+#endif // SHARE_VM_LOGGING_LOGSELECTION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/logging/logSelectionList.cpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,103 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/logSelectionList.hpp"
+#include "logging/logTagSet.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/os.inline.hpp"
+
+static const char* DefaultExpressionString = "all";
+
+bool LogSelectionList::verify_selections(outputStream* out) const {
+ bool valid = true;
+
+ for (size_t i = 0; i < _nselections; i++) {
+ if (_selections[i].tag_sets_selected() == 0) {
+ // Return immediately unless all invalid selections should be listed
+ if (out == NULL) {
+ return false;
+ }
+
+ if (valid) {
+ out->print("No tag set matches selection(s):");
+ }
+ valid = false;
+
+ char buf[256];
+ _selections[i].describe_tags(buf, sizeof(buf));
+ out->print(" %s", buf);
+ }
+ }
+ if (!valid && out != NULL) {
+ out->cr();
+ }
+ return valid;
+}
+
+
+bool LogSelectionList::parse(const char* str, outputStream* errstream) {
+ bool success = true;
+ if (str == NULL || strcmp(str, "") == 0) {
+ str = DefaultExpressionString;
+ }
+ char* copy = os::strdup_check_oom(str, mtLogging);
+ // Split string on commas
+ for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) {
+ if (_nselections == MaxSelections) {
+ if (errstream != NULL) {
+ errstream->print_cr("Can not have more than " SIZE_FORMAT " log selections in a single configuration.",
+ MaxSelections);
+ }
+ success = false;
+ break;
+ }
+
+ comma_pos = strchr(cur, ',');
+ if (comma_pos != NULL) {
+ *comma_pos = '\0';
+ }
+
+ LogSelection selection = LogSelection::parse(cur, errstream);
+ if (selection == LogSelection::Invalid) {
+ success = false;
+ break;
+ }
+ _selections[_nselections++] = selection;
+ }
+
+ os::free(copy);
+ return success;
+}
+
+LogLevelType LogSelectionList::level_for(const LogTagSet& ts) const {
+ // Return NotMentioned if the given tagset isn't covered by this expression.
+ LogLevelType level = LogLevel::NotMentioned;
+ for (size_t i= 0; i < _nselections; i++) {
+ if (_selections[i].selects(ts)) {
+ level = _selections[i].level();
+ }
+ }
+ return level;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/logging/logSelectionList.hpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGSELECTIONLIST_HPP
+#define SHARE_VM_LOGGING_LOGSELECTIONLIST_HPP
+
+#include "logging/logConfiguration.hpp"
+#include "logging/logSelection.hpp"
+#include "logging/logTag.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogTagSet;
+
+// Class used to temporary encode a series of log selections during log configuration.
+// Consists of ordered LogSelections, i.e. "tag1+tag2=level1,tag3*=level2".
+class LogSelectionList : public StackObj {
+ public:
+ static const size_t MaxSelections = 256;
+
+ private:
+ friend void LogConfiguration::configure_stdout(LogLevelType, int, ...);
+
+ size_t _nselections;
+ LogSelection _selections[MaxSelections];
+
+ public:
+ LogSelectionList() : _nselections(0) {
+ }
+
+ LogSelectionList(const LogSelection& selection) : _nselections(1) {
+ _selections[0] = selection;
+ }
+
+ bool parse(const char* str, outputStream* errstream = NULL);
+ LogLevelType level_for(const LogTagSet& ts) const;
+
+ // Verify that each selection actually selects something.
+ // Returns false if some invalid selection was found. If given an outputstream,
+ // this function will list all the invalid selections on the stream.
+ bool verify_selections(outputStream* out = NULL) const;
+};
+
+#endif // SHARE_VM_LOGGING_LOGSELECTIONLIST_HPP
--- a/src/hotspot/share/logging/logTagLevelExpression.cpp Mon Feb 19 09:16:04 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-#include "precompiled.hpp"
-#include "logging/logTagLevelExpression.hpp"
-#include "logging/logTagSet.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/os.inline.hpp"
-
-const char* LogTagLevelExpression::DefaultExpressionString = "all";
-
-static bool matches_tagset(const LogTagType tags[],
- bool allow_other_tags,
- const LogTagSet& ts) {
- bool contains_all = true;
- size_t tag_idx;
- for (tag_idx = 0; tag_idx < LogTag::MaxTags && tags[tag_idx] != LogTag::__NO_TAG; tag_idx++) {
- if (!ts.contains(tags[tag_idx])) {
- contains_all = false;
- break;
- }
- }
- // All tags in the expression must be part of the tagset,
- // and either the expression allows other tags (has a wildcard),
- // or the number of tags in the expression and tagset must match.
- return contains_all && (allow_other_tags || tag_idx == ts.ntags());
-}
-
-bool LogTagLevelExpression::verify_tagsets(outputStream* out) const {
- bool valid = true;
-
- for (size_t i = 0; i < _ncombinations; i++) {
- bool matched = false;
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- if (matches_tagset(_tags[i], _allow_other_tags[i], *ts)) {
- matched = true;
- break;
- }
- }
-
- if (!matched) {
- // If this was the first invalid combination, write the message header
- if (valid && out != NULL) {
- out->print("No tag set matches selection(s): ");
- }
- valid = false;
-
- // Break as soon as possible unless listing all invalid combinations
- if (out == NULL) {
- break;
- }
-
- // List the combination on the outputStream
- for (size_t t = 0; t < LogTag::MaxTags && _tags[i][t] != LogTag::__NO_TAG; t++) {
- out->print("%s%s", (t == 0 ? "" : "+"), LogTag::name(_tags[i][t]));
- }
- if (_allow_other_tags[i]) {
- out->print("*");
- }
- out->print(" ");
- }
- }
-
- if (!valid && out != NULL) {
- out->cr();
- }
-
- return valid;
-}
-
-bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) {
- bool success = true;
- if (str == NULL || strcmp(str, "") == 0) {
- str = DefaultExpressionString;
- }
- char* copy = os::strdup_check_oom(str, mtLogging);
- // Split string on commas
- for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) {
- if (_ncombinations == MaxCombinations) {
- if (errstream != NULL) {
- errstream->print_cr("Can not have more than " SIZE_FORMAT " tag combinations in a what-expression.",
- MaxCombinations);
- }
- success = false;
- break;
- }
-
- comma_pos = strchr(cur, ',');
- if (comma_pos != NULL) {
- *comma_pos = '\0';
- }
-
- // Parse the level, if specified
- LogLevelType level = LogLevel::Unspecified;
- char* equals = strchr(cur, '=');
- if (equals != NULL) {
- level = LogLevel::from_string(equals + 1);
- if (level == LogLevel::Invalid) {
- if (errstream != NULL) {
- errstream->print_cr("Invalid level '%s' in what-expression.", equals + 1);
- }
- success = false;
- break;
- }
- *equals = '\0'; // now ignore "=level" part of substr
- }
- set_level(level);
-
- // Parse special tags such as 'all'
- if (strcmp(cur, "all") == 0) {
- set_allow_other_tags();
- new_combination();
- continue;
- }
-
- // Check for '*' suffix
- char* asterisk_pos = strchr(cur, '*');
- if (asterisk_pos != NULL && asterisk_pos[1] == '\0') {
- set_allow_other_tags();
- *asterisk_pos = '\0';
- }
-
- // Parse the tag expression (t1+t2+...+tn)
- char* plus_pos;
- char* cur_tag = cur;
- do {
- plus_pos = strchr(cur_tag, '+');
- if (plus_pos != NULL) {
- *plus_pos = '\0';
- }
- LogTagType tag = LogTag::from_string(cur_tag);
- if (tag == LogTag::__NO_TAG) {
- if (errstream != NULL) {
- errstream->print_cr("Invalid tag '%s' in what-expression.", cur_tag);
- }
- success = false;
- break;
- }
- if (_ntags == LogTag::MaxTags) {
- if (errstream != NULL) {
- errstream->print_cr("Tag combination exceeds the maximum of " SIZE_FORMAT " tags.",
- LogTag::MaxTags);
- }
- success = false;
- break;
- }
- if (!add_tag(tag)) {
- if (errstream != NULL) {
- errstream->print_cr("Tag combination have duplicate tag '%s' in what-expression.",
- cur_tag);
- }
- success = false;
- break;
- }
- cur_tag = plus_pos + 1;
- } while (plus_pos != NULL);
-
- new_combination();
- }
-
- os::free(copy);
- return success;
-}
-
-LogLevelType LogTagLevelExpression::level_for(const LogTagSet& ts) const {
- // Return NotMentioned if the given tagset isn't covered by this expression.
- LogLevelType level = LogLevel::NotMentioned;
- for (size_t combination = 0; combination < _ncombinations; combination++) {
- if (matches_tagset(_tags[combination], _allow_other_tags[combination], ts)) {
- level = _level[combination];
- }
- }
- return level;
-}
-
--- a/src/hotspot/share/logging/logTagLevelExpression.hpp Mon Feb 19 09:16:04 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-#ifndef SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
-#define SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
-
-#include "logging/logConfiguration.hpp"
-#include "logging/logLevel.hpp"
-#include "logging/logTag.hpp"
-#include "memory/allocation.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-class LogTagSet;
-
-// Class used to temporary encode a 'what'-expression during log configuration.
-// Consists of a combination of tags and levels, e.g. "tag1+tag2=level1,tag3*=level2".
-class LogTagLevelExpression : public StackObj {
- public:
- static const size_t MaxCombinations = 256;
-
- private:
- friend void LogConfiguration::configure_stdout(LogLevelType, int, ...);
-
- static const char* DefaultExpressionString;
-
- size_t _ntags, _ncombinations;
- LogTagType _tags[MaxCombinations][LogTag::MaxTags];
- LogLevelType _level[MaxCombinations];
- bool _allow_other_tags[MaxCombinations];
-
- void new_combination() {
- // Make sure either all tags are set or the last tag is __NO_TAG
- if (_ntags < LogTag::MaxTags) {
- _tags[_ncombinations][_ntags] = LogTag::__NO_TAG;
- }
-
- _ncombinations++;
- _ntags = 0;
- }
-
- bool add_tag(LogTagType tag) {
- assert(_ntags < LogTag::MaxTags, "Can't have more tags than MaxTags!");
- for (size_t i = 0; i < _ntags; i++) {
- if (_tags[_ncombinations][i] == tag) {
- return false;
- }
- }
- _tags[_ncombinations][_ntags++] = tag;
- return true;
- }
-
- void set_level(LogLevelType level) {
- _level[_ncombinations] = level;
- }
-
- void set_allow_other_tags() {
- _allow_other_tags[_ncombinations] = true;
- }
-
- public:
- LogTagLevelExpression() : _ntags(0), _ncombinations(0) {
- for (size_t combination = 0; combination < MaxCombinations; combination++) {
- _level[combination] = LogLevel::Invalid;
- _allow_other_tags[combination] = false;
- _tags[combination][0] = LogTag::__NO_TAG;
- }
- }
-
- bool parse(const char* str, outputStream* errstream = NULL);
- LogLevelType level_for(const LogTagSet& ts) const;
-
- // Verify the tagsets/selections mentioned in this expression.
- // Returns false if some invalid tagset was found. If given an outputstream,
- // this function will list all the invalid selections on the stream.
- bool verify_tagsets(outputStream* out = NULL) const;
-};
-
-#endif // SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
--- a/test/hotspot/gtest/logging/logTestUtils.inline.hpp Mon Feb 19 09:16:04 2018 +0100
+++ b/test/hotspot/gtest/logging/logTestUtils.inline.hpp Mon Feb 19 09:46:10 2018 +0100
@@ -30,6 +30,12 @@
#define LOG_TEST_STRING_LITERAL "a (hopefully) unique log message for testing"
+static const char* invalid_selection_substr[] = {
+ "=", "+", " ", "+=", "+=*", "*+", " +", "**", "++", ".", ",", ",," ",+",
+ " *", "all+", "all*", "+all", "+all=Warning", "==Info", "=InfoWarning",
+ "BadTag+", "logging++", "logging*+", ",=", "gc+gc+"
+};
+
static inline bool string_contains_substring(const char* haystack, const char* needle) {
return strstr(haystack, needle) != NULL;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/logging/test_logSelection.cpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,203 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "logging/logLevel.hpp"
+#include "logging/logSelection.hpp"
+#include "logging/logTagSet.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "logTestUtils.inline.hpp"
+#include "unittest.hpp"
+
+// These tests can only run in debug VMs because they rely on the (debug-only) LogTag::_test
+#ifdef ASSERT
+
+#define NON_EXISTING_TAG_SET "logging+test+start+exit+safepoint"
+
+// let google test know how to print LogSelection nicely for better error messages
+void PrintTo(const LogSelection& sel, ::std::ostream* os) {
+ if (sel == LogSelection::Invalid) {
+ *os << "LogSelection::Invalid";
+ return;
+ }
+ char buf[256];
+ sel.describe(buf, sizeof(buf));
+ *os << buf;
+}
+
+TEST(LogSelection, sanity) {
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, false, LogLevel::Trace);
+
+ EXPECT_EQ(2u, selection.ntags());
+ EXPECT_EQ(LogLevel::Trace, selection.level());
+
+ // Verify that copying the selection also works as expected
+ LogSelection copy = selection;
+ EXPECT_EQ(2u, copy.ntags());
+ EXPECT_EQ(LogLevel::Trace, copy.level());
+
+ tags[0] = PREFIX_LOG_TAG(gc);
+ tags[1] = PREFIX_LOG_TAG(_NO_TAG);
+ LogSelection copy2(tags, true, LogLevel::Off); // start with a completely different selection
+ copy2 = selection; // and test copy assignment
+ EXPECT_EQ(2u, copy2.ntags());
+ EXPECT_EQ(LogLevel::Trace, copy2.level());
+}
+
+TEST(LogSelection, tag_sets_selected) {
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, false, LogLevel::Trace);
+
+ EXPECT_EQ(1u, selection.tag_sets_selected()) << "there should be a single (it's not a wildcard selection) "
+ "tag set selected by this (in gtest libjvm)";
+
+ EXPECT_EQ(LogTagSet::ntagsets(), LogSelection::parse("all").tag_sets_selected()) << "all should select every tag set";
+ EXPECT_EQ(0u, LogSelection::parse(NON_EXISTING_TAG_SET).tag_sets_selected()) <<
+ "(assuming the tag set doesn't exist) the selection shouldn't select any tag sets";
+}
+
+static const char* valid_expression[] = {
+ "all", "gc", "gc+logging", "logging+gc", "logging+gc*", "gc=trace",
+ "logging+gc=trace", "logging*", "logging*=info", "gc+logging*=error"
+};
+
+TEST(LogSelection, parse) {
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, true, LogLevel::Off);
+ LogSelection parsed = LogSelection::parse("logging+test*=off");
+ EXPECT_EQ(selection, parsed) << "parsed selection not equal to programmatically constructed";
+
+ // Verify valid expressions parse without problems
+ for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
+ EXPECT_NE(LogSelection::Invalid, LogSelection::parse(valid_expression[i])) <<
+ "Valid expression '" << valid_expression[i] << "' did not parse";
+ }
+
+ // Test 'all' with each level
+ for (LogLevelType level = LogLevel::First; level <= LogLevel::Last; level = static_cast<LogLevelType>(level + 1)) {
+ char buf[64];
+ int ret = jio_snprintf(buf, sizeof(buf), "all=%s", LogLevel::name(level));
+ ASSERT_NE(-1, ret);
+
+ LogSelection sel = LogSelection::parse(buf);
+ EXPECT_EQ(LogTagSet::ntagsets(), sel.tag_sets_selected()) << "'all' should select all tag sets";
+ EXPECT_EQ(level, sel.level());
+ }
+
+ // Test with 5 tags
+ LogTagType expected_tags[] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(start),
+ PREFIX_LOG_TAG(exit), PREFIX_LOG_TAG(safepoint) };
+ LogSelection expected(expected_tags, false, LogLevel::Debug);
+ LogSelection five_tag_selection = LogSelection::parse("logging+test+start+exit+safepoint=debug");
+ EXPECT_EQ(5u, five_tag_selection.ntags()) << "parsed wrong number of tags";
+ EXPECT_EQ(expected, five_tag_selection);
+ EXPECT_EQ(LogLevel::Debug, five_tag_selection.level());
+
+ // Test implicit level
+ selection = LogSelection::parse("logging");
+ EXPECT_EQ(LogLevel::Unspecified, selection.level()) << "parsed implicit level incorrectly";
+ EXPECT_EQ(1u, selection.ntags());
+}
+
+TEST(LogSelection, parse_invalid) {
+
+ // Attempt to parse an expression with too many tags
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(NON_EXISTING_TAG_SET "+gc"));
+
+ // Construct a bunch of invalid expressions and verify that they don't parse
+ for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
+ char buf[256];
+ for (size_t j = 0; j < ARRAY_SIZE(invalid_selection_substr); j++) {
+ // Prefix with invalid substr
+ jio_snprintf(buf, sizeof(buf), "%s%s", invalid_selection_substr[j], valid_expression[i]);
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ // Suffix with invalid substr
+ jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_selection_substr[j]);
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ // Use only the invalid substr
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(invalid_selection_substr[j])) <<
+ "'" << invalid_selection_substr[j] << "'" << " considered legal";
+ }
+
+ // Suffix/prefix with some unique invalid prefixes/suffixes
+ jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ jio_snprintf(buf, sizeof(buf), "logging*%s", valid_expression[i]);
+ EXPECT_EQ(LogSelection::Invalid, LogSelection::parse(buf)) << "'" << buf << "'" << " considered legal";
+ }
+}
+
+TEST(LogSelection, equals) {
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, true, LogLevel::Info);
+ LogSelection copy(tags, true, LogLevel::Info);
+ EXPECT_EQ(selection, selection);
+ EXPECT_EQ(selection, copy);
+
+ tags[0] = PREFIX_LOG_TAG(gc);
+ LogSelection other_tags(tags, true, LogLevel::Info);
+ EXPECT_NE(selection, other_tags);
+
+ tags[0] = PREFIX_LOG_TAG(test);
+ tags[1] = PREFIX_LOG_TAG(logging);
+ LogSelection reversed(tags, true, LogLevel::Info);
+ EXPECT_NE(selection, reversed);
+
+ LogSelection no_wildcard(tags, false, LogLevel::Info);
+ EXPECT_NE(selection, no_wildcard);
+
+ LogSelection different_level(tags, true, LogLevel::Warning);
+ EXPECT_NE(selection, different_level);
+
+ tags[2] = PREFIX_LOG_TAG(gc);
+ tags[3] = PREFIX_LOG_TAG(_NO_TAG);
+ LogSelection more_tags(tags, true, LogLevel::Info);
+ EXPECT_NE(selection, more_tags);
+
+ tags[1] = PREFIX_LOG_TAG(_NO_TAG);
+ LogSelection fewer_tags(tags, true, LogLevel::Info);
+ EXPECT_NE(selection, fewer_tags);
+}
+
+TEST(LogSelection, describe_tags) {
+ char buf[256];
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, true, LogLevel::Off);
+ selection.describe_tags(buf, sizeof(buf));
+ EXPECT_STREQ("logging+test*", buf);
+}
+
+TEST(LogSelection, describe) {
+ char buf[256];
+ LogTagType tags[LogTag::MaxTags] = { PREFIX_LOG_TAG(logging), PREFIX_LOG_TAG(test), PREFIX_LOG_TAG(_NO_TAG) };
+ LogSelection selection(tags, true, LogLevel::Off);
+ selection.describe(buf, sizeof(buf));
+ EXPECT_STREQ("logging+test*=off", buf);
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/logging/test_logSelectionList.cpp Mon Feb 19 09:46:10 2018 +0100
@@ -0,0 +1,146 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "logging/logLevel.hpp"
+#include "logging/logSelectionList.hpp"
+#include "logging/logTagSet.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "logTestUtils.inline.hpp"
+#include "unittest.hpp"
+
+TEST(LogSelectionList, combination_limit) {
+ size_t max_combinations = LogSelectionList::MaxSelections;
+ EXPECT_GT(max_combinations, LogTagSet::ntagsets())
+ << "Combination limit not sufficient for configuring all available tag sets";
+}
+
+TEST(LogSelectionList, parse) {
+ char buf[256];
+ const char* valid_expression[] = {
+ "logging=off,all", "gc,logging", "logging+gc", "logging+gc,gc", "gc=trace,logging=info",
+ "logging+gc=trace,gc+logging=warning,logging", "gc,all=info"
+ };
+
+ // Verify valid expressions parse without problems
+ for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
+ LogSelectionList expr;
+ EXPECT_TRUE(expr.parse(valid_expression[i])) << "Valid expression '" << valid_expression[i] << "' did not parse";
+ }
+
+ // Verify invalid expressions do not parse
+ for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
+ for (size_t j = 0; j < ARRAY_SIZE(invalid_selection_substr); j++) {
+ // Prefix with invalid substr
+ LogSelectionList expr;
+ jio_snprintf(buf, sizeof(buf), "%s%s", invalid_selection_substr[j], valid_expression[i]);
+ EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ // Suffix with invalid substr
+ LogSelectionList expr1;
+ jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_selection_substr[j]);
+ EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ // Use only the invalid substr
+ LogSelectionList expr2;
+ EXPECT_FALSE(expr2.parse(invalid_selection_substr[j])) << "'" << invalid_selection_substr[j] << "'" << " considered legal";
+ }
+
+ // Suffix/prefix with some unique invalid prefixes/suffixes
+ LogSelectionList expr;
+ jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
+ EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
+
+ LogSelectionList expr1;
+ jio_snprintf(buf, sizeof(buf), "logging*%s", valid_expression[i]);
+ EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
+ }
+}
+
+// Test the level_for() function for an empty expression
+TEST(LogSelectionList, level_for_empty) {
+ LogSelectionList emptyexpr;
+ ASSERT_TRUE(emptyexpr.parse(""));
+ // All tagsets should be unspecified since the expression doesn't involve any tagset
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ EXPECT_EQ(LogLevel::Unspecified, emptyexpr.level_for(*ts));
+ }
+}
+
+// Test level_for() with an expression that has overlap (last subexpression should be used)
+TEST(LogSelectionList, level_for_overlap) {
+ LogSelectionList overlapexpr;
+ // The all=warning will be overridden with gc=info and/or logging+safepoint*=trace
+ ASSERT_TRUE(overlapexpr.parse("all=warning,gc=info,logging+safepoint*=trace"));
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ if (ts->contains(PREFIX_LOG_TAG(gc)) && ts->ntags() == 1) {
+ EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(*ts));
+ } else if (ts->contains(PREFIX_LOG_TAG(logging)) && ts->contains(PREFIX_LOG_TAG(safepoint))) {
+ EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(*ts));
+ } else {
+ EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(*ts));
+ }
+ }
+ EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
+ EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
+ EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset()));
+ EXPECT_EQ(LogLevel::Trace,
+ overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc, class, safepoint, heap)>::tagset()));
+}
+
+// Test level_for() with an expression containing two independent subexpressions
+TEST(LogSelectionList, level_for_disjoint) {
+ LogSelectionList reducedexpr;
+ ASSERT_TRUE(reducedexpr.parse("gc+logging=trace,class*=error"));
+ EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
+ EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint, class)>::tagset()));
+ EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
+ EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
+ EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
+ EXPECT_EQ(LogLevel::Trace, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
+}
+
+// Test level_for() with an expression that is completely overridden in the last part of the expression
+TEST(LogSelectionList, level_for_override) {
+ LogSelectionList overrideexpr;
+ // No matter what, everything should be set to error level because of the last part
+ ASSERT_TRUE(overrideexpr.parse("logging,gc*=trace,all=error"));
+ EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
+ EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
+ EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
+ EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
+}
+
+// Test level_for() with a mixed expression with a bit of everything
+TEST(LogSelectionList, level_for_mixed) {
+ LogSelectionList mixedexpr;
+ ASSERT_TRUE(mixedexpr.parse("all=warning,gc*=debug,gc=trace,safepoint*=off"));
+ EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
+ EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, class)>::tagset()));
+ EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, class)>::tagset()));
+ EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, safepoint, logging)>::tagset()));
+ EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
+ EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
+ EXPECT_EQ(LogLevel::Trace, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
+}
--- a/test/hotspot/gtest/logging/test_logTagLevelExpression.cpp Mon Feb 19 09:16:04 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "precompiled.hpp"
-#include "jvm.h"
-#include "logging/logLevel.hpp"
-#include "logging/logTagLevelExpression.hpp"
-#include "logging/logTagSet.hpp"
-#include "unittest.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-TEST(LogTagLevelExpression, combination_limit) {
- size_t max_combinations = LogTagLevelExpression::MaxCombinations;
- EXPECT_GT(max_combinations, LogTagSet::ntagsets())
- << "Combination limit not sufficient for configuring all available tag sets";
-}
-
-TEST(LogTagLevelExpression, parse) {
- char buf[256];
- const char* invalid_substr[] = {
- "=", "+", " ", "+=", "+=*", "*+", " +", "**", "++", ".", ",", ",," ",+",
- " *", "all+", "all*", "+all", "+all=Warning", "==Info", "=InfoWarning",
- "BadTag+", "logging++", "logging*+", ",=", "gc+gc+"
- };
- const char* valid_expression[] = {
- "all", "gc", "gc,logging", "gc+logging", "logging+gc", "logging+gc,gc", "logging+gc*", "gc=trace",
- "gc=trace,logging=info", "logging+gc=trace", "logging+gc=trace,gc+logging=warning,logging",
- "gc,all=info", "logging*", "logging*=info", "gc+logging*=error", "logging*,gc=info"
- };
-
- // Verify valid expressions parse without problems
- for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
- LogTagLevelExpression expr;
- EXPECT_TRUE(expr.parse(valid_expression[i])) << "Valid expression '" << valid_expression[i] << "' did not parse";
- }
-
- // Verify we can use 'all' with each available level
- for (uint level = LogLevel::First; level <= LogLevel::Last; level++) {
- char buf[32];
- int ret = jio_snprintf(buf, sizeof(buf), "all=%s", LogLevel::name(static_cast<LogLevelType>(level)));
- ASSERT_NE(ret, -1);
-
- LogTagLevelExpression expr;
- EXPECT_TRUE(expr.parse(buf));
- }
-
- // Verify invalid expressions do not parse
- for (size_t i = 0; i < ARRAY_SIZE(valid_expression); i++) {
- for (size_t j = 0; j < ARRAY_SIZE(invalid_substr); j++) {
- // Prefix with invalid substr
- LogTagLevelExpression expr;
- jio_snprintf(buf, sizeof(buf), "%s%s", invalid_substr[j], valid_expression[i]);
- EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
-
- // Suffix with invalid substr
- LogTagLevelExpression expr1;
- jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_substr[j]);
- EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
-
- // Use only the invalid substr
- LogTagLevelExpression expr2;
- EXPECT_FALSE(expr2.parse(invalid_substr[j])) << "'" << invalid_substr[j] << "'" << " considered legal";
- }
-
- // Suffix/prefix with some unique invalid prefixes/suffixes
- LogTagLevelExpression expr;
- jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
- EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
-
- LogTagLevelExpression expr1;
- jio_snprintf(buf, sizeof(buf), "logging*%s", valid_expression[i]);
- EXPECT_FALSE(expr1.parse(buf)) << "'" << buf << "'" << " considered legal";
- }
-}
-
-// Test the level_for() function for an empty expression
-TEST(LogTagLevelExpression, level_for_empty) {
- LogTagLevelExpression emptyexpr;
- ASSERT_TRUE(emptyexpr.parse(""));
- // All tagsets should be unspecified since the expression doesn't involve any tagset
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- EXPECT_EQ(LogLevel::Unspecified, emptyexpr.level_for(*ts));
- }
-}
-
-// Test level_for() with "all" without any specified level
-TEST(LogTagLevelExpression, level_for_all) {
- LogTagLevelExpression allexpr;
- ASSERT_TRUE(allexpr.parse("all"));
- // Level will be unspecified since no level was given
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- EXPECT_EQ(LogLevel::Unspecified, allexpr.level_for(*ts));
- }
-}
-
-// Test level_for() with "all=debug"
-TEST(LogTagLevelExpression, level_for_all_debug) {
- LogTagLevelExpression alldebugexpr;
- ASSERT_TRUE(alldebugexpr.parse("all=debug"));
- // All tagsets should report debug level
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- EXPECT_EQ(LogLevel::Debug, alldebugexpr.level_for(*ts));
- }
-}
-
-// Test level_for() with "all=off"
-TEST(LogTagLevelExpression, level_for_all_off) {
- LogTagLevelExpression alloffexpr;
- ASSERT_TRUE(alloffexpr.parse("all=off"));
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- EXPECT_EQ(LogLevel::Off, alloffexpr.level_for(*ts));
- }
-}
-
-// Test level_for() with an expression that has overlap (last subexpression should be used)
-TEST(LogTagLevelExpression, level_for_overlap) {
- LogTagLevelExpression overlapexpr;
- // The all=warning will be overridden with gc=info and/or logging+safepoint*=trace
- ASSERT_TRUE(overlapexpr.parse("all=warning,gc=info,logging+safepoint*=trace"));
- for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
- if (ts->contains(PREFIX_LOG_TAG(gc)) && ts->ntags() == 1) {
- EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(*ts));
- } else if (ts->contains(PREFIX_LOG_TAG(logging)) && ts->contains(PREFIX_LOG_TAG(safepoint))) {
- EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(*ts));
- } else {
- EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(*ts));
- }
- }
- EXPECT_EQ(LogLevel::Warning, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
- EXPECT_EQ(LogLevel::Info, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
- EXPECT_EQ(LogLevel::Trace, overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, safepoint)>::tagset()));
- EXPECT_EQ(LogLevel::Trace,
- overlapexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc, class, safepoint, heap)>::tagset()));
-}
-
-// Test level_for() with an expression containing two independent subexpressions
-TEST(LogTagLevelExpression, level_for_disjoint) {
- LogTagLevelExpression reducedexpr;
- ASSERT_TRUE(reducedexpr.parse("gc+logging=trace,class*=error"));
- EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
- EXPECT_EQ(LogLevel::Error, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint, class)>::tagset()));
- EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
- EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
- EXPECT_EQ(LogLevel::NotMentioned, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
- EXPECT_EQ(LogLevel::Trace, reducedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
-}
-
-// Test level_for() with an expression that is completely overridden in the last part of the expression
-TEST(LogTagLevelExpression, level_for_override) {
- LogTagLevelExpression overrideexpr;
- // No matter what, everything should be set to error level because of the last part
- ASSERT_TRUE(overrideexpr.parse("logging,gc*=trace,all=error"));
- EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(class)>::tagset()));
- EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
- EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
- EXPECT_EQ(LogLevel::Error, overrideexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
-}
-
-// Test level_for() with a mixed expression with a bit of everything
-TEST(LogTagLevelExpression, level_for_mixed) {
- LogTagLevelExpression mixedexpr;
- ASSERT_TRUE(mixedexpr.parse("all=warning,gc*=debug,gc=trace,safepoint*=off"));
- EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging)>::tagset()));
- EXPECT_EQ(LogLevel::Warning, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, class)>::tagset()));
- EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, class)>::tagset()));
- EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc, safepoint, logging)>::tagset()));
- EXPECT_EQ(LogLevel::Off, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(safepoint)>::tagset()));
- EXPECT_EQ(LogLevel::Debug, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(logging, gc)>::tagset()));
- EXPECT_EQ(LogLevel::Trace, mixedexpr.level_for(LogTagSetMapping<LOG_TAGS(gc)>::tagset()));
-}