使用高效的日志工具—Log4J (2)

类别:Java 点击:0 评论:0 推荐:
 Log4J的配置

现在来看log4j.properties配置文件的意义。第一行指定了根Logger的级别是DEBUG,并将此指定输出到A1。A1 就是第二行定义的org.apache.log4j.ConsoleAppender,此行表示将A1输出到控制台。第三行规定了输出到A1的格式为 org.apache.log4j.PatternLayout。第四行规定了输出到A1格式的转换模式为 org.javaresearch.log4j.TestLog4J。

很多成熟的服务器类的软件日志信息会输出到控制台,同时输出到日志文件备查。使用Log4J可以在不改变任何代码的情况下,仅通过修改配置文件就可以轻松地完成这项功能。相关配置文件如下:

#### Use two appenders, one to log to console, another to log to a file log4j.rootCategory=debug, stdout, R # Print only messages of priority WARN or higher for your category log4j.category.your.category.name=WARN #### First appender writes to console log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Pattern to output the caller's file name and line number. log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n #### Second appender writes to a file log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=example.log # Control the maximum log file size log4j.appender.R.MaxFileSize=100KB # Archive log files (one backup file here) log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

这个配置文件指定了两个输出源stdout和R。前者把日志信息输出到控制台,后者是一个轮转日志文件。最大的文件是100KB,当一个日志文件达到最大尺寸时,Log4J会自动把example.log重命名为example.log.1,然后重建一个新的example.log文件,依次轮转。

在Web应用中使用

在Web应用中,应该在哪儿对Log4J进行配置呢?首先要明确,Log4J必须在应用的其它代码执行前完成初始化。因为Servlet 是在Web服务器启动时立即装入的,所以,在Web应用中一般使用一个专门的Servlet来完成Log4J的配置,并保证在web.xml的配置中,这个Servlet位于其它Servlet之前。下面是一个例子,代码如下:

package org.javaresearch.log4j; import java.io.*; import javax.servlet.*; import org.apache.log4j.*; public class Log4JInit extends HttpServlet { public void init() throws ServletException { String prefix = getServletContext().getRealPath("/"); String file = getServletConfig().getInitParameter("log4j-config-file"); // 从Servlet参数读取log4j的配置文件 if (file != null) { PropertyConfigurator.configure(prefix + file); } } public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {} public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {} }

<servlet> <servlet-name>log4jinit</servlet-name> <servlet-class>org.javaresearch. log4j.Log4JInit</servlet-class> <init-param> <param-name> log4j-config-file </param-name> <param-value>/properties/log4j.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

注意:上面的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。log4j.properties文件放在根的properties子目录中,也可以把它放在其它目录中。应该把.properties文件集中存放,这样方便管理。

高级话题

性能

在记录一些日志信息时,会一定程度地影响系统的运行效率,这时日志工具是否高效就是一个关键。Log4J的首要设计目标就是高效,一些关键组件都重写过很多次以不断提高性能。根据Log4J项目小组的报告,在AMD Duron 800MHz + JDK1.3.1的环境下,Log4J判断一条日志语句是否需要输出仅需要5纳秒。实际的日志语句执行的也非常快速,从使用SimpleLayout的 21微秒(几乎与System.out.println一样快),到使用TTCCLayout的37微秒不等。

嵌套诊断环境NDC

在多用户并发的环境下,通常是由不同的线程分别处理不同的客户端请求。此时要在日志信息中区分出不同的客户端,你可以为每一个线程生成一个Logger,从而从一堆日志信息中区分出哪些信息是属于哪个线程的,但这种方式并不高效。Log4J巧妙地使用了Neil Harrison提出的“NDC(嵌套诊断环境)”机制来解决这个问题。Log4J为同一类别的线程生成一个Logger,多个线程共享使用,而它仅在日志信息中添加能够区分不同线程的信息。NDC是什么?举例来说,如果一个Servlet接到并发请求时,为每一个客户端创建一个新的线程,然后分配一个用于保存该请求上下文的NDC堆栈。该上下文可能是发出请求的主机名、IP地址或其它任何可以用于标识该请求的信息。这样,由于不同的客户端处理线程具有不同的NDC堆栈,即使这个Servlet同时生成多个线程处理不同的请求,这些日志信息仍然可以区分出来,就好像Log4J为每一个线程都单独生成了一个 Logger实例一样。在Log4J中是通过org.apache.log4j.NDC实现这种机制的。使用NDC的方法也很简单,步骤如下:

1. 在进入一个环境时调用NDC.push(String),然后创建一个NDC;

2. 所做的日志操作输出中包括了NDC的信息;

3. 离开该环境时调用NDC.pop方法;

4. 当从一个线程中退出时调用NDC.remove方法,以便释放资源。

下面是一个模拟记录来自不同客户端请求事件的例子,代码如下:

import org.apache.log4j.Logger; import org.apache.log4j.NDC; public class TestNDC { static Logger log = Logger.getLogger(TestNDC.class.getName()); public static void main(String[] args) { log.info("Make sure %x is in your layout pattern!"); // 从客户端获得IP地址的例子 String[] ips = {"192.168.0.10","192.168.0.27"}; for (int i = 0; i<ips.length ; i++) // 模拟一个运行方法 { // 将IP放进 NDC中 NDC.push(ips[i]); log.info("A NEW client connected, who's ip should appear in this log message."); NDC.pop(); } NDC.remove(); log.info("Finished."); } }

注意配置文件中的布局格式中一定要加上%x。系统输出如下:

INFO - Make sure %x is in your layout pattern! INFO 192.168.0.10 - A NEW client connected, who's ip should appear in this log message. INFO 192.168.0.27 - A NEW client connected, who's ip should appear in this log message. INFO - Finished.

使用Log4J还是JDK logging API

从JDK 1.4.0开始,引入了java.util.logging包。虽然Log4J小组曾竭力游说JCP(Java Community Process)采用Log4J作为JDK 1.4的“标准”日志API,虽然最终因Sun的日志API规范的负责人Graham Hamilton的一句“Merlin的开发已经到了最后阶段,这时不允许再对主要API做出改变”而没有被采纳,但Log4J还是对新的日志API产生了重要影响。那么,我们到底应该采用Log4J还是java.util.logging包呢?下面仅对两者做一简单的比较。

1. Log4J更加成熟,从1999年10月开始至今已经有3年的时间,并且已经在许多项目中有着成熟的应用。而JDK中的logging包是在1.4之后才引入的,并且不能运行于JDK 1.3之前的版本。Log4J则可以良好地运行于JDK 1.1之后的所有版本。

2. Log4J已经被移植到多种环境下,包括log4c(C)、log4cpp(C++)、log4perl(Perl)、log4net(.net)等。在这些环境下,可以感受到几乎一致的配置和使用方式。这是JDK中的logging API所不能比拟的。

3. Log4J还具有更加强力的格式化系统,可以使记录输出时实现简单的模式。但是,它不会增加类而导致格式化工具的扩展。众多的附加程序和处理器使得Log4J数据包成为一个绝佳的选择,所有你所需要的都可能加以实现。

4. Log4J在性能上做了最大的优化。

Logging API对于简单的使用是足够的,但它缺少了许多Log4J所具有的功能。所以,如果你需要一个强力的logging机制,就应坚持使用Log4J;而如果只是需要一些简单的控制或文件记录,那么可以使用已经内建在JDK之中的logging API。

虽然Log4J和JDK logging API是一种竞争关系,但在logging API还在JCP中讨论(JSR47)时,两者之间就已经开始相互影响了。

FAQ

1. 如何让Log4J使用指定的配置文件

在启动你的应用时植入系统属性。例如,可以把上面的log4j.properties文件放到\properties的相对路径下,并改名为log.properties,此时如果让Log4J能够找到这个配置文件并正确地初始化,需要这样运行程序:

D:\..\java -Dlog4j.configuration=. \properties\log.properties YourAppName

为什么一定要使用系统属性,而不在配置文件中指定呢?很显然,如果把它写入配置文件,那么,Log4J读到它时已经迟了。

2. 如何查看到Log4J的配置过程

可以类似1中的那样,设置系统属性log4j.debug=true,从而打开Log4J的Verbose模式,此时会输出Log4J的初始化过程,这样就会对Log4J的启动有一个更详细的了解。下面是Log4J启动信息的一个示例:

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@92e78c. log4j: Trying to find [log4j.xml] using sun.misc.Launcher$ExtClassLoader@9fbe93class loader. log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource(). log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@92e78c. log4j: Using URL [file:/D:/java/logging/src/log4j.properties] for automatic log4j configuration. log4j: Reading configuration from URL file:/E:/java/logging/src/log4j.properties log4j: Parsing for [root] with value=[DEBUG, A1]. log4j: Level token is [DEBUG]. log4j: Category root set to DEBUG log4j: Parsing appender named "A1". log4j: Parsing layout options for "A1". log4j: Setting property [conversionPattern] to [%d %l %-5p %c [%t] - %m%n]. log4j: End of parsing for "A1". log4j: Parsed "A1" options. log4j: Finished configuring. ...... // 下面就是应用的日志信息,省略。

本文地址:http://com.8s8s.com/it/it12274.htm