日志系统(Log System)是将信息输出到一个或者多个目标上的一种机制。一个日志器(Logger)有下面几个组件。
一个或多个处理器(Handler):处理器决定目标和日志消息的格式。可以把日志消息输出到控制台上、写到文件中或保存到数据库中。
一个名称(Name):一般来说,类中的日志记录器的名称是基于它的包名和类名的。
一个级别(Level):日志消息有一个关联的级别来表示它的重要性。日志记录器也有一个级别用来决定它要输出什么级别的消息。日志记录器仅输出与它的级别相同重要或者更重要的消息。
使用日志系统有以下两个主要目的:
当捕获到异常时尽可能多地输出信息,这有助于定位并解决错误;
输出关于程序正在执行的类和方法的信息。
在本节,我们将学习如何使用java.util.logging包提供的类来将一个日志系统增加到并发应用程序中。
1. 创建一个名为MyFormatter的类,继承java.util.logging.Formatter类。然后,实现抽象format()方法。它以LogRecord对象为参数,返回一个带有日志消息的String对象。
importjava.util.Date;importjava.util.logging.Formatter;importjava.util.logging.LogRecord;public class MyFormatter extendsFormatter {
@OverridepublicString format(LogRecord record) {
StringBuilder sb= newStringBuilder();
sb.append("["+record.getLevel()+"] - ");
sb.append(new Date(record.getMillis())+" : ");
sb.append(record.getSourceClassName()+"."+record.getSourceMethodName()+" : ");
sb.append(record.getMessage()+"\n");returnsb.toString();
}
}
2. 创建一个名为MyLogger的类。
importjava.io.IOException;importjava.util.logging.FileHandler;importjava.util.logging.Formatter;importjava.util.logging.Handler;importjava.util.logging.Level;importjava.util.logging.Logger;public classMyLogger {private staticHandler handler;public staticLogger getLogger(String name){
Logger logger=Logger.getLogger(name);
logger.setLevel(Level.ALL);try{if(handler==null){
handler= new FileHandler("D:\\recipe8.log");
Formatter format= newMyFormatter();
handler.setFormatter(format);
}if(logger.getHandlers().length==0){
logger.addHandler(handler);
}
}catch(SecurityException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e) {//TODO Auto-generated catch block
e.printStackTrace();
}returnlogger;
}
}
3. 创建一个名为Task的类,实现Runnable接口。它是用来测试Logger对象的任务。
importjava.util.concurrent.TimeUnit;importjava.util.logging.Logger;public class Task implementsRunnable {
@Overridepublic voidrun() {try{
Logger logger= MyLogger.getLogger(this.getClass().getName());
logger.entering(Thread.currentThread().getName(),"run()");
TimeUnit.SECONDS.sleep(2);
logger.exiting(Thread.currentThread().getName(),"exit()",
Thread.currentThread());
}catch(InterruptedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4. 实现范例的主类Main,并实现main()方法。
importjava.util.logging.Level;importjava.util.logging.Logger;public classMain {public static voidmain(String[] args) {
Logger logger= MyLogger.getLogger("Core");
logger.entering("Core", "main()",args);
Thread threads[]= new Thread[5];for(int i=0;i
logger.log(Level.INFO,"Launching thread: ", +i);
Task task= newTask();
threads[i]= newThread(task);
logger.log(Level.INFO,"Thread created: "+threads[i].getName());
threads[i].start();
}
logger.log(Level.INFO,"Five Threads created. Waiting for its finalization.");try{for(int i=0;i
threads[i].join();
logger.log(Level.INFO,"Thread has finished its execution", threads[i]);
}
}catch(InterruptedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
logger.exiting("Core", "main()");
}
}
5. 控制台输出结果如下
十月 28, 2015 7:40:16下午 Main main
信息: Launching thread:
十月28, 2015 7:40:16下午 Main main
信息: Thread created: Thread-1十月28, 2015 7:40:16下午 Main main
信息: Launching thread:
十月28, 2015 7:40:16下午 Main main
信息: Thread created: Thread-2十月28, 2015 7:40:16下午 Main main
信息: Launching thread:
十月28, 2015 7:40:16下午 Main main
信息: Thread created: Thread-3十月28, 2015 7:40:16下午 Main main
信息: Launching thread:
十月28, 2015 7:40:16下午 Main main
信息: Thread created: Thread-4十月28, 2015 7:40:16下午 Main main
信息: Launching thread:
十月28, 2015 7:40:16下午 Main main
信息: Thread created: Thread-5十月28, 2015 7:40:16下午 Main main
信息: Five Threads created. Waitingforits finalization.
十月28, 2015 7:40:18下午 Main main
信息: Thread has finished its execution
十月28, 2015 7:40:18下午 Main main
信息: Thread has finished its execution
十月28, 2015 7:40:18下午 Main main
信息: Thread has finished its execution
十月28, 2015 7:40:18下午 Main main
信息: Thread has finished its execution
十月28, 2015 7:40:18下午 Main main
信息: Thread has finished its execution
View Code
6. 日志recipe8.log内容如下:
[FINER] - Wed Oct 28 19:40:16 CST 2015: Core.main() : ENTRY
[INFO]- Wed Oct 28 19:40:16 CST 2015: Main.main : Launching thread:
[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Thread created: Thread-1[INFO]- Wed Oct 28 19:40:16 CST 2015: Main.main : Launching thread:
[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Thread created: Thread-2[FINER]- Wed Oct 28 19:40:16 CST 2015 : Thread-1.run() : ENTRY
[INFO]- Wed Oct 28 19:40:16 CST 2015: Main.main : Launching thread:
[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Thread created: Thread-3[INFO]- Wed Oct 28 19:40:16 CST 2015: Main.main : Launching thread:
[FINER]- Wed Oct 28 19:40:16 CST 2015 : Thread-3.run() : ENTRY
[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Thread created: Thread-4[INFO]- Wed Oct 28 19:40:16 CST 2015: Main.main : Launching thread:
[FINER]- Wed Oct 28 19:40:16 CST 2015 : Thread-2.run() : ENTRY
[FINER]- Wed Oct 28 19:40:16 CST 2015 : Thread-4.run() : ENTRY
[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Thread created: Thread-5[INFO]- Wed Oct 28 19:40:16 CST 2015 : Main.main : Five Threads created. Waiting forits finalization.
[FINER]- Wed Oct 28 19:40:16 CST 2015 : Thread-5.run() : ENTRY
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Thread-1.exit() : RETURN {0}
[INFO]- Wed Oct 28 19:40:18 CST 2015: Main.main : Thread has finished its execution
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Thread-3.exit() : RETURN {0}
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Thread-4.exit() : RETURN {0}
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Thread-2.exit() : RETURN {0}
[INFO]- Wed Oct 28 19:40:18 CST 2015: Main.main : Thread has finished its execution
[INFO]- Wed Oct 28 19:40:18 CST 2015: Main.main : Thread has finished its execution
[INFO]- Wed Oct 28 19:40:18 CST 2015: Main.main : Thread has finished its execution
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Thread-5.exit() : RETURN {0}
[INFO]- Wed Oct 28 19:40:18 CST 2015: Main.main : Thread has finished its execution
[FINER]- Wed Oct 28 19:40:18 CST 2015 : Core.main() : RETURN
View Code
在上面的实现类中,已使用LogRecord类的下列方法来获取日志消息的信息。
getLevel():返回消息级别。
getMillis():返回发送消息到Logger对象时的时间(从1970开始计算的毫秒数)。
getSourceClassName():返回发送消息到Logger的类的名称。
getSourceMessageName():返回发送消息到Logger的方法的名称。
getMessage()方法返回日志消息。
在主程序中,使用了下列方法。
entering():输出FINER级别的消息表示方法开始执行。
exiting():输出FINER级别的消息表示方法停止执行。
log():输出带有指定级别的消息。
也有其他类库比java.util.logging包提供了更完全的日志系统,如Log4j或slf4j类库。但是java.util.logging包是Java API的一部分,并且它的所有方法都是安全的,所以用在并发应用程序中没有问题。