/*
* 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%";
}
}