4.                  配置 
 插入日志请求到应用程序的代码中需要大量的预先计划和最终努力。观察显示大约4%的代码是用来输出的。 
因此,大小适度的程序都被嵌入有成千个日志输出语句。为了以无需手工的方式管理这些日志的输出状态,给日志输出以编号和规范变得势在必行。  
Log4j在程序中有充分的可配置性。然而,用配置文件配置Log4j具有更大的弹性。目前,它的配置文件支持xml和java properties(key=value)文件两种格式。 
让我们以一个例子来演示它是如何做的。假定有一个用了Log4j的程序MyApp。 
 import com.foo.Bar; 
 // Import Log4j classes. 
 import org.apache.Log4j.Logger; 
 import org.apache.Log4j.BasicConfigurator; 
 public class MyApp { 
   // Define a static logger variable so that it references the 
   // Logger instance named "MyApp". 
   static Logger logger = Logger.getLogger(MyApp.class); 
   public static void main(String[] args) { 
    // Set up a simple configuration that logs on the console. 
     BasicConfigurator.configure(); 
      logger.info("Entering application."); 
     Bar bar = new Bar(); 
     bar.doIt(); 
     logger.info("Exiting application."); 
   } 
 } 
MyApp以引入Log4j的相关类开始,接着它定义了一个静态logger变量,并给予值为"MyApp"类的全路径名称。 
MYApp用了定义在包com.foo中的类Bar. 
 package com.foo; 
 import org.apache.Log4j.Logger; 
 public class Bar { 
   static Logger logger = Logger.getLogger(Bar.class); 
   public void doIt() { 
     logger.debug("Did it again!"); 
   } 
 } 
调用BasicConfigurator.configure()方法创建了一个相当简单的Log4j的设置。它加入一 
个ConsoleAppender到根logger。输出将被采用了"%-4r [%t] %-5p %c %x - %m%n"模式 
的PatternLayout所格式化。 
注意,根logger默认被分配了Level.DEBUG的级别。 
MyApp的输出为: 
0    [main] INFO  MyApp  - Entering application. 
36   [main] DEBUG com.foo.Bar  - Did it again! 
51   [main] INFO  MyApp  - Exiting application. 
随后的图形描述了在调用BasicConfigurator.configure()方法后MyApp的对象图。 
  
  
一边要提醒的是,Log4j的子logger只连接到已经存在的它们的父代。特别的是,名为 
com.foo.bar的logger是直接连接到根logger,而不是围绕着没用的com或com.foo 
logger。这显著的提高了程序性能并且减少的内存占用。 
MyApp类配置Log4j是通过调用BasicConfigurator.configure 方法。其它的类仅仅 
需要引入org.apache.Log4j.Logger 类,找到它们希望用的logger,并且用它就行。 
以前的例子通常输出同样的日志信息。幸运的是,修改MyApp是容易的,以便日志输 
出可以在运行时刻被控制。这里是一个小小修改的版本。 
  
 import com.foo.Bar; 
 import org.apache.Log4j.Logger; 
 import org.apache.Log4j.PropertyConfigurator; 
 public class MyApp { 
   static Logger logger = Logger.getLogger(MyApp.class.getName()); 
   public static void main(String[] args) { 
     // BasicConfigurator replaced with PropertyConfigurator. 
     PropertyConfigurator.configure(args[0]); 
     logger.info("Entering application."); 
     Bar bar = new Bar(); 
     bar.doIt(); 
     logger.info("Exiting application."); 
   } 
 } 
修改后的 MyApp通知程序调用PropertyConfigurator()方法解析一个配置文件,并且根 
据这个配置文件来设置日志。 
 这里是一个配置文件的例子,它将产生同以前BasicConfigurator 基本例子一样 
 的输出结果。 
 # Set root logger level to DEBUG and its only appender to A1. 
Log4j.rootLogger=DEBUG, A1 
# A1 is set to be a ConsoleAppender. 
Log4j.appender.A1=org.apache.Log4j.ConsoleAppender 
# A1 uses PatternLayout. 
Log4j.appender.A1.layout=org.apache.Log4j.PatternLayout 
Log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 
假设我们不在对com.foo包的任何类的输出感兴趣的话,随后的配置文件向我们展示 
了实现这个目的的方法之一。 
Log4j.rootLogger=DEBUG, A1 
Log4j.appender.A1=org.apache.Log4j.ConsoleAppender 
Log4j.appender.A1.layout=org.apache.Log4j.PatternLayout 
# Print the date in ISO 8601 format 
Log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n 
# Print only messages of level WARN or above in the package com.foo. 
Log4j.logger.com.foo=WARN 
以这个配置文件配置好的MyApp将输出如下: 
2000-09-07 14:07:41,508 [main] INFO  MyApp - Entering application. 
2000-09-07 14:07:41,529 [main] INFO  MyApp - Exiting application. 
当logger com.foo.bar没有被分配一个级别,它将从com.foo继承,在配置文件中 
它被设置了WARN的级别。在Bar.doIt方法中定义的log为DEBUG级别,低于WARN, 
因此doIt() 方法的日志请求被禁用。 
这里是另外一个配置文件,它使用了多个appenders. 
Log4j.rootLogger=debug, stdout, R 
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 
Log4j.appender.R=org.apache.Log4j.RollingFileAppender 
Log4j.appender.R.File=example.log 
Log4j.appender.R.MaxFileSize=100KB 
# Keep one backup file 
Log4j.appender.R.MaxBackupIndex=1 
Log4j.appender.R.layout=org.apache.Log4j.PatternLayout 
Log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n 
以这个配置文件调用加强了的MyApp类将输出如下信息. 
INFO [main] (MyApp2.java:12) - Entering application. 
DEBUG [main] (Bar.java:8) - Doing it again! 
INFO [main] (MyApp2.java:15) - Exiting application. 
另外,因为根logger有被分配第二个appender,所以输出也将被定向到example.log文件。 
这个文件大小达到100kb时将自动备份。备份时老版本的example.log文件自动被移到 
文件example.log.1中。 
注意我们不需要重新编译代码就可以获得这些不同的日志行为。我们一样可以容易 
的使日志输出到UNIX Syslog daemon, 重定向所有的com.foo到NT Event logger, 
或者转发日志到一个远程的Log4j服务器,它根据本地server的策略来进行日志输出。例 
如转发日志事件到第二个Log4j服务器. 
  
5.                  默认的初始化过程
Log4j类库不对它的环境做任何假设。特别是没有默认的Log4j appender。在一些特别 
的有着良好定义的环境下,logger的静态inializer将尝试自动的配置Log4j。 
java语言的特性保证类的静态initializer当且仅当装载类到内存之时只会被调用一次。 
要记住的重要一点是,不同的类装载器可能装载同一个类的完全不同的拷贝。 
这些同样类的拷贝被虚拟机认为是完全不相干的。 
默认的initialization是非常有用的,特别是在一些应用程序所依靠的运行环境被准确的 
定位的情况下。例如,同一样的应用程序可以被用做一个标准的应用程序,或一个 
applet,或一个在web-server控制下的servlet。 
准确的默认的initialization原理被定义如下: 
1.设置系统属性Log4j.defaultInitOverride为"false"以外的其它值,那么Log4j将 
跳过默认的initialization过程。 
2.设置资源变量字符串给系统属性Log4j.configuration。定义默认initialization 
文件的最好的方法是通过系统属性Log4j.configuration。万一系统属性 
Log4j.configuration没有被定义,那么设置字符串变量resource 给它的默认值 
Log4j.properties。 
3.尝试转换resource 变量为一个URL。 
4.如果变量resource的值不能被转换为一个URL,例如由于MalformedURLException违 
例,那么通过调用 
org.apache.Log4j.helpers.Loader.getResource(resource, Logger.class) 方法从 
classpath中搜索resource,它将返回一个URL,并通知"Log4j.properties"的值是一个错 
误的URL。 
看See Loader.getResource(java.lang.String) 查看搜索位置的列表。 
5.如果没有URL被发现,那么放弃默认的initialization。否则用URL配置Log4j。 
PropertyConfigurator将用来解析URL,配置Log4j,除非URL以".xml"为结尾。 
在这种情况下的话DOMConfigurator将被调用。你可以有机会定义一个自定义的 
configurator。 
系统属性Log4j.configuratorClass 的值取自你的自定义的类名的全路径。 
你自定义的configurator必须实现configurator接口。 
  
6.                  配置范例
6.1               Tomcat下的初始化
默认的Log4j initialization典型的应用是在web-server 环境下。在tomcat3.x和tomcat4.x 
下,你应该将配置文件Log4j.properties放在你的web应用程序的WEB-INF/classes 目录 
下。 
Log4j将发现属性文件,并且以此初始化。这是使它工作的最容易的方法。 
你也可以选择在运行tomcat前设置系统属性Log4j.configuration 。对于tomcat 3.x, 
TOMCAT_OPTS 系统变量是用来设置命令行的选项。对于tomcat4.0,用系统环境变 
量CATALINA_OPTS 代替了TOMCAT_OPTS。 
Example 1  
UNIX 命令行 
export TOMCAT_OPTS="-DLog4j.configuration=foobar.txt" 
告诉Log4j用文件foobar.txt作为默认的配置文件。这个文件应该放在WEB-INF/classes  
目录下。这个文件将被PropertyConfigurator所读。每个web-application将用不同的默认 
配置文件,因为每个文件是和它的web-application 相关的。 
Example 2  
UNIX 命令行 
export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml" 
告诉Log4j输出Log4j-internal的调试信息,并且用foobar.xml作为默认的配置文件。 
这个文件应该放在你的web-application的WEB-INF/classes 目录下。因为有.xml的 
扩展名,它将被DOMConfigurator所读。每个web-application将用不同的默认 
配置文件。因为每个文件都和它所在的web-application 相关的。 
Example 3  
UNIX 命令行 
set TOMCAT_OPTS=-DLog4j.configuration=foobar.lcf -DLog4j.configuratorClass=com.foo.BarConfigurator 
告诉Log4j用文件foobar.lcf作为默认的配置文件。这个文件应该放在你的 
web-application的WEB-INF/classes 目录下。因为定义了Log4j.configuratorClass 系统属 
性,文件将用自定义的com.foo.barconfigurator类来解析。每个web-application将用不 
同的默认配置文件。因为每个文件都和它所在的web-application 相关的。 
Example 4  
UNIX 命令行 
set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf 
告诉Log4j用文件foobar.lcf作为默认的配置文件。这个配置文件用URL file:/c:/foobar.lcf 
定义了全路径名。这样同样的配置文件将被所有的web-application所用。 
不同的web-application将通过它们自己的类装载器来装载Log4j。这样,每个Log4j的环 
境将独立的运作,而没有任何的相互同步。例如:在多个web-application中定义了 
完全相同的输出源的FileAppenders将尝试写同样的文件。结果好象是缺乏安全性的。 
你必须确保每个不同的web-application的Log4j配置没有用到同样的系统资源。 
  
6.2               Servlet 的初始化
用一个特别的servlet来做Log4j的初始化也是可以的。如下是一个例子: 
package com.foo; 
import org.apache.Log4j.PropertyConfigurator; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import java.io.PrintWriter; 
import java.io.IOException; 
public class Log4jInit extends HttpServlet { 
  public  void init() { 
    String prefix =  getServletContext().getRealPath("/"); 
    String file = getInitParameter("Log4j-init-file"); 
    // if the Log4j-init-file is not set, then no point in trying 
    if(file != null) { 
      PropertyConfigurator.configure(prefix+file); 
    } 
  } 
  public  void doGet(HttpServletRequest req, HttpServletResponse res) { 
  } 
} 
在web.xml中定义随后的servlet为你的web-application。 
  <servlet> 
    <servlet-name>Log4j-init</servlet-name> 
    <servlet-class>com.foo.Log4jInit</servlet-class> 
    <init-param> 
      <param-name>Log4j-init-file</param-name> 
      <param-value>WEB-INF/classes/Log4j.lcf</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
  </servlet> 
写一个初始化的servlet是最有弹性的初始化Log4j的方法。代码中没有任何限制,你可 
以在servlet的init方法中定义它。  
 
  |