/* ************************************************************************* *
* *
* Copyright (c) 2004 Peter Cappello <cappello@cs.ucsb.edu> *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
* *
* ************************************************************************* */
/**
* Manages the standard Jicos logger.
*
* Created on: July 18, 2004
* Created by: pippin
*
* @author Andy Pippin
*/
/*
Comments:
File creation is rather complicated. If you specify a filename,
it will be checked to see if it is fully qualified. If it is, it
will be used unchanged. If not, the directory will be prepended.
*/
package jicosfoundation;
import java.util.logging.*;
public class LogManager {
//-- Constants -----------------------------------------------------------//
public static final Level DEFAULT_Level = Level.WARNING;
private static final Level ALL = Level.ALL;
public static final Level SEVERE = Level.SEVERE;
public static final Level WARNING = Level.WARNING;
public static final Level INFO = Level.INFO;
public static final Level CONFIG = Level.CONFIG;
public static final Level FINE = Level.FINE;
public static final Level FINER = Level.FINER;
public static final Level FINEST = Level.FINEST;
private static final Level OFF = Level.OFF;
// Special levels.
public static final Level DEBUG = new myLevel( "DEBUG", Level.FINE.intValue() );
public static final Level ERROR = new myLevel( "ERROR", Level.WARNING.intValue() );
public static final Level FAILED = new myLevel( "FAILED", ((Level.INFO.intValue() + Level.FINE.intValue())/2)+1 );
public static final Level HANDLED = new myLevel( "HANDLED", (Level.INFO.intValue() + Level.FINE.intValue())/2 );
public static final String PROPERTY_Base = "jicos.log";
public static final String PROPERTY_Filename = "filename";
public static final String PROPERTY_Directory = "directory";
public static final String PROPERTY_Level = "level";
public static final String PROPERTY_MaxSize = "maxsize";
public static final String PROPERTY_Files = "files";
public static final String PROPERTY_Handler = "handler";
public static final String PROPERTY_NumRecords = "records";
public static final String PROPERTY_LogHost = "loghost";
public static final String PROPERTY_LogPort = "logport";
public static final String PROPERTY_OutputStream = "output";
// Property values : Logger names.
private static final String LOGGER_Base = "edu.ucsb.cs.jicos";
public static final String LOGGER_Default = "default";
public static final String LOGGER_Applications = "applications";
public static final String LOGGER_Examples = "examples";
public static final String LOGGER_Foundation = "foundation";
public static final String LOGGER_Services = "services";
public static final String LOGGER_Utilities = "utilities";
private final static java.text.DateFormat dateFormatter = new java.text.SimpleDateFormat(
"yyyy.MM.dd-HH:mm:ss");
private final static String CRLF = System.getProperty("line.separator");
//-- Variables -----------------------------------------------------------//
private static java.util.Map loggerMap = null;
//-- Methods -------------------------------------------------------------//
/**
* Helper method - get the default logger.
*
* @return Default logger.
*/
public static Logger getLogger() {
return (localGetLogger(null));
}
/**
* Helper class - get the appropriate logger depending on ths class of
* the <CODE>object</CODE>.
* <BR><BR>
* <TABLE BORDER=0>
* <TR><TH>null</TH> <TD>default logger.</TD></TR>
* <TR><TH>String</TH><TD>treat it as the logger name.</TD></TR>
* <TR><TH>Class</TH> <TD>use the name of the class.</TD></TR>
* <TR><TH>???</TH> <TD>use the name of the class of the object.</TD></TR>
* </TABLE>
*
* @param object
* @return
*/
public static Logger getLogger( Object object ) {
Logger logger = null;
// If null, get default.
if( null == object ) {
logger = localGetLogger( (String)null );
// If a string, use that at the logger name.
} else if( object instanceof String ) {
logger = localGetLogger( (String)object );
// If a class, then use the class name as the logger.
} else if( object instanceof Class ) {
String className = ((Class)object).getName();
int lastDot = className.lastIndexOf( '.' );
String loggerName = className.substring( 0, lastDot );
loggerName = loggerName.replaceFirst( "edu.ucsb.cs.jicos.", "" );
//
logger = localGetLogger( className.substring( 0, lastDot ) );
// Otherwise, use the class name of the object as the logger.
} else {
String className = object.getClass().getName();
int lastDot = className.lastIndexOf( '.' );
String loggerName = className.substring( 0, lastDot );
loggerName = loggerName.replaceFirst( "edu.ucsb.cs.jicos.", "" );
//
logger = localGetLogger( className.substring( 0, lastDot ) );
}
return( logger );
}
/**
* Get a particular logger.
*
* @param loggerName The "unqualified" (no jicos.log) logger name.
* @return The specified logger.
*/
private static Logger localGetLogger(String loggerName) {
Logger logger = null;
String fqLoggerName = loggerName;
// Allow null (the default).
if( null == loggerName ) {
fqLoggerName = LogManager.LOGGER_Default;
}
// Prepend the fully qualified name.
if( !fqLoggerName.startsWith( LogManager.LOGGER_Base ) ) {
fqLoggerName = LogManager.LOGGER_Base + '.' + fqLoggerName;
}
// Create the map, if necessary.
if (null == LogManager.loggerMap) {
LogManager.loggerMap = new java.util.HashMap();
// Add the parent logger. This currently consumes all log messages.
//
Logger parentLogger = Logger.getLogger( LogManager.LOGGER_Base );
parentLogger.setUseParentHandlers( false );
}
// Get the logger. Create it if doesn't exist yet.
logger = (Logger)loggerMap.get( fqLoggerName );
if( null == logger ) {
logger = createLogger( fqLoggerName );
LogManager.loggerMap.put( fqLoggerName, logger );
}
return (logger);
}
/**
* Helper method - display loggers to System.out.
*/
public static void showLoggers() {
showLoggers(System.out);
}
/**
* Display all currently created loggers.
*
* @param output Where to send the output.
*/
public static void showLoggers(java.io.PrintStream output) {
if (null != loggerMap) {
final int width1 = 50;
final int width2 = 64;
final int width3 = 80;
String outputLine;
Handler handler;
System.out.println();
outputLine = " --Logger----------------------------------------- --Level---- --Handler------------------";
output.println( outputLine );
java.util.Set entrySet = loggerMap.entrySet();
java.util.Iterator entries = entrySet.iterator();
while (entries.hasNext()) {
Object mapEntry = entries.next();
Object loggerName = ((java.util.Map.Entry) mapEntry).getKey();
outputLine = " " + loggerName + " ";
outputLine = outputLine.substring(0, width1);
Object loggerObj = ((java.util.Map.Entry) mapEntry).getValue();
Logger logger = (Logger) loggerObj;
outputLine += " " + logger.getLevel().getName() + " ";
outputLine = outputLine.substring(0, width2);
Handler[] handlerArray = logger.getHandlers();
if (0 != handlerArray.length) {
handler = handlerArray[0];
outputLine += handler.getClass().getName().replaceAll(
"java.util.logging.", "");
for (int h = 1; h < handlerArray.length; ++h) {
handler = handlerArray[0];
outputLine += ", "
+ handler.getClass().getName().replaceAll(
"java.util.logging.", "");
}
}
output.println(outputLine);
}
System.out.println();
} else {
System.out.println( " There are no loggers currently available." );
}
return;
}
//
//-- Helper Methods ------------------------------------------------------
/**
* Helper method - log a message of level INFO to the default logger.
*
* @param message The message to log.
*/
public static void log(String message) {
Logger logger = localGetLogger(null);
logger.log(Level.INFO, message);
}
/**
* Helper method - Log the message of the exception to the default logger
* at level WARNING.
*
* @param exception The exception to be logged.
*/
public static void log(Throwable exception) {
if( null != exception ) {
Logger logger = localGetLogger(null);
logger.log(Level.WARNING, exception.getMessage() );
}
}
/**
* Helper method - log a message of the specified level to the default
* logger.
*
* @param level The log level.
* @param message The message to log.
*/
public static void log(Level level, String message) {
Logger logger = localGetLogger(null);
logger.log(level, message);
}
/**
* Helper method - log a message of the specified level to the default
* logger.
*
* @param object The object for which this log message belongs.
* @param level The log level.
* @param message The message to log.
*/
/*
public static void log(Object object, Level level, String message) {
Logger logger = getLogger(object);
logger.log(level, message);
}
*/
//
//-- Private Methods -----------------------------------------------------
// This is only called to create new loggers.
//
private static Logger createLogger(String loggerName) {
Logger newLogger = null;
// Bail if they are stupid.
if (null == loggerName) {
throw new NullPointerException( "Need to specify the logger name." );
}
// Get the logger, handler, formatter, and level.
newLogger = Logger.getLogger( loggerName );
Handler handler = getHandler( loggerName );
java.util.logging.Formatter formatter = new LogManager.Formatter();
Level level = getValue_Level( loggerName );
// Put everything together and create the logger.
handler.setLevel( level );
handler.setFormatter( formatter );
newLogger.setLevel( level );
newLogger.addHandler( handler );
// Give it back.
return( newLogger );
}
//
//========================================================================
//== Create the handler ==================================================
//========================================================================
private static Handler getHandler( String loggerName ) {
Handler handler = null;
// Get the type of handler.
String handlerName = getProperty( loggerName, PROPERTY_Handler, "Console" );
handlerName = handlerName.toLowerCase();
if( handlerName.startsWith( "file" ) ) {
handler = createFileHandler( loggerName );
} else if( handlerName.startsWith( "memory" ) ) {
handler = createMemoryHandler( loggerName );
} else if( handlerName.startsWith( "socket" ) ) {
handler = createSocketHandler( loggerName );
} else if( handlerName.startsWith( "stream" ) ) {
handler = createStreamHandler( loggerName );
} else {
handler = createConsoleHandler( loggerName );
}
// Set the formatter.
handler.setFormatter( new LogManager.Formatter() );
return( handler );
}
private static Handler createFileHandler( String loggerName ) {
Handler handler = null;
String filename = getValue_Filename( loggerName );
int maxSize = getValue_MaxSize( loggerName );
int numFiles = getValue_Files( loggerName );
boolean append = true;
try {
handler = new FileHandler( filename, maxSize, numFiles, append );
} catch( Exception anyException ) { // Ack!! Pfft!!
handler = new ConsoleHandler();
}
return( handler );
}
private static Handler createMemoryHandler( String loggerName ) {
Handler handler = null;
String num = getProperty(loggerName, PROPERTY_NumRecords, "1000");
int numRecords = Integer.parseInt( num );
handler = new MemoryHandler(new ConsoleHandler(), numRecords,
LogManager.WARNING);
return( handler );
}
private static Handler createSocketHandler( String loggerName ) {
Handler handler = null;
String host = getProperty( loggerName, PROPERTY_LogHost, "localhost" );
String port = getProperty( loggerName, PROPERTY_LogPort, null );
try {
if( (null != host) && (null != port) ) {
handler = new SocketHandler( host, Integer.parseInt( port ) );
} else {
handler = new SocketHandler(); // try the default.
}
} catch( Exception anyException ) {
handler = new ConsoleHandler();
}
return( handler );
}
private static Handler createStreamHandler( String loggerName ) {
Handler handler = null;
String streamName = getProperty( loggerName, PROPERTY_OutputStream, "System.err" );
if( "System.out".equals( streamName )) {
handler = new StreamHandler( System.out, null );
} else if( "System.err".equals( streamName )) {
handler = new StreamHandler( System.err, null );
}
return( handler );
}
private static Handler createConsoleHandler( String loggerName ) {
Handler handler = new ConsoleHandler();
return( handler );
}
//
//========================================================================
//== Get a property name =================================================
//========================================================================
// Filename of log.
private static String getValue_Filename( String loggerName ) {
return( getProperty( loggerName, PROPERTY_Filename, "logger"+'-'+loggerName ) );
}
// Directory of log file.
private static String getValue_Directory( String loggerName ) {
return( getProperty( loggerName, PROPERTY_Directory, "log" ) );
}
// Level of logging.
private static Level getValue_Level( String loggerName ) {
String level = getProperty( loggerName, PROPERTY_Level, DEFAULT_Level.toString() );
return( getLevel( level ) );
}
// Maximum file size (in bytes).
private static int getValue_MaxSize( String loggerName ) {
String maxSize = getProperty( loggerName, PROPERTY_MaxSize, "5000000" ); // 5MB
return( Integer.parseInt( maxSize ) );
}
// Number of rotating files.
private static int getValue_Files( String loggerName ) {
String numFiles = getProperty( loggerName, PROPERTY_Files, "5" );
return( Integer.parseInt( numFiles ) );
}
/*
* Get the value of the property for a particular logger.
*
* Example:
* getProperty( "default", "filename", "logger-default" );
*
* If the PROPERTY_Base is "jicos.log", then the property:
* jicos.log.default.filename
* is checked first, then the property:
* jicos.log.filename
* is checked. If neither exist then logger-default is returned.
*
* This method will toss an exception if the loggerName is null!
*
* @param loggerName The "unqualified" name of the logger.
* @param property The property to look for.
* @param defaultValue The default value.
* @return Ther property value.
*/
private static String getProperty( String loggerName, String property, String defaultValue ) {
String propValue = null;
Object value;
// If loggerName or property is null, then it's the programmers own
// damn fault this crashes.
String specific = LogManager.PROPERTY_Base + '.' + loggerName + '.' + property;
specific = specific.replaceFirst( "jicos.log."+ LOGGER_Base, "jicos.log" );
String generic = LogManager.PROPERTY_Base + '.' + property;
// Try for the logger-specific value first.
if( null != (property = System.getProperty( specific )) ) {
propValue = (String)property;
// Try for the logger-general value next.
} else if( null != (property = System.getProperty( generic )) ) {
propValue = (String)property;
} else {
propValue = defaultValue;
}
return( propValue );
}
//
//========================================================================
private static Level getLevel(String levelName) {
Level level;
if (null == levelName)
level = DEFAULT_Level;
else if (levelName.equalsIgnoreCase("all"))
level = Level.ALL;
else if (levelName.equalsIgnoreCase("severe"))
level = Level.SEVERE;
else if (levelName.equalsIgnoreCase("warning"))
level = Level.WARNING;
else if (levelName.equalsIgnoreCase("error"))
level = (Level)LogManager.ERROR;
else if (levelName.equalsIgnoreCase("info"))
level = Level.INFO;
else if (levelName.equalsIgnoreCase("failed"))
level = (Level)LogManager.FAILED;
else if (levelName.equalsIgnoreCase("handled"))
level = (Level)LogManager.HANDLED;
else if (levelName.equalsIgnoreCase("config"))
level = Level.CONFIG;
else if (levelName.equalsIgnoreCase("debug"))
level = (Level)LogManager.DEBUG;
else if (levelName.equalsIgnoreCase("fine"))
level = Level.FINE;
else if (levelName.equalsIgnoreCase("finer"))
level = Level.FINER;
else if (levelName.equalsIgnoreCase("finest"))
level = Level.FINEST;
else if (levelName.equalsIgnoreCase("off"))
level = Level.OFF;
else
level = DEFAULT_Level;
return (level);
}
private static boolean isFullyQualified(String filename) {
boolean isFullyQualified = false;
if (null == filename)
return (false);
String osName = System.getProperty("os.name").toLowerCase();
if (osName.startsWith("windows")) {
if ((2 < filename.length())
&& Character.isLetter(filename.charAt(0))
&& (':' == filename.charAt(1))
&& (('/' == filename.charAt(2) || ('\\' == filename
.charAt(2))))) {
isFullyQualified = true;
}
if ((0 < filename.length()) && ('\\' == filename.charAt(0))) {
isFullyQualified = true;
}
}
else if ((0 < filename.length()) && ('/' == filename.charAt(0))) {
isFullyQualified = true;
}
return (isFullyQualified);
}
//-- Inner Classes -------------------------------------------------------//
public static class Formatter extends java.util.logging.Formatter {
public String format(LogRecord logRecord) {
StringBuffer buffer = new StringBuffer(160);
buffer.append(dateFormatter.format(new java.util.Date(logRecord
.getMillis())));
buffer.append(" ");
buffer.append(logRecord.getLevel().getName());
buffer.append(" ");
String className = logRecord.getSourceClassName();
buffer.append(className.replaceAll("edu.ucsb.cs.jicos", "*"));
String methodName = logRecord.getSourceMethodName();
if( "<init>".equals( methodName ) ) {
methodName = "";
} else {
methodName = "." + methodName;
}
buffer.append( methodName );
buffer.append("(): ");
buffer.append(logRecord.getMessage());
buffer.append(CRLF);
return (new String(buffer));
}
}
public static class myLevel extends java.util.logging.Level {
myLevel() {
super( null, 0 );
}
myLevel( String name, int value ) {
super( name, value );
}
myLevel( String name, int value, String resourceBundleName ) {
super( name, value, resourceBundleName );
}
myLevel( java.util.logging.Level level ) {
super( level.getName(), level.intValue(), level.getResourceBundleName() );
}
}
}
//== End of LogManager.java ====================================================