package jef.common.log;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jef.common.Entry;
import jef.tools.ArrayUtils;
import jef.tools.JefConfiguration;
import jef.tools.JefConfiguration.Item;
import jef.tools.StringUtils;
import jef.tools.XMLUtils;
import jef.tools.io.StringBuilderWriter;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
/**
* This class provides a logging facility. Each message is logged with a
* priority allowing the log to be configured to filter out log messages that
* are below a certain priority.
*/
public class LogUtil {
public static List<Writer> otherStream;
private static org.slf4j.Logger log = LoggerFactory.getLogger("GeeQuery");
//是否将输出改为日志形式输出
public static boolean useSlf4j = JefConfiguration.getBoolean(Item.COMMON_DEBUG_ADAPTER, true);
//是否为调试模式
public static boolean debug = JefConfiguration.getBoolean(Item.DB_DEBUG, false);
//将标志输出替换,从而实现System.out.print重定向到日志。
static {
if(useSlf4j){
boolean redirect = JefConfiguration.getBoolean(Item.SYSOUT_REDIRECT, false);
try {
//是否使用控制台输出重定向到到Logger的功能
log.info("=== The System.out.redirect function is "+(redirect?"Enabled.":"Disabled."));
if(redirect && !(System.out instanceof LogPrintStream)){
org.slf4j.Logger ll=LoggerFactory.getLogger("SYSTEM");
PrintStream sysout=new LogPrintStream(ll,false,System.out);
PrintStream syserr=new LogPrintStream(ll,true,System.err);
System.setOut(sysout);
System.setErr(syserr);//将系统的标准输出替换为自己的输出
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
*
* @param value
* @return
*/
public static void appendBytesString(StringBuilder sb,byte[] value){
sb.append(" -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F\r\n");
int left=value.length;
int i=0;
try{
while(left>16){
String name=Integer.toHexString(i);
int offset=i*16;
name=StringUtils.leftPad(name, 7,'0').concat("0: ");
sb.append(name).append(StringUtils.join(value, ' ',offset,16)).append(" ; ");
String text=new String(value,offset,16,"ISO-8859-1");
text=StringUtils.replaceChars(text, "\r\n\t", "...");
sb.append(text);
sb.append("\r\n");
left-=16;
i++;
}
if(left>0){
int offset=i*16;
String name=Integer.toHexString(i);
name=StringUtils.leftPad(name, 7,'0').concat("0: ");
sb.append(name).append(StringUtils.join(value, ' ',offset,16));
for(int x=left;x<16;x++){
sb.append(" ");
}
String text=new String(value,offset,left,"ISO-8859-1");
text=StringUtils.replaceChars(text, "\r\n\t", "...");
sb.append(" ; ").append(text);
}
}catch(UnsupportedEncodingException e){
//NEVER Happens
e.printStackTrace();
}
}
/**
* 添加一个输出流
*
* @param p
*/
public static void addOutput(Writer p) {
if (p == null)
return;
synchronized (LogUtil.class) {
if (otherStream == null){
otherStream = new ArrayList<Writer>();
}else if(otherStream.contains(p)){
return;
}
otherStream.add(p);
}
}
/**
* 删除一个输出流
*
* @param p
*/
public static void removeOutput(Writer p) {
if (p == null)
return;
synchronized (LogUtil.class) {
otherStream.remove(p);
}
}
public static void fatal(Object o) {
String msg=toString(o);
if(useSlf4j){
log.error(msg);
}else{
System.err.println(msg);
}
showToOnthers(msg, true);
}
public static void error(Object o) {
if(useSlf4j){
if(log.isErrorEnabled()){
String msg=toString(o);
log.error(msg);
showToOnthers(msg, true);
}
}else{
String msg=toString(o);
System.err.println(msg);
showToOnthers(msg, true);
}
}
public static void error(String s,Object... o) {
log.error(s,o);
}
/**
* 以标准的slf4j的格式输出warn
* @param s
* @param o
*/
public static void warn(String s,Object... o) {
log.warn(s,o);
}
/**
* 以标准的slf4j的格式输出info
* @param s
* @param o
*/
public static void info(String s,Object... o){
log.info(s,o);
}
/**
* 以标准的slf4j的格式输出debug
*/
public static void debug(String s,Object... o){
log.debug(s,o);
}
public static void warn(Object o) {
if(useSlf4j){
if(log.isWarnEnabled()){
String msg=toString(o);
log.warn(msg);
showToOnthers(msg, true);
}
}else {
String msg=toString(o);
System.err.println(msg);
showToOnthers(msg, true);
}
}
public static void info(Object o) {
if(useSlf4j){
if(log.isInfoEnabled()){
String msg=toString(o);
log.info(msg);
showToOnthers(msg, true);
}
}else{
String msg=toString(o);
System.out.println(msg);
showToOnthers(msg, true);
}
}
/**
* 将指定的对象显示输出
* @param objs
*/
public static void shows(Object... objs) {
info(objs);
}
public static void show(ResultSet rs) {
try{
show((Object)rs);
}finally{
try {
rs.close();
} catch (SQLException e) {
}
}
}
/**
* 将指定的对象显示输出
* @param o
*/
public static void show(Object o) {
info(o);
}
public static void debug(Object o) {
if(useSlf4j){
if(log.isDebugEnabled()){
String msg=toString(o);
log.debug(msg);
showToOnthers(msg, true);
}
}else if(debug){
String msg=toString(o);
System.out.println(msg);
showToOnthers(msg, true);
}
}
/**
* 将异常异常堆栈打入日志
* 改起来影响比较大,所以就不改了。
* @param t
*/
public static void exception(Throwable t){
log.error("",t);
if (otherStream != null && !otherStream.isEmpty()) {
showToOnthers(StringUtils.exceptionStack(t), true);
}
}
/**
* 将异常信息输入日志
* @param message
* @param t
*/
public static void exception(String message,Throwable t){
log.error(message, t);
if (otherStream != null && !otherStream.isEmpty()) {
showToOnthers(StringUtils.exceptionStack(t), true);
}
}
/**
* 將各种对象轉換為文本
*
* @param o
*/
@SuppressWarnings("rawtypes")
public static void toString(Object o, StringBuilder sb) {
if (o == null){
return;
}
Class<?> c = o.getClass();
if (c==String.class) {
sb.append( (String) o);
} else if (c.isArray()) {
if (c.getComponentType() == Byte.TYPE) {//如果是byte[],就打印出像UltraEdit的二进制文件编辑那种数据对照格式
sb.append("ByteArray:\n");
appendBytesString(sb,(byte[])o);
} else if (c.getComponentType().isPrimitive()) {
StringUtils.joinTo(ArrayUtils.toObject(o), ' ', sb);
} else {
Object[] objs=(Object[]) o;
if(objs.length==0)return;
sb.append(objs[0]);
for(int i=1;i<objs.length;i++){
sb.append('\n').append(objs[i]);
}
}
} else if (o instanceof Iterable<?>) {
Iterator iter=((Iterable) o).iterator();
if(iter.hasNext()){
sb.append(iter.next());
for (;iter.hasNext();) {
sb.append('\n').append(iter.next());
}
}
} else if (o instanceof Enumeration<?>) {
Enumeration enu=(Enumeration)o;
if(enu.hasMoreElements()){
sb.append(enu.nextElement());
for(;enu.hasMoreElements();){
sb.append('\n').append(enu.nextElement());
}
}
} else if (o instanceof Map<?, ?>) {
Map map = (Map) o;
@SuppressWarnings("unchecked")
Iterator<Map.Entry> iter=map.entrySet().iterator();
if(iter.hasNext()){
Map.Entry e=iter.next();
sb.append(StringUtils.rightPad(StringUtils.toString(e.getKey()), 18)).append('\t').append(toString(e.getValue()));
for (;iter.hasNext();) {
e=iter.next();
sb.append('\n').append(StringUtils.rightPad(StringUtils.toString(e.getKey()), 18)).append('\t').append(toString(e.getValue()));
}
}
} else if (o instanceof Node) {
try {
XMLUtils.output((Node)o, new StringBuilderWriter(sb), null, 4);
} catch (IOException e) {
e.printStackTrace();
sb.append(o);
}
} else if (o instanceof Entry<?, ?>) {
Entry<?, ?> e = (Entry<?, ?>) o;
sb.append(StringUtils.rightPad(StringUtils.toString(e.getKey()), 18)).append('\t').append(toString(e.getValue()));
} else if (o instanceof Throwable) {
StringUtils.exceptionSummary((Throwable) o, sb);
} else {
sb.append(StringUtils.toString(o));
}
}
public static CharSequence toString(String head,byte[] b){
StringBuilder sb=new StringBuilder(head.length()+b.length*4+16);
sb.append(head);
appendBytesString(sb, b);
return sb;
}
//不关闭
private static String toString(ResultSet rs) throws SQLException {
StringBuilder sb=new StringBuilder(64);
int limit=JefConfiguration.getInt(Item.CONSOLE_SHOW_RESULT_LIMIT, 200);
ResultSetMetaData meta=rs.getMetaData();
int count=meta.getColumnCount();
sb.append(meta.getColumnLabel(1));
for(int i=2;i<=count;i++){
sb.append(", ");
sb.append(meta.getColumnLabel(i));
}
sb.append('\n');
int size=0;
while(rs.next()){
size++;
sb.append('[');
sb.append(rs.getObject(1));
for(int i=2;i<=count;i++){
sb.append(", ");
sb.append(rs.getObject(i));
}
sb.append("]\n");
if(limit==size){//No need to print...
while(rs.next()){
size++;
}
break;
}
}
sb.append("Total:").append(size).append(" record(s).");
return sb.toString();
}
private static String toString(Object object) {
if(object==null)return "";
@SuppressWarnings("rawtypes")
Class clz=object.getClass();
if(clz==String.class)return (String)object;
if(object.getClass().isArray() || Collection.class.isAssignableFrom(clz) || Enumeration.class.isAssignableFrom(clz)||Node.class.isAssignableFrom(clz)||Map.class.isAssignableFrom(clz)){
StringBuilder sb=new StringBuilder();
toString(object, sb);
return sb.toString();
}else if(object instanceof Throwable){
StringBuilder sb=new StringBuilder();
toString(object, sb);
return sb.toString();
}else if(object instanceof ResultSet){
ResultSet rs=(ResultSet)object;
try{
return toString(rs);
}catch(SQLException e){
throw new RuntimeException(e);
}
}else{
return StringUtils.toString(object);
}
}
public static void showToOnthers(String msg, boolean withNewLine) {
if (otherStream != null) {
for (Iterator<Writer> iter = otherStream.iterator(); iter.hasNext();) {
Writer out = iter.next();
try {
if (withNewLine) {
out.write(msg);
out.write(StringUtils.CRLF_STR);
} else {
out.write(msg);
}
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.print("Will not send display message to " + out.toString());
iter.remove();
}
}
}
}
public static Writer[] getOtherOutput() {
Writer[] r = new Writer[0];
if (otherStream == null)
return r;
return otherStream.toArray(r);
}
public static boolean isDebugEnabled() {
return log.isDebugEnabled();
}
}