WebLogic Server 8.1 中的日志框架建立在 JDK 1.4 中引入的 Java 日志 API 函数基础上。 Java 日志 API 函数定义了标准接口来接收和处理日志事件。日志事件处理可以包括发送事件到自定义目标,如 JMS 队列,也可以控制发送到每个已配置目标文件的日志事件的容量。 |
下载作者提供的与本文相关的文档。 |
为了构建消息条目,WebLogic Server提供了一个国际化(I18n)框架。消息条目是一个 XML 文件,包括日志消息和这些消息的惟一标识、严重性和日志正文文本。使用 WebLogic i18ngen 可把消息条目编译成一个类,这个类提供类型安全方法,用与语言和场所无关的方式向 WebLogic Server 发出日志请求。另外,API 还为不需要 I18n 或已经在 WebLogic I18n 框架外标准化过的日志消息提供了类 weblogic.logging.NonCatalogLogger 。
WebLogic 日志框架从条目和非条目日志源发出消息,并将其输入给 java.util.logging.Logger 类的一个实例。默认情况下,这个日志记录器附加的处理程序将完成书写标准输出、服务器日志文件和为日志事件发送 JMX 通知的 LogBroadcasterRuntimeMBean 。
下面的结构图展示了向作为 java.util.logging.Logger 类实例的服务器日志记录器发送日志请求的流。服务器日志记录器随即向日志文件、标准输出和 JMX 监听程序发布日志事件。
WebLogic 服务器日志记录器
Java 日志 API 函数定义了一个类似于 JMS 的发布-订阅模型。日志记录器发布日志事件并且处理程序接收或处理通知。一个日志记录器可能有 0 个或者多个已注册处理程序来接收已发布的日志消息。每个日志记录器都有单个父母,或者可以有其他日志记录器作为孩子。因此,日志记录器之间存在层次关系。 LogManager 管理这个日志记录器树。 LogManager 只有一个根日志记录器,配置属性是由一个日志记录器从它的父母日志记录器实例继承而来。默认的日志配置是从 JDK 安装的 JRE/lib 目录中的 logging.properties 文件中读取的。
然而,当服务器启动时,WebLogic 服务器日志记录器从 config.xml 读取它的配置内容。任何的配置项变动(例如发向标准输出的消息的开始严重程度)都是通过管理控制台来完成的。服务器日志记录器也没有任何依附于它的子日志记录器。日志框架使用日志记录器的单个实例来发布所有来自条目和非条目源的消息。weblogic.logging.LoggingHelper.getServerLogger() 静态方法可以提供对服务器日志记录器的引用。
事件处理
使用 OOTB 处理程序来配置服务器日志记录器,为的是书写日志文件和发送事件到标准输出。通过调用 Logger.addHandler() 方法,可以添加自定义处理程序,并可以传递java.util.logging.Handler 子类自己的实现结果。当日志事件发生时,日志记录器调用每个注册处理程序的发送方法,发送方法是通过一个封装了日志请求的 java.util.logging.LogRecord 实例传递的。WebLogic Server 日志记录器传递类 weblogic.logging.WLLogRecord 的一个实例到每个注册过的监听程序。WLLogRecord 类从 java.util.logging.LogRecord 继承而来,并提供额外的参数,如线程名称、事务和用户ID等等。当将一个 LogRecord 写入流时,一个处理程序将与提交 LogRecord的java.util.logging.Formatter相关联。您可以提供自己的格式程序,例如,使用 XML 格式完成 LogRecord 的输出。
注意在 WebLogic Server 8.1 版本发布前,监听日志事件的惟一途径是通过JMX 通知,具体的方法是给每台服务器上的LogBroadcasterRuntimeMBean 的单个实例注册一个JMX 监听程序。 LogBroadcasterRuntimeMBean 仍然可以向远程的 JMX NotificationListener 广播日志事件。处理程序提供更简单的方法;局限性是它不是一个远程对象,并且事件需要在服务器 JVM 进程中处理。
容量控制
日志 API 函数通过一个日志记录器和处理程序提供两个Knob 来控制消息流动的容量。一个建立在 java.util.logging.Level 基础上;另一个建立在 java.util.logging.Filter 基础上。级别提供了廉价但有效的容量控制,这是建立在一个简单的整数比较的基础上的。一个级别的所有消息比指定消息的级别要低是不容许的。另外一个方面,过滤对象可以做得更加精致,虽然在 LogRecord 内容检查和决定是否接受一个消息上要付出较高的代价。级别和过滤器都可以应用到日志记录器和处理程序。当为日志记录器设置了级别或过滤器时,它将不会发布被任何处理程序的级别或过滤器拒绝过的消息。当应用到处理程序时,只会限制发向一个指定日志目的地的消息。
WebLogic 日志记录和一个由类 weblogic.logging.WLLevel 定义的固定级别集合协同工作。这些级别与为消息条目所定义的严重性一致。
例子
让我们使用这些知识,在非正常服务器的条件下构建一个自定义处理程序以生成一个电子邮件通知。当开发自定义处理程序时,我们必须注意出现最小的开销,因为所有正在执行的线程将在服务器运行时调用处理程序。为了快速拒绝不太重要的消息,我们将在处理程序上设置关键级别的临界值。这将拒绝所有对于我们来讲不太重要的消息。在早期设置一个级别是控制消息容量更有效的方法。
首先,我们需要配置邮件会话,以便 MailLogHandler 能够使用它。这个例子演示如何使用 weblogic.Admin 命令来进行 MailSession配置。通过 WebLogic 管理控制台,可以完成相同的配置操作。为了简洁起见,我们将不会演示 weblogic.Admin 的所有参数,而在连接到 WebLogic Server 实例时需要这些参数。例如,-url、-username、–password 选项就没有在下面说明。欲了解 weblogic.Admin 命令行工具的完整说明,请参见在线文档。
l 首先,使用 weblogic.Admin CREATE 命令创建一个 MailSession:weblogic.Admin CREATE -type MailSession -name MyMailSession
l 取得已创建的 MailSessionMBean 的完全合格的 ObjectName : weblogic.Admin GET -type MailSession -property Name
l 设置 MailSession 的 JNDI 名称:weblogic.Admin SET -mbean -property JNDIName MyMailSession (因为 mbean 名称参数提供了第一步中新建的 MailSession 的 ObjectName)。
l 设置 MailSession 的属性:weblogic.Admin SET -mbean -property Properties "mail.host=foo.bar.com,mail.user=sandyboy,mail.from=sandyboy@bar.com"
l 将MailSession 连接到服务器:weblogic.Admin SET -mbean -property Targets "mydomain:Name=myserver,Type=Server"
欲获得在 WebLogic Server 环境下如何使用邮件会话的细节,请参见在线文档。
下面展示 MailLogHandler 类的代码。在构造函数中,从 JNDI 中查找邮件会话对象。‘To Address’也被传递到构造函数,所以接收者知道这些邮件通知的来源。当日志记录器调用这些发布方法时,首先调用基础类方法 isLoggable 来保证在当前级别和过滤器设置下能够记录消息。然后,建立邮件消息,并使用 Java 邮件 API 函数在线路上发送消息。
package weblogic.logging.examples; import java.util.Date; import java.util.logging.ErrorManager; import java.util.logging.Handler; import java.util.logging.LogRecord; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.naming.InitialContext; import javax.naming.NamingException; /** * This class demonstrates how to send email notifications based * on server log events */ public class MailLogHandler extends Handler { private Session session; private String toAddress; public MailLogHandler(String jndiName, String toAddr) throws NamingException { InitialContext ctx = new InitialContext(); session = (Session)ctx.lookup(jndiName); toAddress = toAddr; } public void close() { } public void flush() { } public void publish(LogRecord rec) { // Check whether the log event can be published // based on the Level and Filter settings if (!isLoggable(rec)) { return; } try { Message msg = new MimeMessage(session); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toAddress, false)); msg.setSubject("Message received with severity " + rec.getLevel()); msg.setSentDate(new Date(rec.getMillis())); // Content is stored in a MIME multi-part message with one body part MimeBodyPart mbp = new MimeBodyPart(); mbp.setText(rec.getMessage()); Multipart mp = new MimeMultipart(); mp.addBodyPart(mbp); msg.setContent(mp); Transport.send(msg); } catch(AddressException adex) { reportError(adex.getMessage(), adex, ErrorManager.WRITE_FAILURE); } catch(MessagingException mex) { reportError(mex.getMessage(), mex, ErrorManager.WRITE_FAILURE); } } } |
如下所示,在 startup 类的的帮助下,MailLogHandler 可以注册到服务器日志记录器。有关如何部署 startup 类的细节问题,请参考文档。当服务器开始工作时 startup 类开始执行并注册 MailLogHandler,设置它的级别,因此我们不会泛洪邮件服务器。
package weblogic.logging.examples; import java.util.logging.Handler; import weblogic.logging.WLLevel; import weblogic.logging.LoggingHelper; /** * This class sets up the MailLogHandler as a listener to the * Server Logger for log events. */ public class MailStartup { public static void main(String[] args) { try { Handler h = new MailLogHandler("MyMailSession", "sandeeps@bea.com"); h.setLevel(WLLevel.CRITICAL); LoggingHelper.getServerLogger().addHandler(h); } catch(javax.naming.NamingException nmex) { System.err.println("Error adding MailLogHandler" + nmex.getMessage()); } } } |
结束语
正如在例子中所见,使用 WebLogic 日志框架中支持的 Java 日志 API 函数,就更可能在运行时自定义 WebLogic Server 的日志记录行为。