Package com.enterprisedt.util.debug

Source Code of com.enterprisedt.util.debug.Logger

/**
*
*  Copyright (C) 2000-2004 Enterprise Distributed Technologies Ltd
*
*  www.enterprisedt.com
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library 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
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*  Bug fixes, suggestions and comments should be sent to bruce@enterprisedt.com
*
*  Change Log:
*
*    $Log: Logger.java,v $
*    Revision 1.26  2010-10-28 01:39:39  bruceb
*    configurable prefix
*
*    Revision 1.25  2010-05-07 23:11:42  hans
*    Fixed spelling mistake in comments.
*
*    Revision 1.24  2008-09-18 07:04:02  bruceb
*    log4j fixes
*
*    Revision 1.23  2008-04-01 06:41:16  hans
*    Added addFileAppender and addStandardOutputAppender
*
*    Revision 1.22  2008-01-09 03:58:54  bruceb
*    include stack trace
*
*    Revision 1.21  2007-05-29 03:08:53  bruceb
*    remove comment conflict
*
*    Revision 1.20  2007-05-29 03:08:04  bruceb
*    add code for enabling logging of thread names
*
*    Revision 1.19  2007-05-15 04:31:59  hans
*    Made sure each Appender only gets added once in addAppender.
*
*    Revision 1.18  2007/04/26 04:22:53  hans
*    Added removeAppender
*
*    Revision 1.17  2007/03/27 10:23:08  bruceb
*    clearAllElements()
*
*    Revision 1.16  2007/03/26 05:23:32  bruceb
*    add clearAppenders
*
*    Revision 1.15  2007/02/14 00:56:13  hans
*    Added getLevel
*
*    Revision 1.14  2006/11/14 12:13:24  bruceb
*    fix bug whereby ALL level was causing exception in log4j
*
*    Revision 1.13  2006/10/27 16:30:04  bruceb
*    fixed javadoc
*
*    Revision 1.12  2006/10/12 12:38:58  bruceb
*    synchronized methods
*
*    Revision 1.11  2006/09/08 07:49:35  hans
*    Fixed error where isEnabledFor didn't work if log4j is being used.
*    Also added debug methods with MessageFormat-type parameters.
*
*    Revision 1.10  2006/05/22 01:53:03  hans
*    Added method for dumping byte-arrays as hex
*
*    Revision 1.9  2006/03/16 21:49:07  hans
*    Added support for logging of exception causes
*
*    Revision 1.8  2005/02/04 12:29:08  bruceb
*    add exception message to output
*
*    Revision 1.7  2004/10/20 21:03:09  bruceb
*    catch SecurityExceptions
*
*    Revision 1.6  2004/09/17 12:27:11  bruceb
*    1.1 compat
*
*    Revision 1.5  2004/08/31 13:54:50  bruceb
*    remove compile warnings
*
*    Revision 1.4  2004/08/16 21:08:08  bruceb
*    made cvsids public
*
*    Revision 1.3  2004/06/25 11:52:26  bruceb
*    fixed logging bug
*
*    Revision 1.2  2004/05/08 21:13:51  bruceb
*    renamed property
*
*    Revision 1.1  2004/05/01 16:55:42  bruceb
*    first cut
*
*
*/
package com.enterprisedt.util.debug;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

import com.enterprisedt.BaseIOException;

/**
*  Logger class that mimics log4j Logger class. If log4j integration
*  is desired, the "edtftp.log4j" property should be set to "true" and
*  log4j classes must be in the classpath
*
@author      Bruce Blackshaw
@version     $Revision: 1.26 $
*/
public class Logger {
   
    /**
     *  Revision control id
     */
    public static String cvsId = "@(#)$Id: Logger.java,v 1.26 2010-10-28 01:39:39 bruceb Exp $";
   
    /**
     * Level of all loggers
     */
    private static Level globalLevel;
   
    /**
     * Log thread names of all loggers
     */
    private static boolean logThreadNames = false;
   
    /**
     * Timestamp formatter
     */
    private SimpleDateFormat format = new SimpleDateFormat("d MMM yyyy HH:mm:ss.SSS");
   
    /**
     * Hash of all loggers that exist
     */
    private static Hashtable loggers = new Hashtable(10);
   
    /**
     * Vector of all appenders
     */
    private static Vector appenders = new Vector(2);
   
    /**
     * Shall we use log4j or not?
     */
    private boolean useLog4j = false;
   
    /**
     * Log this logger's thread name
     */
    private boolean logThreadName = false;
   
    /**
     * Timestamp
     */
    private Date ts = new Date();
   
    /**
     * Class name for this logger
     */
    private String clazz;
   
    /**
     *  Log4j logging methods
     */
    private Method[][] logMethods = null;

    /**
     * Log4j toPriority method
     */
    private Method toLevelMethod = null;
   
    /**
     * Log4j isEnabledFor method
     */
    private Method isEnabledForMethod = null;
   
    /**
     * Logger log4j object
     */
    private Object logger = null;
   
    /**
     * Arg arrays for use in invoke
     */
    private Object[] argsPlain = new Object[1];
   
    /**
     * Arg arrays for use in invoke
     */
    private Object[] argsThrowable = new Object[2];
   
    /**
     * Determine the logging level
     */
    static {
        String level = Level.OFF.toString();
        try {
            level = System.getProperty("edtftp.log.level", Level.OFF.toString());
        }
        catch (SecurityException ex) {
            System.out.println("Could not read property 'edtftp.log.level' due to security permissions");
        }

        globalLevel = Level.getLevel(level);
    }
   
    /**
     * Constructor
     *
     * @param clazz     class this logger is for
     * @param uselog4j  true if using log4j
     */
    private Logger(String clazz, boolean uselog4j) {
        this.clazz = clazz;
        this.useLog4j = uselog4j;
        if (uselog4j)
            setupLog4j();
    }
   
    /**
     * Attempt to set up log4j logging. Of course, the classes
     * must be in the classpath
     */
    private synchronized void setupLog4j() {
        logMethods = new Method[Level.LEVEL_COUNT][2];
        try {
            Class log4jLogger = Class.forName("org.apache.log4j.Logger");
            Class log4jLevel = Class.forName("org.apache.log4j.Level");
            Class log4jPriority = Class.forName("org.apache.log4j.Priority");
           
            // get static logger method & use to get our logger
            Class[] args = { String.class };
            Method getLogger = log4jLogger.getMethod("getLogger", args);
            Object[] invokeArgs = {clazz};
            logger = getLogger.invoke(null, invokeArgs);
           
            // get the logger's methods and store them
            Class[] plainArgs = {Object.class};
            Class[] throwableArgs = {Object.class,Throwable.class};
            logMethods[Level.FATAL_INT][0] = log4jLogger.getMethod("fatal", plainArgs);
            logMethods[Level.FATAL_INT][1] = log4jLogger.getMethod("fatal", throwableArgs);
            logMethods[Level.ERROR_INT][0] = log4jLogger.getMethod("error", plainArgs);
            logMethods[Level.ERROR_INT][1] = log4jLogger.getMethod("error", throwableArgs);
            logMethods[Level.WARN_INT][0] = log4jLogger.getMethod("warn", plainArgs);
            logMethods[Level.WARN_INT][1] = log4jLogger.getMethod("warn", throwableArgs);
            logMethods[Level.INFO_INT][0] = log4jLogger.getMethod("info", plainArgs);
            logMethods[Level.INFO_INT][1] = log4jLogger.getMethod("info", throwableArgs);
            logMethods[Level.DEBUG_INT][0] = log4jLogger.getMethod("debug", plainArgs);
            logMethods[Level.DEBUG_INT][1] = log4jLogger.getMethod("debug", throwableArgs);
           
            // get the toLevel and isEnabledFor methods
            Class[] toLevelArgs = {String.class};
            toLevelMethod = log4jLevel.getMethod("toLevel", toLevelArgs);
            Class[] isEnabledForArgs = {log4jPriority};
            isEnabledForMethod = log4jLogger.getMethod("isEnabledFor", isEnabledForArgs);
        }
        catch (Exception ex) {
            useLog4j = false;
            error("Failed to initialize log4j logging", ex);
        }
    }
   
    /**
     * Returns the logging level for all loggers.
     *
     * @return current logging level.
     */
    public static synchronized Level getLevel() {
        return globalLevel;
    }

    /**
     * Set all loggers to this level
     *
     * @param level  new level
     */
    public static synchronized void setLevel(Level level) {
        globalLevel = level;
    }
   
    /**
     * Get a logger for the supplied class
     *
     * @param clazz    full class name
     * @return  logger for class
     */
    public static Logger getLogger(Class clazz) {
        return getLogger(clazz.getName());
    }
          
    /**
     * Get a logger for the supplied class
     *
     * @param clazz    full class name
     * @return  logger for class
     */
    public static synchronized Logger getLogger(String clazz) {
        clazz = getLoggerPrefix() + clazz;
        Logger logger = (Logger)loggers.get(clazz);
        if (logger == null) {
            boolean useLog4j = false;
            try {
                String log4j = System.getProperty("edtftp.log.log4j");
                if (log4j != null && log4j.equalsIgnoreCase("true")) {
                    useLog4j = true;
                }
            }
            catch (SecurityException ex) {
                System.out.println("Could not read property 'edtftp.log.log4j' due to security permissions");
            }
            logger = new Logger(clazz, useLog4j);
            loggers.put(clazz, logger);
        }
        return logger;
    }
   
    /**
     * Get the prefix for the loggers, or empty string if not set
     *
     * @return logger prefix
     */
    private static String getLoggerPrefix() {
        String prefix = System.getProperty("edtftp.log.prefix");
        return prefix != null ? prefix : "";
    }
   
    /**
     * Add an appender to our list
     *
     * @param newAppender
     */
    public static synchronized void addAppender(Appender newAppender) {
      if (!appenders.contains(newAppender))
        appenders.addElement(newAppender);
    }

    /**
     * Add a file-appender to our list
     *
     * @param fileName Path of file.
     * @throws IOException
     */
    public static synchronized void addFileAppender(String fileName) throws IOException {
      addAppender(new FileAppender(fileName));
    }
   
    /**
     * Add a standard-output appender to our list.
     */
    public static synchronized void addStandardOutputAppender() {
      addAppender(new StandardOutputAppender());
    }
   
    /**
     * Remove an appender to from list
     *
     * @param appender
     */
    public static synchronized void removeAppender(Appender appender) {
      appender.close();
        appenders.removeElement(appender);
    }
  
    /**
     * Clear all appenders
     */
    public static synchronized void clearAppenders() {
        appenders.removeAllElements();
    }
   
    /**
     * Close all appenders
     */
    public static synchronized void shutdown() {
        for (int i = 0; i < appenders.size(); i++) {
            Appender a = (Appender)appenders.elementAt(i);
            a.close();
        }       
    }
   
    /**
     * Set global flag for logging thread names as part of the logger names.
     *
     * @param logThreadNames true if logging thread names, false otherwise
     */
    public static synchronized void logThreadNames(boolean logThreadNames) {
        Logger.logThreadNames = logThreadNames;
    }
   
    /**
     * Set flag for logging thread names as part of the logger names for this instance
     * of the logger.
     *
     * @param logThreadName true if logging thread names, false otherwise
     */
    public synchronized void logThreadName(boolean logThreadName) {
        this.logThreadName = logThreadName;
    }
   
    /**
     * Log a message
     *
     * @param level     log level
     * @param message   message to log
     * @param t         throwable object
     */
    public synchronized void log(Level level, String message, Throwable t) {
      if (isEnabledFor(level))
      {
          if (useLog4j)
              log4jLog(level, message, t);
          else
              ourLog(level, message, t);
      }
    }
   
    /**
     * Calls log4j's isEnabledFor method.
     *
     * @param level logging level to check
     * @return true if logging is enabled
     */
    private boolean log4jIsEnabledFor(Level level)
    {
        if (level.equals(Level.ALL)) // log4j doesn't have an 'ALL' level
            level = Level.DEBUG;

      try
      {
        // convert the level to a Log4j Level object
        Object[] toLevelArgs = new Object[] { level.toString() };
        Object l = toLevelMethod.invoke(null, toLevelArgs);
 
        // call isEnabled
        Object[] isEnabledArgs = new Object[] { l };
        Object isEnabled = isEnabledForMethod.invoke(logger, isEnabledArgs);
       
        return ((Boolean)isEnabled).booleanValue();
        }
        catch (Exception ex) { // there's a few, we don't care what they are
            ourLog(Level.ERROR, "Failed to invoke log4j toLevel/isEnabledFor method", ex);
            useLog4j = false;
            return false;
        }
    }
   
    /**
     * Log a message to log4j
     *
     * @param level     log level
     * @param message   message to log
     * @param t         throwable object
     */
    private void log4jLog(Level level, String message, Throwable t) {
       
        if (level.equals(Level.ALL)) // log4j doesn't have an 'ALL' level
            level = Level.DEBUG;
       
        // set up arguments
        Object[] args = null;
        int pos = -1;
        if (t == null) {
            args = argsPlain;
            pos = 0;
        }
        else {
            args = argsThrowable;
            args[1] = t;
            pos = 1;
        }
        args[0] = message;
       
        // retrieve the correct method
        Method method = logMethods[level.getLevel()][pos];
       
        // and invoke the method
        try {
            method.invoke(logger, args);
        }
        catch (Exception ex) { // there's a few, we don't care what they are
            ourLog(Level.ERROR, "Failed to invoke log4j logging method", ex);
            ourLog(level, message, t);
            useLog4j = false;
        }
    }

    /**
     * Log a message to our logging system
     *
     * @param level     log level
     * @param message   message to log
     * @param t         throwable object
     */
    private void ourLog(Level level, String message, Throwable t) {
        ts.setTime(System.currentTimeMillis());
        String stamp = format.format(ts);
        StringBuffer buf = new StringBuffer(level.toString());
        buf.append(" [");
        if (logThreadNames || logThreadName)
            buf.append(Thread.currentThread().getName()).append("_");
        buf.append(clazz).append("] ").append(stamp).
        append(" : ").append(message);
        if (t != null) {
            buf.append(" : ").append(t.getMessage());
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            t.printStackTrace(pw);
            pw.println();
            buf.append(sw.toString());
        }
        if (appenders.size() == 0) { // by default to stdout
            System.out.println(buf.toString());
            while (t != null) {
                t.printStackTrace(System.out);
                if (t instanceof BaseIOException) {
                  t = ((BaseIOException)t).getInnerThrowable();
                  if (t!=null)
                    System.out.println("CAUSED BY:");
                }
                else
                  t = null;
            }
        }
        else {
            for (int i = 0; i < appenders.size(); i++) {
                Appender a = (Appender)appenders.elementAt(i);
                a.log(buf.toString());
                while (t != null) {
                    a.log(t);
                    if (t instanceof BaseIOException) {
                      t = ((BaseIOException)t).getInnerThrowable();
                      if (t!=null)
                        a.log("CAUSED BY:");
                    }
                    else
                      t = null;
                }
            }
        }
    }
       
    /**
     * Log an info level message
     *
     * @param message   message to log
     */
    public void info(String message)  {
        log(Level.INFO, message, null);
    }
   
    /**
     * Log an info level message
     *
     * @param message   message to log
     * @param t         throwable object
     */
    public void info(String message, Throwable t)  {
        log(Level.INFO, message, t);
    }

    /**
     * Log a warning level message
     *
     * @param message   message to log
     */
    public void warn(String message)  {
        log(Level.WARN, message, null);
    }
   
    /**
     * Log a warning level message
     *
     * @param message   message to log
     * @param t         throwable object
     */
    public void warn(String message, Throwable t)  {
        log(Level.WARN, message, t);
    }
   
    /**
     * Log an error level message
     *
     * @param message   message to log
     */
    public void error(String message)  {
        log(Level.ERROR, message, null);  
    }
   
    /**
     * Log an error level message
     *
     * @param message   message to log
     * @param t         throwable object
     */
    public void error(String message, Throwable t)  {
        log(Level.ERROR, message, t);  
    }
   
    /**
     * Log a fatal level message
     *
     * @param message   message to log
     */
    public void fatal(String message)  {
        log(Level.FATAL, message, null);
    }

    /**
     * Log a fatal level message
     *
     * @param message   message to log
      * @param t         throwable object
    */
    public void fatal(String message, Throwable t)  {
        log(Level.FATAL, message, t);
    }
   
    /**
     * Log a debug level message
     *
     * @param message   message to log
     */
    public void debug(String message)  {
        log(Level.DEBUG, message, null);
    }
   
  private static String hex[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
    "a", "b", "c", "d", "e", "f" };
   
    /**
     * Log a debug level message
     *
     * @param message   message to log
     */
    public void debug(String message, byte[] data)  {
        log(Level.DEBUG, message, null);
    int i;

    StringBuffer hexStr = new StringBuffer();
    StringBuffer charStr = new StringBuffer();
    for (i = 0; i < data.length; i++) {
      byte b = data[i];
      if ((i > 0) && ((i % 12) == 0)) {
        log(Level.DEBUG, hexStr.toString() + "  " + charStr.toString(), null);
        hexStr = new StringBuffer();
        charStr = new StringBuffer();
      }

      hexStr.append(hex[(b >> 4) & 0x0f] + hex[b & 0x0f] + " ");
      charStr.append(b >= ' ' && b <= '~' ? (char)b : '?');
    }

    log(Level.DEBUG, hexStr.toString() + "  " + charStr.toString(), null);
    }
   
    /**
     * Logs by substituting in the argument at the location marked in the message
     * argument by {0}.
     * Additional MessageFormat formatting instructions may be included.  Note that
     * this method saves processing time by not building the complete string unless
     * it is necessary; this saves the need for encapsulating
     * many complete logging statements in an "if (log.isDebugEnabled())" block.
     * @param message Message containing "substitution marks"
     * @param arg argument to be substituted at the marked location.
     */
    public void debug(String message, Object arg)
    {
      if (isDebugEnabled())
        log(Level.DEBUG, MessageFormat.format(message, new Object[]{arg}), null);
    }
   
    /**
     * Logs by substituting in the arguments at the locations marked in the message
     * argument by {#} (where # is a number).
     * Additional MessageFormat formatting instructions may be included.Note that
     * this method saves processing time by not building the complete string unless
     * it is necessary; this saves the need for encapsulating
     * many complete logging statements in an "if (log.isDebugEnabled())" block.
     * @param message Message containing "substitution marks"
     * @param arg0 argument to be substituted at the marked location.
     * @param arg1 argument to be substituted at the marked location.
     */
    public void debug(String message, Object arg0, Object arg1)
    {
      if (isDebugEnabled())
        log(Level.DEBUG, MessageFormat.format(message, new Object[]{arg0, arg1}), null);
    }
   
    /**
     * Logs by substituting in the arguments at the locations marked in the message
     * argument by {#} (where # is a number).
     * Additional MessageFormat formatting instructions may be included.Note that
     * this method saves processing time by not building the complete string unless
     * it is necessary; this saves the need for encapsulating
     * many complete logging statements in an "if (log.isDebugEnabled())" block.
     * @param message Message containing "substitution marks"
     * @param arg0 argument to be substituted at the marked location.
     * @param arg1 argument to be substituted at the marked location.
     * @param arg2 argument to be substituted at the marked location.
     */
    public void debug(String message, Object arg0, Object arg1, Object arg2)
    {
      if (isDebugEnabled())
        log(Level.DEBUG, MessageFormat.format(message, new Object[]{arg0, arg1, arg2}), null);
    }
   
    /**
     * Logs by substituting in the arguments at the locations marked in the message
     * argument by {#} (where # is a number).
     * Additional MessageFormat formatting instructions may be included.Note that
     * this method saves processing time by not building the complete string unless
     * it is necessary; this saves the need for encapsulating
     * many complete logging statements in an "if (log.isDebugEnabled())" block.
     * @param message Message containing "substitution marks"
     * @param arg0 argument to be substituted at the marked location.
     * @param arg1 argument to be substituted at the marked location.
     * @param arg2 argument to be substituted at the marked location.
     * @param arg3 argument to be substituted at the marked location.
     */
    public void debug(String message, Object arg0, Object arg1, Object arg2, Object arg3)
    {
      if (isDebugEnabled())
        log(Level.DEBUG, MessageFormat.format(message, new Object[]{arg0, arg1, arg2, arg3}), null);
    }
   
    /**
     * Logs by substituting in the arguments at the locations marked in the message
     * argument by {#} (where # is a number).
     * Additional MessageFormat formatting instructions may be included.Note that
     * this method saves processing time by not building the complete string unless
     * it is necessary; this saves the need for encapsulating
     * many complete logging statements in an "if (log.isDebugEnabled())" block.
     * @param message Message containing "substitution marks"
     * @param arg0 argument to be substituted at the marked location.
     * @param arg1 argument to be substituted at the marked location.
     * @param arg2 argument to be substituted at the marked location.
     * @param arg3 argument to be substituted at the marked location.
     * @param arg4 argument to be substituted at the marked location.
     */
    public void debug(String message, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4)
    {
      if (isDebugEnabled())
        log(Level.DEBUG, MessageFormat.format(message, new Object[]{arg0, arg1, arg2, arg3, arg4}), null);
    }

    /**
     * Log a debug level message
     *
     * @param message   message to log
     * @param t         throwable object
     */
    public void debug(String message, Throwable t)  {
        log(Level.DEBUG, message, t);
    }
   
    /**
     * Is logging enabled for the supplied level?
     *
     * @param level   level to test for
     * @return true   if enabled
     */
    public synchronized boolean isEnabledFor(Level level) {
      if (useLog4j) {
        return log4jIsEnabledFor(level);
        }
      else
        return globalLevel.isGreaterOrEqual(level);
    }
   
    /**
     * Is logging enabled for the supplied level?
     *
     * @return true if enabled
     */
    public boolean isDebugEnabled() {
        return isEnabledFor(Level.DEBUG);
    }
   
    /**
     * Is logging enabled for the supplied level?
     *
     * @return true if enabled
     */
    public boolean isInfoEnabled()  {
        return isEnabledFor(Level.INFO);
    }
}
TOP

Related Classes of com.enterprisedt.util.debug.Logger

TOP
Copyright © 2015 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.