声明:本文是《 Java 7 Concurrency Cookbook 》的第八章, 作者: Javier Fernández González 译者:郑玉婷
log工具提供了允许你写信息到一个或者多个目的地的机制。一个Logger是由以下这些组成:
一个或多个处理者: 一个处理者将决定目的地和log信息的格式。你可以把日志信息写入操控台,文档,或者数据库。名字: 通常Logger使用的名字是基于类名或者它的包名。等级: 日志信息有等级来表明它的重要性。Logger也有个等级是用来决定写什么样的信息。它只会写和这个等级一样重要的,或者更重要的信息。为了以下2个主要目的,你应该使用log 系统:
当异常被捕捉,写尽可能多的信息。这个会帮助你定位错误并解决它。写关于程序正在执行的类和方法的信息。在这个指南,你将学习如何使用 java.util.logging 包提供的类来添加一个log系统到你的并发应用。
准备
指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。
怎么做呢…
按照这些步骤来实现下面的例子:
001//1. 创建一个类,名为MyFormatter ,扩展 java.util.logging.Formatter 类。实现抽象方法 format()。它接收一个 LogRecord 对象作为参数,并返回一个有着日志信息 String 对象。 002 public class MyFormatter extends Formatter { 003 @Override 004 public String format(LogRecord record) { 005 006 StringBuilder sb=new StringBuilder(); 007 sb.append("["+record.getLevel()+"] - "); 008 sb.append(new Date(record.getMillis())+" : "); 009 sb.append(record.getSourceClassName()+ "."+record.getSourceMethodName()+" : "); 010 sb.append(record.getMessage()+"\n"); 011 012 return sb.toString(); 013 } 014 015//2. 创建一个类,名为 MyLogger。 016 public class MyLogger { 017 018//3. 声明一个私有 static Handler 属性,名为 handler。 019 private static Handler handler; 020 021//4. 实现公共 static 方法 getLogger() 来创建 Logger 对象,你将要使用它来写日志信息。它接收一个String 参数,名为 name。 022 public static Logger getLogger(String name){ 023 024//5. 使用 Logger 类的getLogger() 方法,获取与 java.util.logging.Logger 相关联的 name 作为参数。 025Logger logger=Logger.getLogger(name); 026 027//6. 使用 setLevel() 方法,确立用来写入全部信息的log级别。 028logger.setLevel(Level.ALL); 029 030//7. 如果处理者属性为null值,创建一个新的 FileHandler 对象在 recipe8.log 文件内写日志信息。使用 setFormatter()对象给处理者分配一个 MyFormatter 对象作为格式。 031 try { 032 if (handler==null) { 033 handler=new FileHandler("recipe8.log"); 034 Formatter format=new MyFormatter(); 035 handler.setFormatter(format); 036 } 037 038//8. If the 如果 Logger 对象还有一个与之相关联的处理者,使用 addHandler() 方法分配一个处理者。 039 if (logger.getHandlers().length==0) { 040 logger.addHandler(handler); 041 } 042 } catch (SecurityException e) { 043 e.printStackTrace(); 044 } catch (IOException e) { 045 e.printStackTrace(); 046} 047 048//9. 返回创建的 Logger 对象。 049 return logger; 050} 051 052//10. 创建一个类,名为Task,它实现Runnable 接口。它将是用来测试你的Logger对象的任务。 053 public class Task implements Runnable { 054 055//11. 实现 run() 方法。 056@Override 057 public void run() { 058 059//12. 首先,声明一个 Logger 对象,名为 logger。使用 MyLogger 类的 getLogger() 方法传递这个类的名字为参数来初始它。 060 Logger logger= MyLogger.getLogger(this.getClass().getName()); 061 062//13. 使用 entering() 方法写日志信息表明执行开始。 063 logger.entering(Thread.currentThread().getName(), "run()"); 064//休眠2秒。 065 try { 066 TimeUnit.SECONDS.sleep(2); 067 } catch (InterruptedException e) { 068 e.printStackTrace(); 069} 070 071//14.使用 exiting() 方法写日志信息表明执行结束 072 logger.exiting(Thread.currentThread().getName(), "run()",Thread.currentThread()); 073} 074 075//15. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。 076 public class Main { 077 078 public static void main(String[] args) { 079 080//16. 声明一个 Logger 对象,名为 logger。使用 MyLogger 类的 getLogger() 方法传递字符串 Core 作为参数来初始它 081 Logger logger=MyLogger.getLogger("Core"); 082 083//17. 使用 entering() 方法写日志信息表明主程序开始执行。 084 logger.entering("Core", "main()",args); 085 086//18. 创建 Thread array 来保存5个线程。 087 Thread threads[]=new Thread[5]; 088 089//19. 创建5个Task对象和5个执行他们的线程。写日志信息表明,你将运行一个新的线程和表明你已经创建了线程。 090 for (int i=0; i<threads.length; i++) { 091 logger.log(Level.INFO,"Launching thread: "+i); 092 Task task=new Task(); 093 threads[i]=new Thread(task); 094 logger.log(Level.INFO,"Thread created: "+ threads[i]. getName()); 095 threads[i].start(); 096} 097 098//20. 写日志信息表明你已经创建了线程。 099 logger.log(Level.INFO,"Ten Threads created."+ "Waiting for its finalization"); 100 101//21. 使用 join() 方法等待5个线程的终结。在每个线程终结之后,写日志信息表明线程已经结束。 102 for (int i=0; i<threads.length; i++) { 103 try { 104 threads[i].join(); 105 logger.log(Level.INFO,"Thread has finished its execution",threads[i]); 106 } catch (InterruptedException e) { 107 logger.log(Level.SEVERE, "Exception", e); 108 } 109} 110 111//22. 使用 exiting() 方法写一个日志信息表明主程序运行结束。 112 logger.exiting("Core", "main()"); 113}它是如何工作的…
在这个指南里,你已经使用 Java logging API 提供的Logger类 在并发应用中写日志信息。首先,你实现了 MyFormatter 类来给日志信息一个格式。这个类扩展 Formatter 类,声明了抽象方法 format()。此方法接收 LogRecord 对象的全部日志消息信息,并返回一条格式化的日志信息。在你的类里使用了 LogRecord类的以下这些方法来获取日志信息:
getLevel(): 返回的信息的级别。getMillis():返回日期,当一条信息被发送给 Logger 对象。getSourceClassName(): 返回发送信息给Logger的类的名字。getSourceMessageName():返回发送信息给Logger的方法的名字getMessage() 返回日志信息。MyLogger 类实现了静态方法 getLogger(), 创建 Logger 对象并分配 Handler 对象使用MyFormatter的格式在recipe8.log 文件中写入日志信息。你可以使用这个类的静态方法 getLogger() 创建对象。此方法返回每个不同的对象作为参数传递的名字。 你只要创建一个Handler对象,全部的Logger对象都会使用它在同一个文件中写日志信息。你还配置了logger写全部的日志信息,无论信息级别。最后,你实现了 Task 对象和一个主程序在logfile写入不同的日志信息。你使用了以下的方法:
entering():写 FINER 等级的信息,表明方法开始运行exiting(): 写 FINER 等级的信息,表明方法结束运行log(): 写特定级别的信息更多…
当你使用log类时,你必须考虑2个重要点:
写必需的信息:如果你写过少的信息,那么logger就没有满足它的目的变的不是特别有作用。如果你写过多的信息,那么就会产生很大的日志文件,就不好管理且很难获取必要信息。
对信息使用适当的级别:如果你用高级别写入消息信息(information messages),或者使用低级别来写入报错信息,那么你就会让看logfiles的人很困惑。就会变得很难了解到底发生了什么错误,或者有过多的信息来分析错误的主要原因。
还有很多其他库比 java.util. logging 包提供了更完整的log系统,例如 Log4j 或者 slf4j libraries。但是 java.util.logging 是Java API 的一部分,而且它的全部方法都是 multi-thread safe,所以在并发应用中使用它将不会遇到任何问题。
参见
第六章,并发集: The Using non-blocking thread-safe lists 第六章,并发集: The Using blocking thread-safe lists 第六章,并发集: The Using blocking thread-safe lists ordered by priority 第六章,并发集: The Using thread-safe lists with delayed elements 第六章,并发集: The Using thread-safe navigable maps 第六章,并发集: The Generating concurrent random numbers
文章转自 并发编程网-ifeve.com
相关资源:敏捷开发V1.0.pptx