log工具提供了允许你写信息到一个或者多个目的地的机制。一个logger是由以下这些组成:
一个或多个处理者: 一个处理者将决定目的地和log信息的格式。你可以把日志信息写入操控台,文档,或者数据库。
名字: 通常logger使用的名字是基于类名或者它的包名。
等级: 日志信息有等级来表明它的重要性。logger也有个等级是用来决定写什么样的信息。它只会写和这个等级一样重要的,或者更重要的信息。
为了以下2个主要目的,你应该使用log 系统:
当异常被捕捉,写尽可能多的信息。这个会帮助你定位错误并解决它。
写关于程序正在执行的类和方法的信息。
在这个指南,你将学习如何使用 java.util.logging 包提供的类来添加一个log系统到你的并发应用。
准备
指南中的例子是使用eclipse ide 来实现的。如果你使用eclipse 或者其他的ide,例如netbeans, 打开并创建一个新的java项目。
怎么做呢…
按照这些步骤来实现下面的例子:
<code>001</code>
<code>//1. 创建一个类,名为myformatter ,扩展 java.util.logging.formatter 类。实现抽象方法 format()。它接收一个 logrecord 对象作为参数,并返回一个有着日志信息 string 对象。</code>
<code>002</code>
<code>public</code> <code>class</code> <code>myformatter</code><code>extends</code> <code>formatter {</code>
<code>003</code>
<code> </code><code>@override</code>
<code>004</code>
<code> </code><code>public</code> <code>string format(logrecord record) {</code>
<code>005</code>
<code>006</code>
<code> </code><code>stringbuilder sb=</code><code>new</code> <code>stringbuilder();</code>
<code>007</code>
<code> </code><code>sb.append(</code><code>"["</code><code>+record.getlevel()+</code><code>"] - "</code><code>);</code>
<code>008</code>
<code> </code><code>sb.append(</code><code>new</code> <code>date(record.getmillis())+</code><code>" : "</code><code>);</code>
<code>009</code>
<code> </code><code>sb.append(record.getsourceclassname()+</code><code>"."</code><code>+record.getsourcemethodname()+</code><code>" : "</code><code>);</code>
<code>010</code>
<code> </code><code>sb.append(record.getmessage()+</code><code>"\n"</code><code>);</code>
<code>011</code>
<code>012</code>
<code> </code><code>return</code> <code>sb.tostring();</code>
<code>013</code>
<code> </code><code>}</code>
<code>014</code>
<code>015</code>
<code>//2. 创建一个类,名为 mylogger。</code>
<code>016</code>
<code>public</code> <code>class</code> <code>mylogger {</code>
<code>017</code>
<code>018</code>
<code>//3. 声明一个私有 static handler 属性,名为 handler。</code>
<code>019</code>
<code>private</code> <code>static</code> <code>handler handler;</code>
<code>020</code>
<code>021</code>
<code>//4. 实现公共 static 方法 getlogger() 来创建 logger 对象,你将要使用它来写日志信息。它接收一个string 参数,名为 name。</code>
<code>022</code>
<code>public</code> <code>static</code> <code>logger getlogger(string name){</code>
<code>023</code>
<code>024</code>
<code>//5. 使用 logger 类的getlogger() 方法,获取与 java.util.logging.logger 相关联的 name 作为参数。</code>
<code>025</code>
<code>logger logger=logger.getlogger(name);</code>
<code>026</code>
<code>027</code>
<code>//6. 使用 setlevel() 方法,确立用来写入全部信息的log级别。</code>
<code>028</code>
<code>logger.setlevel(level.all);</code>
<code>029</code>
<code>030</code>
<code>//7. 如果处理者属性为null值,创建一个新的 filehandler 对象在 recipe8.log 文件内写日志信息。使用 setformatter()对象给处理者分配一个 myformatter 对象作为格式。</code>
<code>031</code>
<code>try</code> <code>{</code>
<code>032</code>
<code> </code><code>if</code> <code>(handler==</code><code>null</code><code>) {</code>
<code>033</code>
<code> </code><code>handler=</code><code>new</code> <code>filehandler(</code><code>"recipe8.log"</code><code>);</code>
<code>034</code>
<code> </code><code>formatter format=</code><code>new</code> <code>myformatter();</code>
<code>035</code>
<code> </code><code>handler.setformatter(format);</code>
<code>036</code>
<code>037</code>
<code>038</code>
<code>//8. if the 如果 logger 对象还有一个与之相关联的处理者,使用 addhandler() 方法分配一个处理者。</code>
<code>039</code>
<code> </code><code>if</code> <code>(logger.gethandlers().length==</code><code>0</code><code>) {</code>
<code>040</code>
<code> </code><code>logger.addhandler(handler);</code>
<code>041</code>
<code>042</code>
<code>}</code><code>catch</code> <code>(securityexception e) {</code>
<code>043</code>
<code> </code><code>e.printstacktrace();</code>
<code>044</code>
<code>}</code><code>catch</code> <code>(ioexception e) {</code>
<code>045</code>
<code>046</code>
<code>}</code>
<code>047</code>
<code>048</code>
<code>//9. 返回创建的 logger 对象。</code>
<code>049</code>
<code>return</code> <code>logger;</code>
<code>050</code>
<code>051</code>
<code>052</code>
<code>//10. 创建一个类,名为task,它实现runnable 接口。它将是用来测试你的logger对象的任务。</code>
<code>053</code>
<code>public</code> <code>class</code> <code>task</code><code>implements</code> <code>runnable {</code>
<code>054</code>
<code>055</code>
<code>//11. 实现 run() 方法。</code>
<code>056</code>
<code>@override</code>
<code>057</code>
<code>public</code> <code>void</code> <code>run() {</code>
<code>058</code>
<code>059</code>
<code>//12. 首先,声明一个 logger 对象,名为 logger。使用 mylogger 类的 getlogger() 方法传递这个类的名字为参数来初始它。</code>
<code>060</code>
<code>logger logger= mylogger.getlogger(</code><code>this</code><code>.getclass().getname());</code>
<code>061</code>
<code>062</code>
<code>//13. 使用 entering() 方法写日志信息表明执行开始。</code>
<code>063</code>
<code>logger.entering(thread.currentthread().getname(),</code><code>"run()"</code><code>);</code>
<code>064</code>
<code>//休眠2秒。</code>
<code>065</code>
<code>066</code>
<code> </code><code>timeunit.seconds.sleep(</code><code>2</code><code>);</code>
<code>067</code>
<code>}</code><code>catch</code> <code>(interruptedexception e) {</code>
<code>068</code>
<code>069</code>
<code>070</code>
<code>071</code>
<code>//14.使用 exiting() 方法写日志信息表明执行结束</code>
<code>072</code>
<code>logger.exiting(thread.currentthread().getname(),</code><code>"run()"</code><code>,thread.currentthread());</code>
<code>073</code>
<code>074</code>
<code>075</code>
<code>//15. 创建例子的主类通过创建一个类,名为 main 并添加 main()方法。</code>
<code>076</code>
<code>public</code> <code>class</code> <code>main {</code>
<code>077</code>
<code>078</code>
<code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>
<code>079</code>
<code>080</code>
<code>//16. 声明一个 logger 对象,名为 logger。使用 mylogger 类的 getlogger() 方法传递字符串 core 作为参数来初始它</code>
<code>081</code>
<code>logger logger=mylogger.getlogger(</code><code>"core"</code><code>);</code>
<code>082</code>
<code>083</code>
<code>//17. 使用 entering() 方法写日志信息表明主程序开始执行。</code>
<code>084</code>
<code>logger.entering(</code><code>"core"</code><code>,</code><code>"main()"</code><code>,args);</code>
<code>085</code>
<code>086</code>
<code>//18. 创建 thread array 来保存5个线程。</code>
<code>087</code>
<code>thread threads[]=</code><code>new</code> <code>thread[</code><code>5</code><code>];</code>
<code>088</code>
<code>089</code>
<code>//19. 创建5个task对象和5个执行他们的线程。写日志信息表明,你将运行一个新的线程和表明你已经创建了线程。</code>
<code>090</code>
<code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i<threads.length; i++) {</code>
<code>091</code>
<code> </code><code>logger.log(level.info,</code><code>"launching thread: "</code><code>+i);</code>
<code>092</code>
<code> </code><code>task task=</code><code>new</code> <code>task();</code>
<code>093</code>
<code> </code><code>threads[i]=</code><code>new</code> <code>thread(task);</code>
<code>094</code>
<code> </code><code>logger.log(level.info,</code><code>"thread created: "</code><code>+ threads[i]. getname());</code>
<code>095</code>
<code> </code><code>threads[i].start();</code>
<code>096</code>
<code>097</code>
<code>098</code>
<code>//20. 写日志信息表明你已经创建了线程。</code>
<code>099</code>
<code>logger.log(level.info,</code><code>"ten threads created."</code><code>+</code><code>"waiting for its finalization"</code><code>);</code>
<code>100</code>
<code>101</code>
<code>//21. 使用 join() 方法等待5个线程的终结。在每个线程终结之后,写日志信息表明线程已经结束。</code>
<code>102</code>
<code>103</code>
<code> </code><code>try</code> <code>{</code>
<code>104</code>
<code> </code><code>threads[i].join();</code>
<code>105</code>
<code> </code><code>logger.log(level.info,</code><code>"thread has finished its execution"</code><code>,threads[i]);</code>
<code>106</code>
<code> </code><code>}</code><code>catch</code> <code>(interruptedexception e) {</code>
<code>107</code>
<code> </code><code>logger.log(level.severe,</code><code>"exception"</code><code>, e);</code>
<code>108</code>
<code>109</code>
<code>110</code>
<code>111</code>
<code>//22. 使用 exiting() 方法写一个日志信息表明主程序运行结束。</code>
<code>112</code>
<code>logger.exiting(</code><code>"core"</code><code>,</code><code>"main()"</code><code>);</code>
<code>113</code>
它是如何工作的…
在这个指南里,你已经使用 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,所以在并发应用中使用它将不会遇到任何问题。