【永恒的瞬间】
☜Give me hapy ☞
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。



Log4j-init

com.foo.Log4jInit



Log4j-init-file

WEB-INF/classes/Log4j.lcf



1



写一个初始化的servlet是最有弹性的初始化Log4j的方法。代码中没有任何限制,你可

以在servlet的init方法中定义它。



posted on 2007-01-03 17:03 ☜♥☞MengChuChen 阅读(327) 评论(0)  编辑  收藏 所属分类: Log4j

只有注册用户登录后才能发表评论。


网站导航: