FileDocCategorySizeDatePackage
Logger.javaAPI DocAndroid 1.5 API20206Wed May 06 22:41:16 BST 2009com.vladium.logging

Logger

public final class Logger extends Object implements ILogLevels
A simple Java version-independent logging framework. Each Logger is also an immutable context that encapsulates configuration elements like the logging verbosity level etc. In general, a Logger is looked up as an inheritable thread-local piece of data. This decouples classes and logging configurations in a way that seems difficult with log4j.

Note that a given class is free to cache its context in an instance field if the class is instantiated and used only on a single thread (or a set of threads that are guaranteed to share the same logging context). [This is different from the usual log4j pattern of caching a logger in a class static field]. In other cases (e.g., the instrumentation runtime), it makes more sense to scope a context to a single method invocation.

Every log message is structured as follows:

  1. message is prefixed with the prefix string set in the Logger if that is not null;
  2. if the calling class could be identified and it supplied the calling method name, the calling method is identified with all name components that are not null;
  3. caller-supplied message is logged, if not null;
  4. caller-supplied Throwable is dumped starting with a new line, if not null.
MT-safety: a given Logger instance will not get corrupted by concurrent usage from multiple threads and guarantees that data written to the underlying PrintWriter in a single log call will be done in one atomic print() step.
see
ILogLevels
author
(C) 2001, Vlad Roubtsov

Fields Summary
private final int
m_level
private final PrintWriter
m_out
private final String
m_prefix
private final Set
m_classMask
private static final String
PREFIX_TO_STRIP
private static final int
PREFIX_TO_STRIP_LENGTH
private static final boolean
FLUSH_LOG
private static final String
COMMA_DELIMITERS
private static final Logger
STATIC_LOGGER
private static final ThreadLocalStack
THREAD_LOCAL_STACK
Constructors Summary
private Logger(int level, PrintWriter out, String prefix, Set classMask)

        m_level = level;
        m_out = out;
        m_prefix = prefix;
        m_classMask = classMask; // no defensive clone
    
Methods Summary
private void_log(int level, java.lang.String method, java.lang.String msg, boolean logCaller)

        if ((level <= m_level) && (level >= SEVERE))
        {
            final Class caller = logCaller ? ClassLoaderResolver.getCallerClass (2) : null;
            final StringBuffer buf = new StringBuffer (m_prefix != null ? m_prefix + ": " : "");

            if ((caller != null) || (method != null))
            {
                buf.append ("[");
                
                if (caller != null) // if the caller could not be determined, s_classMask is ignored
                {
                    String callerName = caller.getName ();
                    
                    if (callerName.startsWith (PREFIX_TO_STRIP))
                        callerName = callerName.substring (PREFIX_TO_STRIP_LENGTH);
                        
                    String parentName = callerName;
                    
                    final int firstDollar = callerName.indexOf ('$");
                    if (firstDollar > 0) parentName = callerName.substring (0, firstDollar);
                    
                    if ((m_classMask == null) || m_classMask.contains (parentName))
                        buf.append (callerName);
                    else
                        return;
                }
                
                if (method != null)
                {
                    buf.append ("::");
                    buf.append (method);
                }
                
                buf.append ("] ");
            }

            final PrintWriter out = m_out;

            if (msg != null) buf.append (msg);
            
            out.println (buf);
            if (FLUSH_LOG) out.flush ();
        }
    
private void_log(int level, java.lang.String method, java.lang.String msg, java.lang.Throwable throwable)

        
        if ((level <= m_level) && (level >= SEVERE))
        {
            final Class caller = ClassLoaderResolver.getCallerClass (2);
            final StringBuffer buf = new StringBuffer (m_prefix != null ? m_prefix + ": " : "");
            
            if ((caller != null) || (method != null))
            {
                buf.append ("[");
                
                if (caller != null) // if the caller could not be determined, s_classMask is ignored
                {
                    String callerName = caller.getName ();
                    
                    if (callerName.startsWith (PREFIX_TO_STRIP))
                        callerName = callerName.substring (PREFIX_TO_STRIP_LENGTH);
                        
                    String parentName = callerName;
                    
                    final int firstDollar = callerName.indexOf ('$");
                    if (firstDollar > 0) parentName = callerName.substring (0, firstDollar);
                    
                    if ((m_classMask == null) || m_classMask.contains (parentName))
                        buf.append (callerName);
                    else
                        return;
                }
                
                if (method != null)
                {
                    buf.append ("::");
                    buf.append (method);
                }
                
                buf.append ("] ");
            }
            
            final PrintWriter out = m_out;
            
            if (msg != null) buf.append (msg);
            
            if (throwable != null)
            {
                final StringWriter sw = new StringWriter ();
                final PrintWriter pw = new PrintWriter (sw);
                
                throwable.printStackTrace (pw);
                pw.flush ();
                
                buf.append (sw.toString ());
            }

            out.println (buf);
            if (FLUSH_LOG) out.flush ();
        }
    
public final booleanatINFO()
A convenience method equivalent to isLoggable(INFO).

        return (INFO <= m_level);
    
public final booleanatTRACE1()
A convenience method equivalent to isLoggable(TRACE1).

        return (TRACE1 <= m_level);
    
public final booleanatTRACE2()
A convenience method equivalent to isLoggable(TRACE2).

        return (TRACE2 <= m_level);
    
public final booleanatTRACE3()
A convenience method equivalent to isLoggable(TRACE3).

        return (TRACE3 <= m_level);
    
public final booleanatVERBOSE()
A convenience method equivalent to isLoggable(VERBOSE).

        return (VERBOSE <= m_level);
    
private voidcleanup()

        m_out.flush ();
    
public static com.vladium.logging.Loggercreate(int level, java.io.PrintWriter out, java.lang.String prefix, java.util.Set classMask)

        if ((level < NONE) || (level > ALL))
            throw new IllegalArgumentException ("invalid log level: " + level);
        
        if ((out == null) || out.checkError ())
            throw new IllegalArgumentException ("null or corrupt input: out");
        
        return new Logger (level, out, prefix, classMask);
    
public static com.vladium.logging.Loggercreate(int level, java.io.PrintWriter out, java.lang.String prefix, java.util.Set classMask, com.vladium.logging.Logger base)
This works as a cloning creator of sorts.

param
level
param
out
param
prefix
param
classMask
param
base
return

        if (base == null)
        {
            return create (level, out, prefix, classMask);
        }
        else
        {
            final int _level = level >= NONE
                ? level
                : base.m_level;
                
            final PrintWriter _out = (out != null) && ! out.checkError ()
                ? out
                : base.m_out;
            
            // TODO: do a better job of logger cloning
            final String _prefix = prefix;
//            final String _prefix = prefix != null
//                ? prefix
//                : base.m_prefix;
            
            final Set _classMask = classMask != null
                ? classMask
                : base.m_classMask;
        
        
            return new Logger (_level, _out, _prefix, _classMask);
        }
    
public static com.vladium.logging.LoggergetLogger()
Returns the current top of the thread-local logger stack or the static Logger instance scoped to Logger.class if the stack is empty.

return
current logger [never null]

        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();
        
        // [assertion: stack != null]

        if (stack.isEmpty ())
        {
            return STATIC_LOGGER;
        }
        else
        {
            return (Logger) stack.getLast ();
        }
    
public java.io.PrintWritergetWriter()
Provides direct access to the PrintWriter used by this Logger.

return
print writer used by this logger [never null]

        return m_out;
    
public final voidinfo(java.lang.String msg)
A convenience method to log 'msg' from an anonymous calling method at INFO level.

param
msg log message [ignored if null]

        _log (INFO, null, msg, false);
    
public final booleanisLoggable(int level)
A quick method to determine if logging is enabled at a given level. This method acquires no monitors and should be used when calling one of log() or convenience logging methods directly incurs significant parameter construction overhead.

see
ILogLevels

        return (level <= m_level);
    
public final voidlog(int level, java.lang.String msg, boolean logCaller)
Logs 'msg' from an unnamed calling method.

param
level level to log at [the method does nothing if this is less than the set level].
param
msg log message [ignored if null]

        _log (level, null, msg, logCaller);
    
public final voidlog(int level, java.lang.String method, java.lang.String msg, boolean logCaller)
Logs 'msg' from a given calling method.

param
level level to log at [the method does nothing if this is less than the set level].
param
method calling method name [ignored if null]
param
msg log message [ignored if null]

        _log (level, method, msg, logCaller);
    
public final voidlog(int level, java.lang.String msg, java.lang.Throwable throwable)
Logs 'msg' from an unnamed calling method followed by the 'throwable' stack trace dump.

param
level level to log at [the method does nothing if this is less than the set level].
param
msg log message [ignored if null]
param
throwable to dump after message [ignored if null]

        _log (level, null, msg, throwable);
    
public final voidlog(int level, java.lang.String method, java.lang.String msg, java.lang.Throwable throwable)
Logs 'msg' from a given calling method followed by the 'throwable' stack trace dump.

param
level level to log at [the method does nothing if this is less than the set level].
param
method calling method name [ignored if null]
param
msg log message [ignored if null]
param
throwable to dump after message [ignored if null]

        _log (level, method, msg, throwable);
    
public static voidpop(com.vladium.logging.Logger ctx)
Requiring a context parameter here helps enforce correct push/pop nesting in the caller code.

param
ctx [may not be null]

        // TODO: add guards for making sure only the pushing thread is allowed to
        // execute this
        
        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();

        try
        {
            final Logger current = (Logger) stack.getLast ();
            if (current != ctx)
                throw new IllegalStateException ("invalid context being popped: " + ctx);
            
            stack.removeLast ();
            current.cleanup ();
        }
        catch (NoSuchElementException nsee)
        {
            throw new IllegalStateException ("empty logger context stack on thread [" + Thread.currentThread () + "]: " + nsee);
        }
    
public static voidpush(com.vladium.logging.Logger ctx)

param
ctx [may not be null]

        if (ctx == null)
            throw new IllegalArgumentException ("null input: ctx");
        
        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();
        stack.addLast (ctx);
    
public static intstringToLevel(java.lang.String level)

        if (ILogLevels.SEVERE_STRING.equalsIgnoreCase (level) || ILogLevels.SILENT_STRING.equalsIgnoreCase (level))
            return ILogLevels.SEVERE;
        else if (ILogLevels.WARNING_STRING.equalsIgnoreCase (level) || ILogLevels.QUIET_STRING.equalsIgnoreCase (level))
            return ILogLevels.WARNING;
        else if (ILogLevels.INFO_STRING.equalsIgnoreCase (level))
            return ILogLevels.INFO;
        else if (ILogLevels.VERBOSE_STRING.equalsIgnoreCase (level))
            return ILogLevels.VERBOSE;
        else if (ILogLevels.TRACE1_STRING.equalsIgnoreCase (level))
            return ILogLevels.TRACE1;
        else if (ILogLevels.TRACE2_STRING.equalsIgnoreCase (level))
            return ILogLevels.TRACE2;
        else if (ILogLevels.TRACE3_STRING.equalsIgnoreCase (level))
            return ILogLevels.TRACE3;
        else if (ILogLevels.NONE_STRING.equalsIgnoreCase (level))
            return ILogLevels.NONE;
        else if (ILogLevels.ALL_STRING.equalsIgnoreCase (level))
            return ILogLevels.ALL;
        else
        {
            int _level = Integer.MIN_VALUE;
            try
            {
                _level = Integer.parseInt (level);
            }
            catch (Exception ignore) {}
            
            if ((_level >= ILogLevels.NONE) && (_level <= ILogLevels.ALL))
                return _level;
            else
                return ILogLevels.INFO; // default to something middle of the ground
        }
    
public final voidtrace1(java.lang.String method, java.lang.String msg)
A convenience method equivalent to log(TRACE1, method, msg).

param
method calling method name [ignored if null]
param
msg log message [ignored if null]

        _log (TRACE1, method, msg, true);
    
public final voidtrace2(java.lang.String method, java.lang.String msg)
A convenience method equivalent to log(TRACE2, method, msg).

param
method calling method name [ignored if null]
param
msg log message [ignored if null]

        _log (TRACE2, method, msg, true);
    
public final voidtrace3(java.lang.String method, java.lang.String msg)
A convenience method equivalent to log(TRACE3, method, msg).

param
method calling method name [ignored if null]
param
msg log message [ignored if null]

        _log (TRACE3, method, msg, true);
    
public final voidverbose(java.lang.String msg)
A convenience method to log 'msg' from an anonymous calling method at VERBOSE level.

param
msg log message [ignored if null]

        _log (VERBOSE, null, msg, false);
    
public final voidwarning(java.lang.String msg)
A convenience method to log 'msg' from an anonymous calling method at WARNING level.

param
msg log message [ignored if null]

        _log (WARNING, null, msg, false);