In the program, we often use system.out.println to output debugging information, convenient and simple, but it is often because it is too simple, it is too convenient, so that we need to replace it with a more powerful way, this The purpose of article article is to provide a way.
During my development process, I will have this expectation for the output debugging information: when the development is developed, the output is a lot of detail information, which makes it easy to debug, and when it is released, don't change any code, you can Let the program only show the information that customers will be interested in; the same does not need to change the code, allow the debugging information to the screen, file, even socket; in addition to the debugging information, you can also output this debug information The class and the number of rows can make me quickly position.
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 sucket = 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
* Sse Messages to Customers. And We Seldom Rely Finest Messages to Check Errors. Just Feel
* Free to use finest at any code linehen you are in cotraming. Note: Finest Messges May
* Be removed by Any Others WITHOUT PRIORM.
* /
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.totring ()));
}
/ **
* 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));
}
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 shouth limited.
* /
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));
}
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 UseMeeth.
* If the socket lost, some operate may can not contact Continue.
* ONLY OCAsional 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.totring ()));
}
/ **
* 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));
}
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 ie) {
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 ie) {
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 = 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 ("YYY-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"); } } Note: When using setlevel to set the Level to config, it will only be output than the CONFIG level INFO, WARNING, and Servere will be output. For more information on Level, refer to JDK documentation -> java.util.logging-> Class Level. Suggest: Severe: Very serious and unable to recover, each independent thread is at least captured, and RuntimeException can be output with Severe, because such errors must be guaranteed in the development phase. WARNING: Severe errors may result in incorrect procedures, only unverified errors can use Warning output. Regular errors should be automatically processed in the program, such as the server connection is not equal, and should be output with a low level. INFO, Config: I have important information that should be prompted, such as start, stopping some main services, unsuccessful or abnormal connections. Fine, Finer, Finest: Debugging information, where Fine displays some useful information. Other considerations: 1 Severe, Warning, Info, config levels to avoid using words such as Fail, Exception, and should ensure syntax, spelling correct. These few levels may be seen by customers. Such as "Connection Lost" can be replaced by "Connection Stopped". 2 Do not use the Exception.PrintStackTrace () function, if you need to debug the debug.fine (exception) or debug.finest (Exception). 3 Under no circumstances, do not submit to result in the output debugging information of the brush screen, as shown once every time you read a packet. Don't just reduce the output level, but you have to comment forever. The low output level will also take up the CPU time. The output of the brush screen will seriously affect performance.