/* * Copyright (c) 2018, 2021, 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_io.h" #include"logging/log.hpp" #include"logging/logSelection.hpp" #include"logging/logTagSet.hpp" #include"runtime/os.hpp" #include"utilities/globalDefinitions.hpp" #include"utilities/ostream.hpp" #include"utilities/quickSort.hpp"
// 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("Invalid tag '%s' in log selection.", cur_tag);
LogTagType match = LogTag::fuzzy_match(cur_tag); if (match != LogTag::__NO_TAG) {
errstream->print(" Did you mean '%s'?", LogTag::name(match));
}
errstream->cr();
} 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;
}
}
}
double LogSelection::similarity(const LogSelection& other) const { // Compute Soerensen-Dice coefficient as the similarity measure
size_t intersecting = 0; for (size_t i = 0; i < _ntags; i++) { for (size_t j = 0; j < other._ntags; j++) { if (_tags[i] == other._tags[j]) {
intersecting++; break;
}
}
} return 2.0 * intersecting / (_ntags + other._ntags);
}
// Comparator used for sorting LogSelections based on their similarity to a specific LogSelection. // A negative return value means that 'a' is more similar to 'ref' than 'b' is, while a positive // return value means that 'b' is more similar. // For the sake of giving short and effective suggestions, when two selections have an equal // similarity score, the selection with the fewer tags (selecting the most tag sets) is considered // more similar. class SimilarityComparator { const LogSelection& _ref; public:
SimilarityComparator(const LogSelection& ref) : _ref(ref) {
} intoperator()(const LogSelection& a, const LogSelection& b) const { constdouble epsilon = 1.0e-6;
// Sort by similarity (descending) double s = _ref.similarity(b) - _ref.similarity(a); if (fabs(s) > epsilon) { return s < 0 ? -1 : 1;
}
// Then by number of tags (ascending) int t = static_cast<int>(a.ntags() - (int)b.ntags()); if (t != 0) { return t;
}
// Lastly by tag sets selected (descending) returnstatic_cast<int>(b.tag_sets_selected() - a.tag_sets_selected());
}
};
// See if simply adding a wildcard would make the selection match if (!_wildcard) {
LogSelection sel(_tags, true, _level); if (sel.tag_sets_selected() > 0) {
suggestions[nsuggestions++] = sel;
}
}
// Check for matching tag sets with a single tag mismatching (a tag too many or short a tag) for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG }; for (size_t i = 0; i < ts->ntags(); i++) {
tags[i] = ts->tag(i);
}
// Suggest wildcard selection unless the wildcard doesn't match anything extra
LogSelection sel(tags, true, _level); if (sel.tag_sets_selected() == 1) {
sel = LogSelection(tags, false, _level);
}
double score = similarity(sel);
// Ignore suggestions with too low similarity if (score < similarity_requirement) { continue;
}
// Cap not reached, simply add the new suggestion and continue searching if (nsuggestions < suggestion_cap) {
suggestions[nsuggestions++] = sel; continue;
}
// Find the least matching suggestion already found, and if the new suggestion is a better match, replace it double min = 1.0;
size_t pos = -1; for (size_t i = 0; i < nsuggestions; i++) { double score = similarity(suggestions[i]); if (score < min) {
min = score;
pos = i;
}
} if (score > min) {
suggestions[pos] = sel;
}
}
if (nsuggestions == 0) { // Found no similar enough selections to suggest. return;
}
// Sort found suggestions to suggest the best one first
SimilarityComparator sc(*this);
QuickSort::sort(suggestions, nsuggestions, sc, false);
out->print("Did you mean any of the following?"); for (size_t i = 0; i < nsuggestions; i++) {
out->print(" ");
suggestions[i].describe_tags_on(out);
}
}
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.