8196783: Refactor LogTagLevelExpression into separate classes
Reviewed-by: rehn, pliden
This commit is contained in:
parent
8cf755c120
commit
29dd30e010
@ -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 @@ void LogConfiguration::delete_output(size_t idx) {
|
||||
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 @@ void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression&
|
||||
|
||||
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::disable_logging() {
|
||||
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 @@ void LogConfiguration::configure_stdout(LogLevelType level, int exact_match, ...
|
||||
"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_command_line_arguments(const char* opts) {
|
||||
}
|
||||
|
||||
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 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr,
|
||||
outputstr = "stdout";
|
||||
}
|
||||
|
||||
LogTagLevelExpression expr;
|
||||
if (!expr.parse(what, errstream)) {
|
||||
LogSelectionList selections;
|
||||
if (!selections.parse(selectionstr, errstream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -433,9 +430,9 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 @@ class LogConfiguration : public AllStatic {
|
||||
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();
|
||||
|
202
src/hotspot/share/logging/logSelection.cpp
Normal file
202
src/hotspot/share/logging/logSelection.cpp
Normal file
@ -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;
|
||||
}
|
67
src/hotspot/share/logging/logSelection.hpp
Normal file
67
src/hotspot/share/logging/logSelection.hpp
Normal file
@ -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
|
103
src/hotspot/share/logging/logSelectionList.cpp
Normal file
103
src/hotspot/share/logging/logSelectionList.cpp
Normal file
@ -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;
|
||||
}
|
65
src/hotspot/share/logging/logSelectionList.hpp
Normal file
65
src/hotspot/share/logging/logSelectionList.hpp
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
203
test/hotspot/gtest/logging/test_logSelection.cpp
Normal file
203
test/hotspot/gtest/logging/test_logSelection.cpp
Normal file
@ -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
|
@ -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
|
||||
@ -24,78 +24,63 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logTagLevelExpression.hpp"
|
||||
#include "logging/logSelectionList.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "unittest.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(LogTagLevelExpression, combination_limit) {
|
||||
size_t max_combinations = LogTagLevelExpression::MaxCombinations;
|
||||
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(LogTagLevelExpression, parse) {
|
||||
TEST(LogSelectionList, 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"
|
||||
"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++) {
|
||||
LogTagLevelExpression expr;
|
||||
LogSelectionList 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++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(invalid_selection_substr); j++) {
|
||||
// Prefix with invalid substr
|
||||
LogTagLevelExpression expr;
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s", invalid_substr[j], valid_expression[i]);
|
||||
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
|
||||
LogTagLevelExpression expr1;
|
||||
jio_snprintf(buf, sizeof(buf), "%s%s", valid_expression[i], invalid_substr[j]);
|
||||
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
|
||||
LogTagLevelExpression expr2;
|
||||
EXPECT_FALSE(expr2.parse(invalid_substr[j])) << "'" << invalid_substr[j] << "'" << " considered legal";
|
||||
LogSelectionList expr2;
|
||||
EXPECT_FALSE(expr2.parse(invalid_selection_substr[j])) << "'" << invalid_selection_substr[j] << "'" << " considered legal";
|
||||
}
|
||||
|
||||
// Suffix/prefix with some unique invalid prefixes/suffixes
|
||||
LogTagLevelExpression expr;
|
||||
LogSelectionList expr;
|
||||
jio_snprintf(buf, sizeof(buf), "*%s", valid_expression[i]);
|
||||
EXPECT_FALSE(expr.parse(buf)) << "'" << buf << "'" << " considered legal";
|
||||
|
||||
LogTagLevelExpression expr1;
|
||||
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(LogTagLevelExpression, level_for_empty) {
|
||||
LogTagLevelExpression emptyexpr;
|
||||
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()) {
|
||||
@ -103,38 +88,9 @@ TEST(LogTagLevelExpression, level_for_empty) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
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()) {
|
||||
@ -154,8 +110,8 @@ TEST(LogTagLevelExpression, level_for_overlap) {
|
||||
}
|
||||
|
||||
// Test level_for() with an expression containing two independent subexpressions
|
||||
TEST(LogTagLevelExpression, level_for_disjoint) {
|
||||
LogTagLevelExpression reducedexpr;
|
||||
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()));
|
||||
@ -166,8 +122,8 @@ TEST(LogTagLevelExpression, level_for_disjoint) {
|
||||
}
|
||||
|
||||
// Test level_for() with an expression that is completely overridden in the last part of the expression
|
||||
TEST(LogTagLevelExpression, level_for_override) {
|
||||
LogTagLevelExpression overrideexpr;
|
||||
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()));
|
||||
@ -177,8 +133,8 @@ TEST(LogTagLevelExpression, level_for_override) {
|
||||
}
|
||||
|
||||
// Test level_for() with a mixed expression with a bit of everything
|
||||
TEST(LogTagLevelExpression, level_for_mixed) {
|
||||
LogTagLevelExpression mixedexpr;
|
||||
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()));
|
Loading…
x
Reference in New Issue
Block a user