package com.quadcap.util;
/* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
*
* This software is distributed under the Quadcap Free Software License.
* This software may be used or modified for any purpose, personal or
* commercial. Open Source redistributions are permitted. Commercial
* redistribution of larger works derived from, or works which bundle
* this software requires a "Commercial Redistribution License"; see
* http://www.quadcap.com/purchase.
*
* Redistributions qualify as "Open Source" under one of the following terms:
*
* Redistributions are made at no charge beyond the reasonable cost of
* materials and delivery.
*
* Redistributions are accompanied by a copy of the Source Code or by an
* irrevocable offer to provide a copy of the Source Code for up to three
* years at the cost of materials and delivery. Such redistributions
* must allow further use, modification, and redistribution of the Source
* Code under substantially the same terms as this license.
*
* Redistributions of source code must retain the copyright notices as they
* appear in each source code file, these license terms, and the
* disclaimer/limitation of liability set forth as paragraph 6 below.
*
* Redistributions in binary form must reproduce this Copyright Notice,
* these license terms, and the disclaimer/limitation of liability set
* forth as paragraph 6 below, in the documentation and/or other materials
* provided with the distribution.
*
* The Software is provided on an "AS IS" basis. No warranty is
* provided that the Software is free of defects, or fit for a
* particular purpose.
*
* Limitation of Liability. Quadcap Software shall not be liable
* for any damages suffered by the Licensee or any third party resulting
* from use of the Software.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;
import java.util.Hashtable;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import com.quadcap.sql.file.DatafileException;
/**
* Common functions for debug and log output.
*
* @author Stan Bailes
*/
public class Debug {
static public PrintStream debugStream = System.out;
static public int printLevel = 0;
private static String debugFileName = null;
private static FileOutputStream debugFileStream = null;
static Hashtable debugMap = new Hashtable();
static NullSecurityManager sm = null;
static public final int debugOff = 0;
static public final int debugSome = 1;
static public final int debugAll = 3;
static public final int debugPackage = 4;
static public int debugMode = debugAll;
static public final int debugNoTime = 0;
static public final int debugElap = 1;
static public final int debugInterval = 2;
static public final int debugShowTime = 3;
static public int debugTime = debugShowTime;
static public long start = new Date().getTime();
static public long last = start;
static SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
/*{com.quadcap.util.Config-vars.xml-0}
*
* <config>
*/
/*{com.quadcap.util.Config-vars.xml-999999}
*
* </config>
*/
/*{com.quadcap.util.Config-vars.xml-10}
*
* <config-var>
* <config-name>debug.file</config-name>
* <config-dflt>stderr</config-dflt>
* <config-desc>Specify the name of the debug log file. The default
* value, <code>stderr</code>, causes debug information to
* be written to <code>System.err</code>.</config-desc>
* </config-var>
*
* <config-var>
* <config-name>debug.level</config-name>
* <config-dflt>0</config-dflt>
* <config-desc>Specify the level of debugging output. Level zero,
* the lowest level, essentially turns debug output off (though
* errors/exceptions will still be reported.) Increasing levels
* will result in more debug output. The maximum debug level is
* five (5).</config-desc>
* </config-var>
*/
static {
//System.setSecurityManager(sm = new NullSecurityManager());
try {
ConfigString file = ConfigString.find("debug.file", "stderr");
if (file != null) {
setLogFile(file.toString());
}
ConfigNumber level = ConfigNumber.find("debug.level", "0");
if (level != null) {
printLevel = level.intValue();
}
} catch (IOException e) {
Debug.print(e);
}
}
static public Class[] getClassContext() {
return sm.pubGetClassContext();
}
static public void setDebugLevel(String name, String level) {
debugMap.put(name, level);
}
static public void print(Throwable e) {
if (e == null) return;
if (!(e instanceof SQLException)) {
Debug.println(0, 2, e.getClass().getName());
}
debugStream.print(hdr());
e.printStackTrace(debugStream);
if (e instanceof SQLException) {
printSQLException((SQLException)e);
} else if (e.getCause() != null) {
Debug.println("Cause of this exception:");
print(e.getCause());
}
}
static void printSQLException(SQLException e) {
StringBuffer sb = new StringBuffer(e.toString());
int idx;
while ((idx = sb.toString().indexOf("Exception:")) >= 0) {
sb.setCharAt(idx + 9, ',');
}
Debug.println(0, 3, sb.toString() + ", SQLState = " + e.getSQLState() +
", errorCode = " + e.getErrorCode());
SQLException next = e.getNextException();
if (next != null) {
Debug.println("Next SQL Exception:");
printSQLException(next);
} else if (e.getCause() != null) {
Debug.println("Cause of this exception:");
print(e);
}
}
static public void println(String s) {
println(0, 1, s);
}
static public String getInterval() {
String ret = null;
Date d = new Date();
long now = d.getTime();
switch (debugTime) {
case debugInterval:
ret = "" + (now - last);
last = now;
break;
case debugElap:
ret = "" + (now - start);
break;
case debugShowTime:
ret = "" + sdf.format(d);
break;
}
return ret;
}
/**
* Specify the file to be used for debug/log output. If there is
* already a debug file open with a different name, it is closed first,
* and if the name specified is <code>"stdout"</code>, then debug
* output is directed to <code>System.out</code>.
*
* @param name the name of the debug log file.
* @exception IOException may be thrown.
*/
static public void setLogFile(String name) throws IOException {
if (name.equals("stdout")) {
if (debugFileStream != null) {
debugFileStream.close();
debugFileStream = null;
}
debugStream = System.out;
} else if (name.equals("stderr")) {
if (debugFileStream != null) {
debugFileStream.close();
debugFileStream = null;
}
debugStream = System.err;
} else {
boolean append = name.startsWith("append:");
if (append) name = name.substring(7).trim();
name = new File(name).getAbsolutePath();
if (debugFileName == null || !name.equals(debugFileName)) {
debugFileName = name;
if (debugFileStream != null) {
debugFileStream.close();
debugFileStream = null;
}
debugFileStream = new FileOutputStream(name, append);
debugStream = new PrintStream(debugFileStream);
println("---- [Debug started]");
}
}
}
/**
* Specify the 'level' for debugging output. Only debug statements
* satisfying <code>level <= printLevel</code> result in output.
*
* @param printLevel the new debug output level.
*/
static public void setLogLevel(int printLevel) {
if (printLevel != Debug.printLevel) {
Debug.println(0, "Changing log level from " + Debug.printLevel +
" to " + printLevel);
Debug.printLevel = printLevel;
}
}
/**
* Specify the debug mode using the convenient string representation
*
* @param mode the debug mode.
*/
static public void setDebugMode(String mode) {
if (mode.equals("off")) {
Debug.debugMode = Debug.debugOff;
} else if (mode.equals("some")) {
Debug.debugMode = Debug.debugSome;
} else if (mode.equals("all")) {
Debug.debugMode = Debug.debugAll;
} else if (mode.equals("package")) {
Debug.debugMode = Debug.debugPackage;
}
}
/**
* Debug output at level <code>level</code>.
*/
static synchronized public void println(int level, String s) {
println(level, 1, s);
}
static String hdr() {
StringBuffer sb = new StringBuffer();
if (debugTime != debugNoTime) {
sb.append(getInterval());
sb.append(": ");
}
sb.append("[");
sb.append(Thread.currentThread().getName());
sb.append("] ");
return sb.toString();
}
/**
* Debug output at level <code>level</code>.
*/
static synchronized public void println(int level, int depth, String s) {
if (level > printLevel) return;
debugStream.print(hdr());
if (sm != null) {
String className = debugSite(level, depth+1);
debugStream.print(className + ": ");
}
debugStream.println(s);
}
static String debugSite(int level, int depth) {
if (debugMode == debugOff || level > printLevel) return null;
boolean print = true;
Class[] classes = sm.pubGetClassContext();
String className = "";
String packageName = "";
if (classes.length > 2 + depth) {
Class caller = classes[2 + depth];
className = caller.getName();
int pos = className.lastIndexOf('.');
if (pos >= 0) {
packageName = className.substring(0, pos);
className = className.substring(pos+1);
}
}
String debugVal;
switch (debugMode) {
case debugSome:
debugVal = (String)debugMap.get(className);
if (debugVal != null && level <= Integer.parseInt(debugVal)) {
print = debugMode == debugSome;
}
break;
case debugPackage:
debugVal = (String)debugMap.get(packageName);
if (debugVal != null && level <= Integer.parseInt(debugVal)) {
print = debugMode == debugPackage;
}
break;
}
if (print) return className;
return null;
}
}
|