/*
* Created on 17.05.2005 for PIROL
*
* SVN header information:
* $Author: michaudm $
* $Rev: 2259 $
* $Date: 2011-05-08 12:47:24 +0200 (So, 08. Mai 2011) $
* $Id: GenericDebugLogger.java 2259 2011-05-08 10:47:24Z michaudm $
*/
package de.fho.jump.pirol.utilities.debugOutput;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Calendar;
import org.openjump.io.PropertiesHandler;
import de.fho.jump.pirol.utilities.settings.PirolPlugInSettings;
/**
* Class to handle debugging outputs. It is a singleton and keeps track of local debug settings and personal log levels.
* Configuration changes should not be done at runtime, but in the properties file ("debugging.properties") in the
* "[HOME]/.OpenJump_PIROL/config" directory. This file will be created when the logger is used the first time and filled
* with default values. For information on these values, please see commenting in the java source code.
*
* @author Ole Rahn, Stefan Ostermann
* <br>
* <br>FH Osnabrück - University of Applied Sciences Osnabrück,
* <br>Project: PIROL (2005),
* <br>Subproject: Daten- und Wissensmanagement
*
* @version $Rev: 2259 $
*
* @see de.fho.jump.pirol.utilities.settings.PirolPlugInSettings
* @see PersonalLogger
*/
public final class GenericDebugLogger {
private static GenericDebugLogger logger = null;
/**
* user Id for the logger object -> messages from this user are always displayed
*/
private final static String loggerUserId = "GenericDebugLogger";
/**
* Prefix for the username to store/read from the properties file
*/
private final static String userFlagPrefix = "showMessagesOf_";
protected PropertiesHandler properties = null;
protected static final String propertiesFile = "debugging.properties";
// default values: only the most important messages will be put out
/**
* The logLevel specifies which kinds of messages will be put out. A message will
* be put out, if its severity is greater or equal to the log level (or if the user's
* log messages are enabled)
* <pre>
* logLevel severity sheme:
* 0 - debug - just an output for debugging purposes
* 1 - warning - something that might not be good happened
* 2 - minor error - an error that won't have influence on the results occured
* 3 - error - an error that may invalidate the current results occured
* 4 - severe error - an error that may invalidate the current and future results or may crash the VM, etc.
* </pre>
*/
protected int logLevel = 1; // errors with effect on the results, only //sstein: set from 3 to 1
protected final static String KEY_LOGLEVEL = "logLevel";
/**Constant {@link #logLevel} for debugging purposes.*/
public final static int SEVERITY_DEBUG = 0;
/**Constant {@link #logLevel} for something that might not be good
* happened.*/
public final static int SEVERITY_WARNING = 1;
/**Constant {@link #logLevel} for an error that won't have influence on
* the results occured.*/
public final static int SEVERITY_MINORERROR = 2;
/**Constant {@link #logLevel} for an error that may invalidate the
* current results occured.*/
public final static int SEVERITY_ERROR = 3;
/**Constant {@link #logLevel} for an error that may invalidate the
* current and future results or may crash the VM, etc..*/
public final static int SEVERITY_SEVEREERROR = 4;
protected final static String[] severityLevels = new String[]{"DEBUG", "WARNING", "MIN.ERROR", "ERROR", "SEV.ERROR"};
/**
* format the output string so that eclipse supports jumping into the
* correct file and line number when clicking on the output.
*/
protected boolean eclipseFriendlyOutput = true;
protected final static String KEY_ECLIPSEFRIENDLYOUTPUT = "eclipseFriendlyOutput";
/**
* wether or not to print time stamps in the messages
*/
protected boolean printTimeStamp = false;
protected final static String KEY_PRINTTIMESTAMPS = "printTimeStamps";
/**
* wether or not to print file name and line number in code
*/
protected boolean printFileAndLine = true;
protected final static String KEY_PRINTFILEANDLINE = "printFileAndLineNumber";
/**
* print additional line break before output of new messages?
*/
protected boolean printNewLineFirst = false;
protected final static String KEY_PRINTNEWLINEFIRST = "printNewLineFirst";
/**
* print short class names instead of class name plus the whole package path?
*/
protected boolean printShortClassNames = true;
protected final static String KEY_PRINTSHORTCLASSNAMES = "printShortClassNames";
/**
* print user names with every message?
*/
protected boolean printUserNames = false;
protected final static String KEY_PRINTUSERNAMES = "printUserNames";
protected PrintStream stdOut;
protected PrintStream stdErr;
protected File logFile = null;
/**
* use a log file instead of printing messages to the console?
*/
protected boolean useLogFile = true;
protected final static String KEY_USELOGFILE = "useLogFile";
/**
* constructor is private, since we use the singleton pattern.
*/
private GenericDebugLogger(){
this.setOutputStream( System.out );
this.setErrorStream( System.err );
try {
this.loadProperties();
} catch (FileNotFoundException e) {
this.printMinorError(GenericDebugLogger.loggerUserId,e.getMessage());
} catch (IOException e) {
this.printMinorError(GenericDebugLogger.loggerUserId, e.getMessage());
}
if (this.useLogFile){
this.logFile = new File(PirolPlugInSettings.tempDirectory().getPath() + File.separator + "session.log" );
FileOutputStream fos = null;
try {
if (!logFile.exists()){
try {
logFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
fos = new FileOutputStream(logFile);
PrintStream logFileStream = new PrintStream(fos);
this.setOutputStream( logFileStream );
this.setErrorStream( logFileStream );
} catch (FileNotFoundException e) {
this.printWarning(GenericDebugLogger.loggerUserId, "Problems using a log file: " + e.getMessage());
}
}
}
/**
* load local configuration file, to check if there are saved directorties for
* debugging outputs.
* @throws IOException if the file with the given file name could not be accessed
*/
protected final void loadProperties() throws IOException{
this.properties = new PropertiesHandler(GenericDebugLogger.propertiesFile);
this.properties.load();
this.logLevel = this.properties.getPropertyAsInt(GenericDebugLogger.KEY_LOGLEVEL, this.logLevel);
this.printTimeStamp = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_PRINTTIMESTAMPS, this.printTimeStamp);
this.printFileAndLine = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_PRINTFILEANDLINE, this.printFileAndLine);
this.printNewLineFirst = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_PRINTNEWLINEFIRST, this.printNewLineFirst);
this.printShortClassNames = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_PRINTSHORTCLASSNAMES, this.printShortClassNames);
this.printUserNames = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_PRINTUSERNAMES, this.printUserNames);
this.useLogFile = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_USELOGFILE, this.useLogFile);
this.eclipseFriendlyOutput = this.properties.getPropertyAsBoolean(GenericDebugLogger.KEY_ECLIPSEFRIENDLYOUTPUT, this.eclipseFriendlyOutput);
this.properties.store(null);
}
/**
* check if the properties contain information on how to treat messages
* from this user
*@param user user id to check
*@return true, if Properties contain information on this user that allow posting his/her messages
*/
protected final boolean showMessagesOfUser(String user){
if (user.equals(GenericDebugLogger.loggerUserId))
return true;
String userString = GenericDebugLogger.userFlagPrefix + user.toLowerCase();
boolean allowMessagesFromUser = false;
allowMessagesFromUser = this.properties.getPropertyAsBoolean(userString, allowMessagesFromUser);
try {
this.properties.store();
} catch (IOException e) {
this.printMinorError(GenericDebugLogger.loggerUserId, e.getMessage());
}
return allowMessagesFromUser;
}
/**
* THE method to get an instance of this class
*@return the logger
*/
static final GenericDebugLogger getInstance(){
if (GenericDebugLogger.logger == null)
GenericDebugLogger.logger = new GenericDebugLogger();
return GenericDebugLogger.logger;
}
protected final void printMessage(String user, int severity, String message){
if (this.properties==null){
try {
this.loadProperties();
} catch (IOException e) {
this.printError(GenericDebugLogger.loggerUserId,"still can not load properties!");
return;
}
}
if (severity >= this.logLevel || this.showMessagesOfUser(user)){
String outputString = this.printUserNames?"("+user+") ":"";
outputString += GenericDebugLogger.severityLevels[severity] + " in " + this.getCallerString(new Throwable());
if (this.printTimeStamp == true){
Calendar date = Calendar.getInstance();
outputString += "(" + date.get(Calendar.HOUR_OF_DAY) + ":" + date.get(Calendar.MINUTE) + ":" + date.get(Calendar.SECOND) + "," + date.get(Calendar.MILLISECOND) + ")";
}
outputString += ": " + ((this.eclipseFriendlyOutput)?"\n\t":"") + message;
if (this.printNewLineFirst == true)
this.stdOut.println("---");
if (severity < GenericDebugLogger.SEVERITY_MINORERROR)
this.stdOut.println(outputString);
else
this.stdErr.println(outputString);
}
}
protected final String getCallerString(Throwable t){
String caller = "";
String FileAndNumberSep = ":";
StackTraceElement[] elements = t.getStackTrace();
for (int i=0; i<elements.length; i++){
if (elements[i].getClassName().equals(GenericDebugLogger.class.getName()))
continue;
if (elements[i].getClassName().equals(PersonalLogger.class.getName()))
continue;
if (this.printShortClassNames &&
elements[i].getClassName().indexOf(".")>-1 &&
!this.eclipseFriendlyOutput){
caller = elements[i].getClassName().substring(elements[i].getClassName().lastIndexOf(".")+1);
} else {
caller = elements[i].getClassName();
}
// fill in method name
caller += "."+ elements[i].getMethodName();// + "()";
if (! this.eclipseFriendlyOutput) {
caller+="()";
FileAndNumberSep = ",";
}
if (this.printFileAndLine == true || this.eclipseFriendlyOutput){
caller += "(" + elements[i].getFileName() +
FileAndNumberSep + elements[i].getLineNumber() +") ";
}
break;
}
if (caller.length() == 0)
caller = "???";
return caller;
}
protected final void printDebug(String user, String message){
this.printMessage(user, GenericDebugLogger.SEVERITY_DEBUG, message);
}
protected final void printWarning(String user, String message){
this.printMessage(user, GenericDebugLogger.SEVERITY_WARNING, message);
}
protected final void printMinorError(String user, String message){
this.printMessage(user, GenericDebugLogger.SEVERITY_MINORERROR, message);
}
protected final void printError(String user, String message){
this.printMessage(user, GenericDebugLogger.SEVERITY_ERROR, message);
}
protected final void printSevereError(String user, String message){
this.printMessage(user, GenericDebugLogger.SEVERITY_SEVEREERROR, message);
}
/**
*
*@return current log level
*/
public final int getLogLevel() {
return logLevel;
}
/**
*
* @param logLevel
*/
public final void setLogLevel(int logLevel) {
this.logLevel = logLevel;
this.properties.setProperty(GenericDebugLogger.KEY_LOGLEVEL, new Integer(logLevel).toString());
try {
this.properties.store();
} catch (IOException e) {
this.printError(GenericDebugLogger.loggerUserId, e.getMessage());
}
}
/**
*
* @return true or false //TODO specify the return value
*/
public final boolean isPrintFileAndLine() {
return printFileAndLine;
}
/**
*
* @return true or false //TODO specify the return value
*/
public final boolean isPrintNewLineFirst() {
return printNewLineFirst;
}
/**
*
* @return true or false //TODO specify the return value
*/
public final boolean isPrintTimeStamp() {
return printTimeStamp;
}
/**
*@return File name of the file where logger configuration is stored
*/
public final String getPropertiesFile() {
return propertiesFile;
}
/**
* Set the stream, where messages with a loglevel < SEVERITY_MINORERROR are put out.
*@param out stream for debugging output
*/
public final void setOutputStream(PrintStream out) {
this.stdOut = out;
this.stdOut.print("\n");
}
/**
* Set the stream, where messages with a loglevel >= SEVERITY_MINORERROR are put out.
*@param err stream for debugging output
*/
public final void setErrorStream(PrintStream err) {
this.stdErr = err;
this.stdErr.print("\n");
}
}