/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.tools;
import com.rapidminer.RapidMiner;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* <p>
* Utility class providing static methods for logging.<br>
* Parameters read from the XML process configuration file:
* </p>
* <ul>
* <li>logfile (filename or "stdout" or "stderr")</li>
* <li>logverbosity (possible values are in {@link LogService#LOG_VERBOSITY_NAMES}</li>
* </ul>
*
* <p>
* Beside the <b>local</b> log service associated with a concrete process and which will be
* automatically initialized during the setup phase, one <b>global</b> log service exist which is
* used for generic log messages not bound to the operators used in a process. This global log
* service is usually initialized to log messages on system out (at least during the basic
* initialization phase of RapidMiner). After the basic intialization phase, the global messages
* will be presented in the message viewer (if the RapidMiner GUI is used) or still printed to
* system out or in any other stream defined via the method
* {@link #initGlobalLogging(OutputStream, int)}. Alternatively, one could also define an
* environment variable named {@link RapidMiner#PROPERTY_RAPIDMINER_GLOBAL_LOG_FILE}.
* </p>
*
* <p>
* Usually, operators should only use the log verbosities MINIMUM for messages with a low priority
* and STATUS for normal information messages. In rare cases, the verbosity level NOTE could be used
* for operators stating some message more important then STATUS (hence the user should see the
* message for the default log verbosity level of INIT) but not as important then WARNING. The
* verbosity levels WARNING, EXCEPTION, and ERROR should be used in error cases. All other log
* verbosity levels should only be used by internal RapidMiner classes and not by user written
* operators.
* </p>
*
* <p>
* We recommend to set the parameter for the log verbosity level to INIT for the process design
* phase (eventually STATUS for debugging) and to the log verbosity level WARNING in the production
* phase. This way it is ensured that not too many logging messages are produced in the production
* phase.
* </p>
*
* <p>
* Log messages can be formatted by using the following macros:
* </p>
* <ul>
* <li>"$b" and "^b" start and end bold mode respectively</li>
* <li>"$i" and "^i" start and end italic mode respectively</li>
* <li>"$m" and "^m" start and end monospace mode respectively</li>
* <li>"$n" and "^n" start and end note color mode respectively</li>
* <li>"$w" and "^w" start and end warning color mode respectively</li>
* <li>"$e" and "^e" start and end error color mode respectively</li>
* </ul>
*
* @author Ingo Mierswa
*/
public class LogService extends WrapperLoggingHandler {
// -------------------- Verbosity Level --------------------
/** Indicates an unknown verbosity level. */
public static final int UNKNOWN_LEVEL = -1;
/**
* Indicates the lowest log verbosity. Should only be used for very detailed but not necessary
* logging.
*/
public static final int MINIMUM = 0;
/**
* Indicates log messages concerning in- and output. Should only be used by the class Operator
* itself and not by its subclasses.
*/
public static final int IO = 1;
/** The default log verbosity for all logging purposes of operators. */
public static final int STATUS = 2;
/**
* Only the most important logging messaged should use this log verbosity. Currently used only
* by the LogService itself.
*/
public static final int INIT = 3;
/**
* Use this log verbosity for logging of important notes, i.e. things less important than
* warnings but important enough to see for all not interested in the detailed status messages.
*/
public static final int NOTE = 4;
/** Use this log verbosity for logging of warnings. */
public static final int WARNING = 5;
/** Use this log verbosity for logging of errors. */
public static final int ERROR = 6;
/**
* Use this log verbosity for logging of fatal errors which will stop process running somewhere
* in the future.
*/
public static final int FATAL = 7;
/**
* Normally this log verbosity should not be used by operators. Messages with this verbosity
* will always be displayed.
*/
public static final int MAXIMUM = 8;
/** For switching off logging during testing. */
public static final int OFF = 9;
public static final String LOG_VERBOSITY_NAMES[] = { "all", "io", "status", "init", "notes", "warning", "error",
"fatal", "almost_none", "off" };
/** The prefix used to indicate the global logger. */
public static final String GLOBAL_PREFIX = "$gG^g";
private static final Logger GLOBAL_LOGGER = Logger.getLogger("com.rapidminer",
"com.rapidminer.resources.i18n.LogMessages");
private static final LogService GLOBAL_LOGGING = new LogService(GLOBAL_LOGGER);
// ------ methods for init -------
private LogService(Logger logger) {
super(logger);
// setup a log file if the execution mode can access the filesystem (e.g. not for RA)
// we want our logfile to look the same regardless of any user settings, so ignore
// a possible user logging property config file
if (RapidMiner.getExecutionMode().canAccessFilesystem()) {
try {
FileHandler logFileHandler = new FileHandler(FileSystemService.getLogFile().getAbsolutePath(), false);
logFileHandler.setLevel(Level.ALL);
logFileHandler.setFormatter(new SimpleFormatter());
LogService.getRoot().addHandler(logFileHandler);
} catch (IOException e) {
LogService.getRoot().log(Level.WARNING, "com.rapidminer.logservice.logfile.failed_to_init", e.getMessage());
}
}
}
/**
* Returns the global logging. If no logging was otherwise create, this method creates the
* default standard out log service if no log file was defined in the property
* {@link RapidMiner#PROPERTY_RAPIDMINER_GLOBAL_LOG_FILE}. Alternatively, developers can invoke
* the method {@link #initGlobalLogging(OutputStream, int)}.
*
* @deprecated use {@link #getRoot()} instead
*/
@Deprecated
public static LogService getGlobal() {
return GLOBAL_LOGGING;
}
public static Logger getRoot() {
return GLOBAL_LOGGER;
}
// private void addConsole(Level level) {
// StreamHandler handler = new ConsoleHandler();
// handler.setLevel(Level.ALL);
// getRoot().setLevel(level);
// getRoot().addHandler(handler);
// }
public void setVerbosityLevel(int level) {
getRoot().setLevel(LEVELS[level]);
}
/**
* The methods in {@link Logger} do not provide a means to pass an exception AND I18N arguments,
* so this method provides a shortcut for this.
*/
public static void log(Logger logger, Level level, Throwable exception, String i18NKey, Object... arguments) {
logger.log(level, I18N.getMessage(logger.getResourceBundle(), i18NKey, arguments), exception);
}
/**
* @deprecated Use {@link Logger#isLoggable(Level)}
*/
@Deprecated
public boolean isSufficientLogVerbosity(int level) {
return GLOBAL_LOGGER.isLoggable(LEVELS[level]);
}
// -------------------- Methoden zum Protokollieren --------------------
/**
* Writes the message to the output stream if the verbosity level is high enough.
*
* @deprecated please do not use this log method any longer, use the method
* {@link #log(String, int)} instead
*/
@Deprecated
public static void logMessage(String message, int verbosityLevel) {
getGlobal().log(message, verbosityLevel);
}
}