/* * Copyright (c) 2001, 2022, 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.
*/
/** * This class helps to print test-execution trace messages * and filter them when execution mode is not verbose. * <p> * Verbose mode if defined by providing <i>-verbose</i> command line * option, handled by <code>ArgumentParser</code>. Use <code>verbose()</code> * method to determine which mode is used. * <p> * <code>Log</code> provides with two main methods to print messages: * <ul> * <li> <code>complain(String)</code> - to print error message * <li> <code>display(String)</code> - to print additional log message * </ul> * No other way to print messages to the log stream should be used. * <p> * Error messages appeares in log stream in all modes. Additional log massages, * printed with <code>display()</code> method will be filtered out, if log mode * is not verbose. In verbose log made messages of both types are printed. * Additionally, in verbose mode a summary of all occured errors will be printed * at the program exit, by automatically invoking method * <code>printErrorsSummary()</code>. * <p> * To provide printing messages from different sources into one log * with distinct prefixes use internal <code>Log.Logger</code> class. * * @see #verbose() * @see #complain(String) * @see #display(String) * @see ArgumentParser * @see Log.Logger
*/ publicclass Log extends FinalizableObject { /** * Report step-by-step activity to this stream. * * @deprecated Tests should not use this field directly.
*/
@Deprecated protected PrintStream out = null;
/** * Is log-mode verbose? * Default value is <code>false</code>.
*/ privateboolean verbose = false;
/** * Should log messages prefixed with timestamps? * Default value is <code>false</code>.
*/ privateboolean timestamp = false;
publicstatic String getLevelsString() {
StringBuffer result = new StringBuffer(); for ( String s : NAME_TO_LEVEL_MAP.keySet() ) {
result.append(s).append(", ");
} return result.substring(0, result.length() - 3);
}
}
/** * Threshold value for printing trace messages for debugging purpose. * Default value is <code>0</code> a.k.a. <code>TraceLevel.INFO</code>;
*/ privateint traceLevel = TraceLevel.DEFAULT;
/** * Is printing errors summary enabled? Default value is <code>true</code>;
*/ privateboolean errorsSummaryEnabled = true;
/** * Is printing saved verbose messages on error enabled? Default value is <code>true</code>;
*/ privateboolean verboseOnErrorEnabled = true;
/** * This <code>errosBuffer</code> will keep all messages printed via * <code>complain()</code> method for final summary output. * Ensure that buffer has enough room for messages to keep, * to minimize probability or OutOfMemory error while keeping * an error message in stress tests.
*/ private Vector<String> errorsBuffer = new Vector<String>(1000);
/** * Most tests in nsk do not log exceptions, they only log an error message. * This makes failure analysis harder. * To solve this we will automatically generate Exceptions for error logs. * To not log too many Exceptions, we try to log each unique error only once. * <code>loggedExceptions</code> contains all messages that have already been logged.
*/ private Set<String> loggedExceptions = new HashSet<String>();
/** * This <code>logBuffer</code> will keep all messages printed via * <code>display()</code> method in non-verbose mode until * swithching verbose mode on or invoking <code>complain()</code>. * Ensure that buffer has enough room for messages to keep, * to minimize probability or OutOfMemory error while keeping * an error message in stress tests.
*/ private Vector<String> logBuffer = new Vector<String>(1000);
/** * Did I already warned if output stream is not assigned?
*/ privateboolean noOutWarned = false;
/** * Create new Log's only with <code>Log(out)</code> or with * <code>Log(out,argsHandler)</code> constructors. * * @deprecated Extending test class with Log is obsolete.
*/
@Deprecated protected Log() { // install finalizer to print errors summary at exit
Finalizer finalizer = new Finalizer(this);
finalizer.activate();
// Don't log exceptions from this method. It would just add unnecessary logs.
loggedExceptions.add("nsk.share.jdi.SerialExecutionDebugger.executeTests");
}
/** * Incarnate new Log for the given <code>stream</code> and * for non-verbose mode.
*/ public Log(PrintStream stream) { this();
out = stream;
}
/** * Incarnate new Log for the given <code>stream</code>; and * either for verbose or for non-verbose mode accordingly to * the given <code>verbose</code> key.
*/ public Log(PrintStream stream, boolean verbose) { this(stream); this.verbose = verbose;
}
/** * Incarnate new Log for the given <code>stream</code>; and * either for verbose or for non-verbose mode accordingly to * the given <code>argsHandler</code>.
*/ public Log(PrintStream stream, ArgumentParser argsParser) { this(stream, argsParser.verbose());
traceLevel = argsParser.getTraceLevel();
timestamp = argsParser.isTimestamp();
}
/** * Return <i>true</i> if log mode is verbose.
*/ publicboolean verbose() { return verbose;
}
/** * Return <i>true</i> if printing errors summary at exit is enabled.
*/ publicboolean isErrorsSummaryEnabled() { return errorsSummaryEnabled;
}
/** * Enable or disable printing errors summary at exit.
*/ publicvoid enableErrorsSummary(boolean enable) {
errorsSummaryEnabled = enable;
}
/** * Return <i>true</i> if printing saved verbose messages on error is enabled.
*/ publicboolean isVerboseOnErrorEnabled() { return errorsSummaryEnabled;
}
/** * Enable or disable printing saved verbose messages on error.
*/ publicvoid enableVerboseOnError(boolean enable) {
verboseOnErrorEnabled = enable;
}
/** * Enable or disable verbose mode for printing messages.
*/ publicvoid enableVerbose(boolean enable) { if (!verbose) {
flushLogBuffer();
}
verbose = enable;
}
publicint getTraceLevel() { return traceLevel;
}
/** * Set threshold for printing trace messages. * Warning: trace level changes may NOT be observed by other threads immediately.
*/ publicvoid setTraceLevel(int level) {
traceLevel = level;
}
/** * Return output stream of this <code>Log</code> object.
*/ public PrintStream getOutStream() { return out;
}
/** * Returns a string that contains prefix concatenated * with Throwable.printStackTrace() output.
*/ publicstatic String printExceptionToString(Object prefix, Throwable exception) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(bos);
pw.println(prefix);
exception.printStackTrace(pw);
pw.close(); return bos.toString();
}
/** * Print <code>message</code> to the assigned output stream. * * @deprecated Test ought to be quiet if log mode is non-verbose * and there is no errors found by the test. Methods * <code>display()</code> and <code>complain()</code> * are enough for testing purposes.
*/
@Deprecated publicsynchronizedvoid println(String message) {
doPrint(message); if (!verbose() && isVerboseOnErrorEnabled()) {
keepLog(composeLine(message));
}
}
/** * Print <code>message</code> to the assigned output stream, * if log mode is <i>non</i>-verbose. * * @deprecated Test ought to be quiet if log mode is non-verbose * and there is no errors found by the test. Methods * <code>display()</code> and <code>complain()</code> * are enough for testing purposes.
*/
@Deprecated publicsynchronizedvoid comment(String message) { if (!verbose()) {
doPrint(message);
}
}
/** * Print trace <code>message</code> to the assigned output stream, * only if specified <code>level</code> is less or equal for the * trace level specified in command line by <code>-trace.level</code> * option.
*/ publicvoid trace(int level, Object message) { if (level <= traceLevel) { synchronized ( this ) {
doPrint("### TRACE " + level + ": " + message);
}
}
} /** * Print trace <code>message</code> and <code>exception</code> to * the assigned output stream, * only if specified <code>level</code> is less or equal for the * trace level specified in command line by <code>-trace.level</code> * option.
*/ publicvoid trace(int level, Object message, Throwable exception) { if (level <= traceLevel) {
trace(level, printExceptionToString(message, exception));
}
}
/** * Print <code>message</code> to the assigned output stream, * if log mode is verbose. The <code>message</code> will be lost, * if execution mode is non-verbose, and there is no error messages * printed.
*/ publicsynchronizedvoid display(Object message) { if (verbose()) {
doPrint(message.toString());
} elseif (isVerboseOnErrorEnabled()) {
keepLog(composeLine(message.toString()));
} else { // ignore
}
}
/** * Print error <code>message</code> to the assigned output stream * (or to stderr if output is not specified) and keep the message * into <code>errorsBuffer</code>.
*/ publicsynchronizedvoid complain(Object message) { if (!verbose() && isVerboseOnErrorEnabled()) {
PrintStream stream = findOutStream();
stream.println("#> ");
stream.println("#> WARNING: switching log to verbose mode,");
stream.println("#> because error is complained");
stream.println("#> ");
stream.flush();
enableVerbose(true);
}
String msgStr = message.toString();
printError(msgStr); if (isErrorsSummaryEnabled()) {
keepError(msgStr);
}
logExceptionForFailureAnalysis(msgStr);
}
/** * Print error <code>message</code> and <code>exception</code> * to the assigned output stream * (or to stderr if output is not specified) and keep the message * into <code>errorsBuffer</code>.
*/ publicvoid complain(Object message, Throwable exception) { if ( exception != null )
complain(printExceptionToString(message, exception)); else
complain(message);
}
/** * Create an Exception and print the stack trace for an error msg. * This makes it possible to detect a failure reason for this error.
*/ privatevoid logExceptionForFailureAnalysis(String msg) { // Some error messages are formatted in multiple lines and with tabs. // We clean the messages to help parse the stack traces for failure analysis. // We keep at most 2 lines, otherwise the error message may be too long.
String[] lines = msg.split("[\r\n]+");
msg = lines.length >= 2 ? lines[0] + " " + lines[1] : lines[0];
msg = msg.replaceAll("\t", " ");
// Create a dummy exception just so we can print the stack trace.
TestFailure e = new TestFailure(msg);
StackTraceElement[] elements = e.getStackTrace();
// Only log the first complain message from each function. // The reason is that some functions splits an error message // into multiple lines and call complain() many times. // We do not want a RULE for each of those calls. // This means that we may miss some rules, but that // is better than to create far too many rules.
String callerClass = elements[callerIndex].getClassName();
String callerMethod = elements[callerIndex].getMethodName();
String callerKey = callerClass + "." + callerMethod; boolean isAlreadyLogged = loggedExceptions.contains(msg) || loggedExceptions.contains(callerKey);
if (!isAlreadyLogged) {
PrintStream stream = findOutStream();
stream.println("The following stacktrace is for failure analysis.");
e.printStackTrace(stream);
}
/** * Redirect log to the given <code>stream</code>, and switch * log mode to verbose. * Prints errors summary to current stream, cancel current stream * and switches to new stream. Turns on verbose mode for new stream. * * @deprecated This method is obsolete.
*/
@Deprecated protectedsynchronizedvoid logTo(PrintStream stream) {
finalize(); // flush older log stream
out = stream;
verbose = true;
}
/** * Clear all messages from log buffer.
*/ publicsynchronizedvoid clearLogBuffer() {
logBuffer.clear();
}
/** * Print all messages from log buffer which were hidden because * of non-verbose mode,
*/ privatesynchronizedvoid flushLogBuffer() { if (!logBuffer.isEmpty()) {
PrintStream stream = findOutStream(); for (int i = 0; i < logBuffer.size(); i++) {
stream.println(logBuffer.elementAt(i));
}
stream.flush();
}
}
/** * Return <code>out</code> stream if defined or <code>Sytem.err<code> otherwise; * print a warning message when <code>System.err</code> is used first time.
*/ privatesynchronized PrintStream findOutStream() {
PrintStream stream = out; if (stream == null) {
stream = System.err; if (!noOutWarned) {
noOutWarned = true;
stream.println("#> ");
stream.println("#> WARNING: switching log stream to stderr,");
stream.println("#> because no output stream is assigned");
stream.println("#> ");
};
};
stream.flush(); return stream;
}
/** * Compose line to print possible prefixing it with timestamp.
*/ private String composeLine(String message) { if (timestamp) { long time = System.currentTimeMillis(); long ms = time % 1000;
time /= 1000; long secs = time % 60;
time /= 60; long mins = time % 60;
time /= 60; long hours = time % 24; return"[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message;
} return message;
}
/** * Print the given <code>message</code> either to <code>out</code> * stream, or to <code>System.err</code> if <code>out</code> * stream is not specified.
*/ privatesynchronizedvoid doPrint(String message) {
PrintStream stream = findOutStream();
stream.println(composeLine(message));
stream.flush();
}
/** * Print the given error <code>message</code> either to <code>out</code> * stream, or to <code>System.err</code> if <code>out</code> * stream is not specified.
*/ privatesynchronizedvoid printError(String message) { // Print each line with the ERROR prefix:
BufferedReader br = new BufferedReader(new StringReader(message)); for (String line; ; ) { try {
line = br.readLine(); if (line == null) break;
doPrint("# ERROR: " + line);
} catch (IOException e) { thrownew TestBug("Exception in Log.printError(): " + e);
};
}
}
/** * Keep the given log <code>message</code> into <code>logBuffer</code>.
*/ privatesynchronizedvoid keepLog(String message) {
logBuffer.addElement(message);
}
/** * Keep the given error <code>message</code> into <code>errorsBuffer</code>.
*/ privatesynchronizedvoid keepError(String message) {
errorsBuffer.addElement(message);
}
/** * Print errors messages summary from errors buffer if any; * print a warning message first.
*/ privatesynchronizedvoid printErrorsSummary() { if (errorsBuffer.size() <= 0) return;
PrintStream stream = findOutStream();
stream.println();
stream.println();
stream.println("#> ");
stream.println("#> SUMMARY: Following errors occured");
stream.println("#> during test execution:");
stream.println("#> ");
stream.flush();
for (Enumeration e = errorsBuffer.elements(); e.hasMoreElements(); ) {
printError((String) e.nextElement());
}
}
/** * Print errors summary if mode is verbose, flush and cancel output stream.
*/ protectedvoid finalize() { if (verbose() && isErrorsSummaryEnabled()) {
printErrorsSummary();
} if (out != null)
out.flush();
out = null;
}
/** * Perform finalization at the exit.
*/ publicvoid finalizeAtExit() {
finalize();
}
/** * This class can be used as a base for each class that use <code>Log</code> * for print messages and errors. * <code>Logger</code> provides with ability to print such messages with * specified prefix to make it possible to distinct messages printed from * different sources. * * @see Log
*/ publicstaticclass Logger {
/** * Make <code>Logger</code> object with empty <code>Log</code> and * default prefix. * This method may be used only in derived class, that should specify * the used <code>Log</code> object further and assign it to <code>log</code>. * * @see #log * @see #setLogPrefix
*/ protected Logger() {
}
/** * Make <code>Logger</code> object for specified <code>Log</code> * with default prefix. * * @see #setLogPrefix
*/ public Logger(Log log) { this.log = log;
}
/** * Make <code>Logger</code> object for specified <code>Log</code> with * given messages prefix.
*/ public Logger(Log log, String prefix) { this.log = log; this.logPrefix = prefix;
}
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 und die Messung sind noch experimentell.