众所周知,Weblogic的服务器日志是保存在一个.log文件中的,另一种日志信息提示使用标准输出,但是通常情况下,这样的日志提供方式并不能满足我们的要求。下面举了两个例子:
情景一:远程调试不便
当我们在远程调试程序的时候,如果服务器为Linux,为了获得服务器的日志信息,通常需要远程telnet到服务器上,然后通过远程启动服务器实例,最后查看Weblogic服务器的日志文件来获得日志信息,操作的语句大概是这样的情况(省略了部分细节):
telnet remote_server
./startWeblogic.sh > xxx.log &
tail ?f xxx.log
这还算不错的情况,如果服务器为windows,情况更糟,我们需要不停的打开xx.log这个文件,看看服务器上的日志到底输出了什么信息。
情景二:不能及时得到服务器端的日志信息
当我们的产品已经被发布并进入服务状态时,如果服务器发生了异常,我们通常只能被动的等待发现错误的人通知我们或者是被动的查看日志信息获取异常信息,假设在服务器端产生异常的同时我们能够得到异常信息并主动进行处理,对于保持系统的稳定性是不是更有益?
这样的情况给weblogic应用的开发者和服务器管理者都带来了很大的不便,很幸运的是weblogic服务器中的日志服务可以很好的帮我们解决这些问题:
它提供了一系列的工具和接口让我们可以非常方便的自定义日志信息、实现日志信息的本地化,向weblogic日志系统写入、读取、过滤日志信息,而且可以侦听这些日志信息的产生并采取对应的处理措施(比如向系统管理者发送邮件通知异常情况)。
下面的章节将演示如何使用Weblogic服务器中日志服务提供的功能。
除非特别说明,下面的演示所提到的操作都是基于windows2000平台,Weblogic 服务器的版本是weblogic platform 8.1 sp2(安装在c:/bea目录下,后面将使用%bea_home%来引用这个目录)。
I18N消息目录框架(internationalization (I18N) message catalog framework)提供的一组工具和API让让使用者可以发送自定义的消息给weblogic的日志系统。
关于I18N消息目录框架的详细内容请访问weblogic帮助文档中的关于国际化(internationalization)的部分。
下面几个小节将介绍如何自定义需要发送给weblogic服务器的日志系统的信息、如何发送这些信息给weblogic服务器的日志系统
自定义日志信息使用了weblogic platform提供的MsnEditor工具,你可以使用如下步骤自定义这些信息:
界面中各属性详细说明如下:
Message catalog: 要保存消息目录的xml文件位置,比如:E: estCatalog.xml
Catalog type: 目录的类型,这里保持默认的Log messages
I18n package: I18ngen工具生成的java调用类所在的包,如:org.vivianj.i18n
L10n package: L10ngen工具生成的java调用类所在的包,如:org.vivianj.l10n
Subsystem: 标示你的子系统的特征字符,比如作者需要这个消息目录用于客户关
系管理系统,这里可以取为CRM
Prefix: 前缀,它将显示在日志内容的最前面,比如系统默认的消息目录的prefix
是BEA。
Bese id: 消息目录下面消息的最小编号值,必须>500000,而且不能超过6位数字
End id: 消息目录下面消息的最大编号值,必须>500000,而且不能超过6位数字,
要比Base id 大
loggables: 表示是否需要增加返回Loggeable对象的特殊方法
输入各项信息后单击“create catalog”按钮将输入的信息保存到指定的xml文件中。
现在你又回到了MsgEditor工具的主界面,但是界面和刚开始有了些变化,上面的Message catalog后面的文本框应该有了内容:E: estCatalog.xml,界面上部分截图如下:
现在你可以通过界面的下半部分向这个消息目录中增加消息了,消息增加界面中各属性的详细说明如下:
消息的唯一ID号,请单击“Get next id”按钮获得下一个ID号
日志消息级别,用户定义的日志消息只能使用debug, info, warning, and error.
写入日志时要调用的方法签名,是标准的方法签名,签名中可以设置参数,比如:myMethod(String s0,String s1)
请选择Logger,表示你的信息是使用Logger的消息格式并且被Logger对象处理
是否需要为Throwable对象生成stackreace
表示该信息是否是以前版本发布的
消息主体,可以使用method中提供的参数,这里使用{n}来获取method中规定的参数,n表示参数的下标,从0开始
更详细的信息,也可以使用method中提供的参数
导致问题的原因,也可以使用method中提供的参数
推荐的解决方法,也可以使用method中提供的参数
日志消息本地化使用了weblogic附带的MsgLocalizer工具,你可以使用如下步骤为指定文件内的日志消息实现本地化:
现在如果你调用对应的debug方法,他传送的将是你本地化后的信息。
java weblogic.i18ngen -build -d targetdirectory source-files
targetdirectory 编译后生成的.properties和.java文件的存放目录
source-files 保存了消息目录.xml文件
java weblogic.l10ngen -d targetdirectory source-files
其后的参数说明和4.3.1种的说明一致。
将他们当作你自己编写的类,然后你可以通过调用生成的类中的debug方法向weblogic服务器日志系统写入日志了,而且发送的是本地化后的信息。其中的debug方法签名就是日志消息中定义的方法签名。
weblogic Server中的日志服务允许你通过编程和配置指定将那些日志信息发送给日志系统,包括将哪些信息发送给日志文件、哪些文件发送给标准输出界面,这些过滤功能都是用JDK1.4中的日志处理功能实现的,他们位于java.util.logging包中。
当weblogic服务器中的日志消息产生时,他们会被保存到Logger对象中,Logger对象将消息发送给经过注册的日志处理器,系统默认的日志处理器有3个,分别是ConsoleHandler、FileStreamHandler、LogBroadcasterRuntimeMBean:
为了控制日志消息,Logger对象和三个处理器都提供了Level(级别)和Filter(过滤器),下面将讲述如何通过Level(级别)和Filter(过滤器)来控制Logger发布哪些消息以及处理器处理哪些消息:
weblogic服务器日志信息分为7级,从低到高分别是:
DEBUG, INFO, NOTICE,WARNING, ALERT, ERROR, CRITICAL, EMERGENCY
默认情况下,Logger对象将所有级别的日志信息发送给日志处理器,你可以设置Logger的处理级别,只需要通过简单的调用Logger.setLevel方法就可以了,如果系统日志信息级别等于或者超过你设定的级别,系统才会发送。比如例设定为ERROR,那么只有ERROR, CRITICAL, EMERGENCY三种级别的日子信息才会被发送。
同样,处理器默认处理所有消息,你也可以调用Handler. setLevel方法来设定他要处理的消息级别。
为了更好的控制日志信息的发布,还可以调用Logger.setFilter方法给Logger对象增加过滤器,也就是自己提供一些限制条件,只有符合条件的日子信息才能被发送出去。你可以通过继承java.util.logging.Filter来实现自己的过滤器,下面是作者编写的一个简单的过滤器,它规定应用这个过滤器的Logger只发布内容中包含Error字符串的日志:
import java.util.logging.Logger; import java.util.logging.Filter; import java.util.logging.LogRecord; import weblogic.logging.WLLogRecord; import weblogic.logging.WLLevel; public class MyWLSFilter implements Filter { public boolean isLoggable(LogRecord record) { if (record instanceof WLLogRecord) { WLLogRecord rec = (WLLogRecord)record; if (rec.getMessage().indexOf("Error")>-1) { return false; } else { return true; } } else { return false; } } }
同样,你也可以调用Handler. setFilter方法来设定他的过滤器。
要对Logger对象设置消息级别和过滤器,首先要获得服务器的Logger对象,你可以通过LoggingHelper. GetServerLogger获得服务器端的Logger对象,然后调用它的setLevel方法设定它的消息级别,或者调用它的setFilter方法设置Logger对象的过滤器,调用代码类似这样的情况:
Logger serverlogger = LoggingHelper.getServerLogger();
serverlogger.setLevel(WLLevel.ALERT);
serverlogger.setFilter(new MyWLSFilter());
同样,如果要设置日志处理器的消息级别和过滤器,你要获得服务器端的处理器对象。然后调用它的setLevel方法设定它的消息级别,或者调用它的setFilter方法设置Logger对象的过滤器,调用代码类似这样的情况:
Logger serverlogger = LoggingHelper.getServerLogger(); Handler[] handlerArray = serverlogger.getHandlers(); for (int i=0; i < handlerArray.length; i++) { Handler h = handlerArray[i]; //针对不同的处理器,设置不同的消息级别和过滤器 if(h.getClass().getName().equals (“weblogic.logging.ConsoleHandler”)){ h.setLevel(WLLevel.ALERT); h.setFilter(new MyWLSFilter()); } if(h.getClass().getName().equals (“weblogic.logging.FileStreamHandler”)){ h.setLevel(WLLevel.Error); h.setFilter(new MyWLSFilter()); } if(h.getClass().getName().equals (“weblogic.logging. LogBroadcasterRuntimeMBean”)){ h.setLevel(WLLevel.DEBUG); h.setFilter(new MyWLSFilter()); } }
前面的图中我们已经看到,服务器端的Logger对象有3种处理器:ConsoleHandler,FileStreamHandler,LogBroadcaster RuntimeMBean。某些情况下,这些处理方式不能满足我们的要求,所以我们需要实现自己的日志处理,得益于Weblogic服务器的可扩充性,这个实现的过程还是比较简单的,大概的步骤是这个样子:
在这个方法里面,你可以进行如下处理:
在Handler.close方法里面可以释放一些打开的资源,比如你引用的数据库、文件资源等
下面的代码是作者编写的日志处理器,这里只是简单的将信息答应在控制台上,你可以扩展他,增加更强大的通知功能:
package org.vivianj; import java.util.logging.Handler; import java.util.logging.LogRecord; import weblogic.logging.WLLogRecord; import weblogic.logging.WLLevel; public class MyWLHandle extends Handler{ public void publish(LogRecord record){ WLLogRecord wlLogRecord = (WLLogRecord) record; /*硬编码实现过滤器,只处理debug级别的错误信息 * 更好的方法是实现自己的过滤器类实现过滤 */ if (wlLogRecord.getLevel() == WLLevel.DEBUG){ System.out.println("我的处理器处理的错误信息:" + wlLogRecord.getMessage()); //你可以在这里增加更强大的通知功能,比如邮件、手机短信等 } } public void close() { //如果需要释放资源,请在这里增加代码 } public void flush() {} public static void main(String[] args) { } }
为了获得weblogic服务器的日志事件通知,你需要向服务器注册你的日志处理器,步骤如下:
package org.vivianj; import java.rmi.RemoteException; import java.util.logging.Handler; import java.util.logging.Logger; import weblogic.logging.LoggingHelper; public class RegisteLogHander { public void registeLogger() throws RemoteException { //通过LoggingHelper类的静态方法getServerLogger获得服务器端的Logger对象 Logger logger = LoggingHelper.getServerLogger(); Handler h = null; try { //实例化自己的日志处理器 h = new MyWLHandle(); //将自己的日志处理器注册给服务器端的Logger对象 //这样当服务器的Logger对象里面被写入日志信息时,自己的处理内可以得到通知 logger.addHandler(h); } catch(Exception nmex) { System.err.println("Error adding MyJDBCHandler to logger " + nmex.getMessage()); logger.removeHandler(h); } } public static void main(String s[]){ try{ new RegisteLogHander().registeLogger(); } catch(Exception e){ e.printStackTrace(); } } }
现在代码都准备好了,什么时候开始执行、在哪里执行呢?这个时候我们需要借助于weblogic的Startup Class这样一个特性了,它可以让你的类在应用部署、激活之前执行执行的类,正好符合我们的要求。步骤如下:
输入信息如下:
重起weblogic服务器,现在你的日志处理类应该可以开始工作了。
MsgEditor工具的界面设计不太合理,要完整显示这个界面需要显示器支持1024X768的分辨率,而且如果打开windows的任务栏和开始菜单,下面两个按钮使用仍然不太方便,而如果你使用的分辨率是800*600,情况更糟,界面的下面一部分就看不到了(包括add和cancel按钮),所以你根本无法完整的使用这个工具。建议BEA将这个界面放入一个JScrollPanel中,不管使用者的分辨率多大,虽然使用不太方便,但至少不影响到用户使用这个工具。
虽然BEA提供了大量的日志信息供我们使用,但是这些信息没有实现本地化,而且这些日志信息发送的途径也不完全符合我们的要求,这时候我们就可以使用weblogic提供的接口来扩展weblogic的功能:将日志信息本地化(中文化)、提供自己的日志信息、使用weblogic的日志处理器来保存自己的日志信息、使用分级/过滤器来限制日志信息处理器的处理范围、实现自己的处理器等。作者根据自己的经验讲解了如何实现这些定制功能的整个程,希望能够对大家有所帮助。