Log

From Stack Overflow
Jump to: navigation, search
/*
 * Log.java
 *
 * Created on April 18, 2002, 5:24 PM
 */

package org.ninjasoft.util;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import java.io.PrintStream;
import java.io.ByteArrayOutputStream;
import org.apache.log4j.MDC;

/**
 * Wrapper for log4j configuration and logging.  Log4j will look for the
 * file log4j.properties in your classpath.
 */
public class Log
{
    /** Whether the log4j system has been properly initialize */
    private static boolean initialized = false;
    public static final String MDC_EXCEPTION = "exception";

    /** Cannot instantiate */
    private Log() {}

    /** Initialize the log4j system */
    private static void initialize()
    {
        try{
            // This will search for the log4j configutation file
            new PropertyConfigurator();
            // Check that root logger has been configured, if not set a default config
            Logger root = Logger.getRootLogger();
            if (!root.getAllAppenders().hasMoreElements())
            {
                BasicConfigurator.configure();
                root.setLevel(Level.INFO);
                root.info("log4j.properties not found, using default configuration");
                root.setLevel(Level.ERROR);
            }
        }catch(VerifyError e){
            System.err.println();
            System.err.println("log4j not installed or too old.  Be sure log4j 1.2 or greater is installed.");
            System.err.println("http://jakarta.apache.org/log4j/");
            System.err.println();
            throw e;
        }
        initialized = true;
    }

    /**
     * Log a debug message
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void debug(Object obj, String message)
    {
        log(obj, Level.DEBUG, message);
    }
    
    /**
     * Log a debug message, with binary data
     * @param obj use this object's class name as the category name, or the literal name if a String object
     * @param message message to log
     * @param data binary data to log
     */
    public static void debug(Object obj, String message, byte[] data)
    {
        log(obj, Level.DEBUG, message + "\n" + encode(data));
    }

    /**
     * Log an error message
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void error(Object obj, String message)
    {
        log(obj, Level.ERROR, message);
    }

    /**
     * Log an error message, with binary data
     * @param obj use this object's class name as the category name, or the literal name if a String object
     * @param message message to log
     * @param data binary data to log
     */
    public static void error(Object obj, String message, byte[] data)
    {
        log(obj, Level.ERROR, message + "\n" + encode(data));
    }
    
    /**
     * Log an info message
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void info(Object obj, String message)
    {
        log(obj, Level.INFO, message);
    }
    
    /**
     * Log an info message, with binary data
     * @param obj use this object's class name as the category name, or the literal name if a String object
     * @param message message to log
     * @param data binary data to log
     */
    public static void info(Object obj, String message, byte[] data)
    {
        log(obj, Level.INFO, message + "\n" + encode(data));
    }

    /**
     * Log a warning message
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void warn(Object obj, String message)
    {
        log(obj, Level.WARN, message);
    }

    /**
     * Log a warning message, with binary data
     * @param obj use this object's class name as the category name, or the literal name if a String object
     * @param message message to log
     * @param data binary data to log
     */
    public static void warn(Object obj, String message, byte[] data)
    {
        log(obj, Level.WARN, message + "\n" + encode(data));
    }
    
    /**
     * Log a fatal message
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void fatal(Object obj, String message)
    {
        log(obj, Level.FATAL, message);
    }

    /**
     * Log a fatal message, with binary data
     * @param obj use this object's class name as the category name, or the literal name if a String object
     * @param message message to log
     * @param data binary data to log
     */
    public static void fatal(Object obj, String message, byte[] data)
    {
        log(obj, Level.FATAL, message + "\n" + encode(data));
    }
    
    /**
     * Log a debug message, tied to a Throwable object
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void debug(Object obj, String message, Throwable throwable)
    {
        log(obj, Level.DEBUG, message, throwable);
        flagException (throwable );
    }

    /**
     * Log an error message, tied to a Throwable object
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void error(Object obj, String message, Throwable throwable)
    {
        log(obj, Level.ERROR, message, throwable);
        flagException (throwable );
    }

    /**
     * Log an info message, tied to a Throwable object
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void info(Object obj, String message, Throwable throwable)
    {
        log(obj, Level.INFO, message, throwable);
        flagException (throwable );
    }

    /**
     * Log a warn message, tied to a Throwable object
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void warn(Object obj, String message, Throwable throwable)
    {
        log(obj, Level.WARN, message, throwable);
        flagException (throwable );
    }

    /**
     * Log a fatal message, tied to a Throwable object
     *@parm obj use this object's class name as the category name, or the literal name if a String object
     *@param message message to log
     */
    public static void fatal(Object obj, String message, Throwable throwable)
    {
        log(obj, Level.FATAL, message, throwable);
        flagException (throwable );
    }

    /**
     * Log a message in the log4j system
     *@param obj use this object's class name as the category name, of the literal name if a String
     *@param level log level to use
     *@param message the message to log
     *@param throwable the Throwable object to log with the message
     */
    private static void log(Object obj, Level level, String message)
    {
        if (!initialized) initialize();
        if (obj instanceof String)
            Logger.getLogger((String)obj).log(level, message);
        else
            Logger.getLogger(obj.getClass()).log(level, message);
    }

    /**
     * Log a message tied to a Throwable object in the log4j system
     *@param obj use this object's class name as the category name, of the literal name if a String
     *@param level log level to use
     *@param message the message to log
     *@param throwable the Throwable object to log with the message
     */
    private static void log(Object obj, Level level, String message, Throwable throwable)
    {
        if (!initialized) initialize();
        if (obj instanceof String)
            Logger.getLogger((String)obj).log(level, message, throwable);
        else
            Logger.getLogger(obj.getClass()).log(level, message, throwable);

		flagException (throwable );
    }

    public static void main(String[] argv)
    {
        Log.error(new java.util.Hashtable(), "Logger test1");
        Log.error(new java.util.Hashtable(), "Logger test2", new RuntimeException("My Exception1"));
        Log.error("com.certivo.test.of.logger", "Logger test3");
        Log.error("com.certivo.test.of.logger", "Logger test4", new RuntimeException("My Exception2"));
        Log.debug("com.certivo.debug", "Logger test5, this may be ignored");
    }

    /**
     *  returns true if debug is enabled for this object
     *
     *  @returns true/false
     */
    public static boolean isDebugEnabled(Object obj){
       Logger theLogger = null;
       if (obj instanceof String){
           theLogger = Logger.getLogger((String)obj);
       }
       else{
           theLogger = Logger.getLogger(obj.getClass());
       }

       return theLogger.isDebugEnabled();
    }

    public static void flagException ( Throwable t )
    {
        // add throwable to MDC context
        if ( t != null )
        {
			MDC.put(MDC_EXCEPTION,t);
		}
	}
    
    /**
     * Perform a basic HTTP URL-Encoded encoding.  This allows us to escape the binary
     * characters, yet still be able to see any embedded ASCII characters. 
     * @param b the binary block to encode
     * @return the encoded/escaped binary data as a string
     */
    private static String encode(byte[] b) {
        StringBuffer result = new StringBuffer();
        int pos = 1;
        boolean needsEncoding = false;
        // First, check if it even NEEDS encoding.  If it consists of
        // strictly printable characters, we can just dump those
        // verbatim (and this will increase readibility in the
        // logs because the CRLF's are not going to be escaped).
        for (int i=0; i<b.length; i++) {
            int binaryCharacter = (int) b[i];
            if (binaryCharacter < 0)
                binaryCharacter += 255;
            if (((binaryCharacter < 0x20) || (binaryCharacter > 0x7e))
                 && (binaryCharacter != 0x0a) && (binaryCharacter != 0x0d)) {
                needsEncoding = true;
                break;
            }
            result.append((char) binaryCharacter);
        }
        if (!needsEncoding)
            return "%TEXTBEGIN%\n" + result.toString() + "\n%TEXTEND%";
        result = new StringBuffer();
        // It looks like there are characters needing encoding.  The encoding
        // is done below...
        for (int i=0; i<b.length; i++) {
            int binaryCharacter = (int) b[i];
            if (binaryCharacter < 0)
                binaryCharacter += 256;
            if ((binaryCharacter >= 0x20) && (binaryCharacter <= 0x7e) && (binaryCharacter != 0x25)) {
                result.append((char) binaryCharacter);
                pos++;
            }else{
                result.append("%");
                String hex = Integer.toString(binaryCharacter, 16);
                if (hex.length() == 1)
                    hex = "0" + hex;
                result.append(hex);
                pos += 3;
            }
            if (pos >= 80) {
                result.append("\n");
                pos = 1;
            }
        }
        return "%BINARYBEGIN%\n" + result.toString() + "\n%BINARYEND%";
    }
}
Personal tools