分享
 
 
 

enoeht的Java源码系列(6)--调试信息与日志文件

王朝java/jsp·作者佚名  2006-01-30
窄屏简体版  字體: |||超大  

在程序中我们常常用System.out.println来输出调试信息,方便且简单,但是往往是因为它太简单、太方便了,以致于让我们需要用一个更强大更灵活的方法来替代它,这篇文章的目的就是提供了一个这样的方法。

在我的开发过程中,我会对输出的调试信息有这样的期望:在开发的时候,输出大量的细节信息让我能很方便的调试,而到了发布的时候,不用改任何代码,就能让程序只去显示客户会感兴趣的信息;同样不需要改动代码,就能让调试信息输出到屏幕、文件、甚至套接字里;除了可以输出调试信息外,还可以输出这条调试信息所在的类和行数能让我很快的定位。

package org.kyle.util;

import java.util.logging.*;

import java.util.Date;

import java.io.IOException;

import java.text.SimpleDateFormat;

public class Debug

{

private static Logger logger;

/**

* handler stores three handle, console, file and socket.

*/

private static Handler[] handler = new Handler[3];

/**

* specify the console logger.

*/

public static final int CONSOLE = 0;

/**

* specify the file logger.

*/

public static final int FILE = 1;

/**

* specify the socket logger.

*/

public static final int SOCKET = 2;

/**

* Return a handler's logging Level.

* @param hIdx must be one of CONSOLE,FILE or SOCKET.

* @return Level the Level of designated Handler. null if the index is invalid.

*/

public static Level getLevel(int hIdx)

{

switch(hIdx)

{

case CONSOLE:

case FILE:

case SOCKET:

return handler[hIdx].getLevel();

default:

return null;

}

}

/**

* show the finest message. You can print any unused message such as "i=5". We never give

* these messages to customers. And we seldom rely finest messages to check errors. Just feel

* free to use finest at any code line when you are in programing. Note: finest messges may

* be removed by any others without prior inform.

*/

public static void finest(Object obj)

{

if( obj instanceof Throwable)

{

logger.finest(getExceptionStack((Throwable)obj));

}

else

logger.finest((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the finer message. These messages are minor useful than fine.

*/

public static void finer(Object obj)

{

if( obj instanceof Throwable)

{

logger.finer(getExceptionStack((Throwable)obj));

}

else

logger.finer((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the fine message. A lot of correct operation can be written down. For example, receive

* a RAW pdu from remote computer, receive or send some message from/to internet. Fine level is

* only for inner use. Detail messages which could help developper find out problems. When we

* shipped the products to customer, developper could use fine or finer level for remote debugging.

*/

public static void fine(Object obj)

{

if( obj instanceof Throwable)

{

logger.fine(getExceptionStack((Throwable)obj));

}

else

logger.fine((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the config message. Some correct operation but worth to record. Such as an administrator

* changes some environment, logged on or off, system startup or receive some commands

* from authentication server, etc.

* Detail log such as a successful call or shutdown should use fine level.

*/

public static void config(Object obj)

{

if( obj instanceof Throwable)

{

logger.config(getExceptionStack((Throwable)obj));

}

else

logger.config((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the info message. Some important message should be print out. For example, register fails

* or call fails.

*/

public static void info(Object obj)

{

if( obj instanceof Throwable)

{

logger.info(getExceptionStack((Throwable)obj));

}

else

logger.info((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the warning message. Most error message such socket lost or connection fail should use this method.

* If the socket lost, some operate may can not continue.

* Only ocaasional errors can be print out by this methods. If we can't resolve a problem and it happens

* frequently, we use info instead of warning.

* Waring level is the default level in the final release when this product is shipped to customers.

* While if customers wants to see logs, we show them Config level.

* Developpers should be careful with the spelling or grammer errors in level bigger than Config level.

*/

public static void warning(Object obj)

{

if( obj instanceof Throwable)

{

logger.warning(getExceptionStack((Throwable)obj));

}

else

logger.warning((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* show the severe message, which may cause system exit or cause error. RuntimeException is the

* most common severe message. All severe messages must be resolved by administrator or developper.

*/

public static void severe(Object obj)

{

if( obj instanceof Throwable)

{

logger.severe(getExceptionStack((Throwable)obj));

}

else

logger.severe((obj == null ? "Logging message object is null" : obj.toString() ));

}

/**

* add a console Handler. You can remove it by using removeHandler();

* @see #removeHandler

*/

public static void addConsoleHandler()

{

if (handler[CONSOLE] != null) return;

handler[CONSOLE] = new ConsoleHandler();

addhandler(handler[CONSOLE]);

}

/**

* add a file Handler. You can remove it by using removeHandler();

* @param filename The log file name.

* @see #removeHandler

*/

public static void addFileHandler(String filename)

{

if (handler[FILE] != null) return;

try{

handler[FILE] = new FileHandler(filename, 500000, 1000, true);

addhandler(handler[FILE]);

}catch(IOException ioe){

warning("Can't open log file: " + filename);

}

}

/**

* add a socket Handler. You can remove it by using removeHandler();

* @param host The remote log server address.

* @param port The remote log server port.

* @see #removeHandler

*/

public static void addSocketHandler(String host, int port)

{

if (handler[SOCKET] != null) return;

try{

handler[SOCKET] = new SocketHandler(host, port);

addhandler(handler[SOCKET]);

}catch(IOException ioe){

warning("Can't connect to log socket: " + host + ":" + port);

}

}

private static void addhandler(Handler handler)

{

handler.setFormatter(new ComplexFormatter());

logger.addHandler(handler);

adjustLoggerLevel();

}

/**

* remove Handler. You can add a handler also.

* @see #addConsoleHandler()

* @see #addFileHandler

* @see #addSocketHandler

*/

public static void removeHandler(int handler_index)

{

if (handler[handler_index] == null) return;

logger.removeHandler(handler[handler_index]);

handler[handler_index] = null;

adjustLoggerLevel();

}

/**

* set handler log level.

* @param handler_index The log handler type.

* @param level The log handler level.

* @see #CONSOLE

* @see #FILE

* @see #SOCKET

* @see Level

*/

public static void setLevel(int handler_index, Level level)

{

if (handler[handler_index] == null) return;

handler[handler_index].setLevel(level);

adjustLoggerLevel();

}

public static void setFormatter(int handler_idx, Formatter nFormatter)

{

try

{

if(handler[handler_idx] == null) return;

handler[handler_idx].setFormatter(nFormatter);

}

catch(Exception e)

{

finest(e);

}

}

private static void adjustLoggerLevel()

{

Level logLevel = Level.OFF;

for (int i=0; i

{

if (handler[i] != null && handler[i].getLevel().intValue() < logLevel.intValue())

logLevel = handler[i].getLevel();

}

logger.setLevel(logLevel);

}

/**

* enable or disable handler log trace.

* @param handler_index The log handler type.

* @param trace enable/disable trace.

* @see #CONSOLE

* @see #FILE

* @see #SOCKET

*/

public static void setTrace(int handler_index, boolean trace)

{

if (handler[handler_index] != null)

((ComplexFormatter)handler[handler_index].getFormatter()).m_trace = trace;

}

/**

* enable or disable handler log time.

* @param handler_index The log handler type.

* @param time enable/disable time.

* @see #CONSOLE

* @see #FILE

* @see #SOCKET

*/

public static void setTime(int handler_index, boolean time)

{

if (handler[handler_index] != null)

((ComplexFormatter)handler[handler_index].getFormatter()).m_time = time;

}

/**

* enable or disable handler log tip.

* @param handler_index The log handler type.

* @param tip enable/disable tip.

* @see #CONSOLE

* @see #FILE

* @see #SOCKET

*/

public static void setTip(int handler_index, boolean tip)

{

if (handler[handler_index] != null)

((ComplexFormatter)handler[handler_index].getFormatter()).m_tip = tip;

}

static private class ComplexFormatter extends Formatter

{

private boolean m_trace = false;

private boolean m_time = false;

private boolean m_tip = false;

public ComplexFormatter()

{

}

public String format(LogRecord record)

{

StringBuffer message = new StringBuffer();

if (m_time)

message.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(new Date(record.getMillis())));

if (m_tip)

message.append(record.getLevel().toString() + ":");

message.append(formatMessage(record));

message.append("\n");

if (m_trace)

{

Throwable e = new Throwable();

StackTraceElement[] elements = e.getStackTrace();

String srcClass = record.getSourceClassName();

StringBuffer buf = new StringBuffer();

int i=0;

while (!srcClass.equals(elements[i].getClassName())) i++;

for (int j= i+1; j

buf.append("At: "+elements[j].toString()+"\n");

message.append(buf);

}

return message.toString();

}

}

public static String getExceptionStack(Throwable e)

{

StackTraceElement[] elements = e.getStackTrace();

StringBuffer buf = new StringBuffer(e.toString()+"\n");

int i=0;

for (int j= 0; j

buf.append("At: "+elements[j].toString()+"\n");

return buf.toString();

}

static

{

logger = Logger.getAnonymousLogger();

logger.setUseParentHandlers(false);

handler[CONSOLE] = new ConsoleHandler();

handler[CONSOLE].setFormatter(new ComplexFormatter());

logger.addHandler(handler[CONSOLE]);

}

public static void main(String[] arg) throws Exception

{

setLevel(Debug.CONSOLE, Level.ALL);

addConsoleHandler();

addFileHandler("ab");

setLevel(Debug.FILE, Level.FINE);

addSocketHandler("localhost", 200);

setLevel(Debug.SOCKET, Level.CONFIG);

removeHandler(Debug.FILE);

setTime(Debug.CONSOLE, true);

setTip(Debug.CONSOLE, false);

setTrace(Debug.CONSOLE, false);

finest("finest");

finer("finer");

fine("fine");

config("config");

info("info");

warning("warning");

severe("severe");

}

}

注:当用setLevel把Level设为CONFIG时,就只有比CONFIG级别高的INFO,WARNING,SERVERE会输出。关于Level的详细信息,可参考JDK文档->java.util.logging->Class Level。

建议:

severe: 非常严重且不能自行恢复的错误,每个独立的线程最外层至少要捕获,RuntimeException异常可以用severe输出,因为这类错误必须在开发阶段保证不会出现。

warning: 严重的错误,可能会导致程序处理不正确,只有不频繁发生的错误才可以用warning输出。经常性的错误应该在程序中自动处理,如服务器连接不上等情况,应该用低一级的输出。

info, config: 一些应当提示的重要信息,如启动、停止一些主要服务,不成功或异常的连接等。

fine,finer,finest: 调试信息,其中fine显示一些有用的信息。

另外一些注意事项:

1 severe,warning,info,config四级尽量避免使用fail,exception等词语,且应当保证语法、拼写正确。这几级是可能被客户看到的。如 "connection lost"可以用"connection stopped"这样中性的词语代替。

2不要用Exception.printStackTrace()函数,如需要调试可以调用Debug.fine(Exception)或Debug.finest(Exception)。

3任何情况下,不要提交会导致刷屏的输出调试信息,如每读到一个数据包就显示一次。不要仅仅降低输出级别,而要永久注释掉。很低的输出级别,也会占用CPU时间。刷屏的输出会严重影响性能。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有