package net.xoetrope.debug;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import net.xoetrope.data.XDataSource;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.data.XModel;
/**
* Keep track of errors and waranings. The class is implemented as a singleton
* so that it can count the errors and warnings and give some statistics when
* the application shutsdown as a debugging aid.
* <p>Copyright (c) Xoetrope Ltd., 2002-2005</p>
* $Revision: 2.4 $
* License: see license.txt
*/
public class DebugLogger
{
/**
* do not log anything
*/
public static final int SILENT = -1;
/**
* only output error messages
*/
public static final int NORMAL = 0;
/**
* output errors, dumps and exit messages
*/
public static final int DEBUG = 1;
/**
* output debug messages, errors, dumps, exit massages, traces and log values
*/
public static final int VERBOSE = 2;
/**
* output all logging information
*/
public static final int PARANOID = 3;
private static int numErrors;
private static int numWarnings;
private static DebugLogger logger;
private static int level = NORMAL;
private static boolean logMessageTime;
private static XLogListener logListener;
private static XLogWriter outputWriter;
private static XLogWriter errorWriter;
private static Hashtable zones = new Hashtable();
protected DebugLogger()
{
if ( BuildProperties.DEBUG ) {
numErrors = 0;
numWarnings = 0;
logMessageTime = true;
level = VERBOSE;
}
}
/**
* On exit this method will dump the contents of the debug log and close the VM
*/
public static void exitApplication()
{
if ( BuildProperties.DEBUG )
net.xoetrope.debug.DebugLogger.dump();
System.exit( 0 );
zones.clear();
}
/**
* Display log counts for warnings and errors
*/
public static void dump()
{
if ( BuildProperties.DEBUG ) {
if ( level >= DEBUG ) {
writeLine( "================================================================================" );
writeLine( "There were " + numErrors + " errors logged" );
writeLine( "There were " + numWarnings + " warnings logged" );
writeLine( "================================================================================" );
}
}
}
/**
* Get the logger instance
* @return the DebugLogger instance
*/
public static DebugLogger getInstance()
{
if ( logger == null )
logger = new DebugLogger();
return logger;
}
/**
* Write an error message to the error stream. Errors are logged unless the
* logLevel is SILENT
* @param error the error message
* @param zone the zone name
*/
public static void logError( String zone, String error )
{
if (( level > SILENT ) && isZoneEnabled( zone )) {
getInstance();
writeErrorLine( "ERROR: " + error );
numErrors++;
}
}
/**
* Write an error message to the error stream. Errors are logged unless the
* logLevel is SILENT
* @param error the error message
*/
public static void logError( String error )
{
logError( null, error );
}
/**
* Write a warning message to the console. Warnings are logged unless the
* logLevel is less than DEBUG or unless the DEBUG build property is set to false
* @param zone the zone name
* @param warning the warning message
*/
public static void logWarning( String zone, String warning )
{
if ( BuildProperties.DEBUG ) {
getInstance();
if (( level >= DEBUG ) && isZoneEnabled( zone )) {
writeLine( "WARNING: " + warning );
numWarnings++;
}
}
}
/**
* Write a warning message to the console. Warnings are logged unless the
* logLevel is less than DEBUG or unless the DEBUG build property is set to false
* @param warning the warning message
*/
public static void logWarning( String warning )
{
logWarning( null, warning );
}
/**
* Write a message to the log
* @param msg the message to log
*/
public static void log( String msg )
{
getInstance();
writeLine( msg );
}
/**
* Write a message to the console. Trace messages are logged unless the
* logLevel is less than VERBOSE or unless the DEBUG build property is set to false
* @param zone the zone name
* @param msg the log message
*/
public static void trace( String zone, String msg )
{
if ( BuildProperties.DEBUG ) {
getInstance();
if (( level >= VERBOSE ) && isZoneEnabled( zone ))
writeLine( "TRACE: " + msg );
}
}
/**
* Write a message to the console. Trace messages are logged unless the
* logLevel is less than VERBOSE or unless the DEBUG build property is set to false
* @param msg the log message
*/
public static void trace( String msg )
{
trace( null, msg );
}
/**
* Write a message to the console. The message is assumed to have a substitution
* for a numeric value e.g. 'TRACE: The X value is VALUE: 1.09'
* Trace messages are logged unless the logLevel is less than VERBOSE or
* unless the DEBUG build property is set to false
* @param msg the log message
* @param value the value causing the trace
*/
public static void trace( String msg, double value )
{
if ( BuildProperties.DEBUG ) {
getInstance();
if ( level >= VERBOSE )
writeLine( "TRACE: " + msg + " VALUE: " + value );
}
}
/**
* Write a snapshot of a model or model fragment to the log
* @param currentProject the owner project
* @param model the model node to log
*/
public static void trace( XProject currentProject, XModel model )
{
if ( BuildProperties.DEBUG ) {
getInstance();
if ( level >= VERBOSE ) {
writeLine( "TRACE: model type - " + model.getClass().getName() + "[" + model.getNumChildren() + "," + model.getNumAttributes() + "]");
writeLine( "--------------------------------------------------------------------------------");
StringWriter sw = new StringWriter();
XDataSource os = new XDataSource( currentProject );
if ( model instanceof DumpWriter )
((DumpWriter)model).dump( sw );
else
os.outputModel( sw, model );
System.out.print( sw.toString());
writeLine( "--------------------------------------------------------------------------------");
}
}
}
/**
* Write a representation of the model to the console.
* @param model the model node to dump
*/
public static void dumpModel( XModel model )
{
if ( BuildProperties.DEBUG ) {
if ( model != null ) {
try {
writeLine( model.getTagName() + ":" + model.getId() + ":" + model.get() );
}
catch ( Exception ex ) {
writeLine( model.toString() );
}
for ( int i = 0; i < model.getNumChildren(); i++ ) {
try {
dumpModel( ( XModel )model.get( i ) );
}
catch ( Exception ex1 ) {
writeLine( new Integer( i ).toString() );
}
}
if ( model.getNumChildren() != 0 )
writeLine( "--------------------------------------------------------------------------------");
}
}
}
/**
* Set the logging level, by default the level is verbose<br>
* NORMAL = 0, only output error messages<br>
* DEBUG = 1, output errors, dumps and exit messages<br>
* VERBOSE = 2, output debug messages, errors, dumps, exit massages, traces and log values<br>
* PARANOID = 3, output all logging information<br>
* @param newLevel the new log level
*/
public static void setDebugLevel( int newLevel )
{
level = newLevel;
}
/**
* Set the logging level, by default the level is verbose<br>
* SILENT = -1, do not log anything
* NORMAL = 0, only output error messages<br>
* DEBUG = 1, output errors, dumps and exit messages<br>
* VERBOSE = 2, output debug messages, errors, dumps, exit massages, traces and log values<br>
* PARANOID = 3, output all logging information<br>
* @param newLevel the new log level
*/
public static void setDebugLevel( String newLevel )
{
try {
if ( newLevel != null )
level = new Integer( newLevel ).intValue();
}
catch ( NumberFormatException ex ) {
logError( "Unable to set the logging level, invalid value: " + newLevel );
}
}
/**
* Check if a debug zone is enabled
* @param zone the zone name
* @return true if the zone is enabled
*/
public static boolean isZoneEnabled( String zone )
{
if ( zone == null )
return true;
// If the zones hashtable contains a token then the zone is disabled... i.e. zones are enabled by default
return !( zones.get( zone ) != null );
}
/**
* Enable/disable a debug zone
* @param state true to enable the zone, false otherwise
* @param zone the zone name
*/
public static void enableZone( String zone, boolean state )
{
// If the zones hashtable contains a token then the zone is disabled... i.e. zones are enabled by default
if ( zones.get( zone ) == null ) {
if ( state )
zones.remove( zone );
else
zones.put( zone, zone );
}
}
/**
* Write a line to the system output and log the message
* @param line the message to log
*/
protected static void writeLine( String line )
{
String msg = line;
if ( logMessageTime )
msg = new Date().toString() + " " + msg;
if ( logListener != null )
logListener.addMessage( msg );
if ( outputWriter != null )
outputWriter.writeLine( msg );
else
System.out.println( msg );
}
/**
* Write an error line to the system error stream and log the message
* @param line the message to log
*/
protected static void writeErrorLine( String line )
{
String msg = line;
if ( logMessageTime )
msg = new Date().toString() + " " + msg;
if ( logListener != null )
logListener.addError( msg );
if ( outputWriter != null )
errorWriter.writeLine( msg );
else
System.err.println( msg );
}
/**
* Set a listener for log messsages
* @param logger the listener
*/
public static void setLogListener( XLogListener logger )
{
logListener = logger;
}
/**
* Set the writer for the output stream
*/
public static void setOutputWriter( XLogWriter writer )
{
outputWriter = writer;
}
/**
* Set the writer for the error output stream
*/
public static void setErrorWriter( XLogWriter writer )
{
errorWriter = writer;
}
/**
* Turn on/off the logging of time each log message was stored.
* @param state true to turn on message time logging, or false to turn it off.
*/
public static void setLogMessageTime( boolean state )
{
logMessageTime = state;
}
/**
* Read the debug zones file ("DebugZones.properties")
* @param currentProject the owner project
*/
public static void readLoggerZones( XProject currentProject )
{
if ( BuildProperties.DEBUG ) {
try {
zones.clear();
InputStream is = currentProject.getInputStream( "DebugZones.properties" );
if ( is != null ){
Properties propFile = new Properties();
propFile.load( is );
Enumeration keysEnum = propFile.keys();
while ( keysEnum.hasMoreElements() ) {
String zone = (String)keysEnum.nextElement();
String value = propFile.getProperty( zone );
if ( value != null )
enableZone( zone, value.equals( "on" ));
}
}
}
catch ( Exception e ) {
System.err.println( "Unable to load the \"DebugZones.properties\" file." );
}
}
}
}