Log4j进阶

Java中的Log4j:高级进阶篇 Log4j是一个开放源代码的日志记录工具包,它允许开发人员在应用程序中记录日志信息。Log4j提供了强大的功能,如灵活的日志级别控制、多样的输出目标(控制台、文件、数据库等)以及可扩展的日志格式化机制。📊Log4j允许我们自定义日志消息的格式。下面的例子展示了如何自定义日志格式。通过今天的介绍,你应该已经掌握了如何使用Log4j来处理一些常见的日志记录任务。Log4j的强大之处在于它不仅支持基本的日志记录,还可以帮助我们处理更复杂的场景,比如动态更改日志级别、自定义日志格式等。 阅读详情

Log4j 

动态配置log4j
1 配置外部配置文件来配置的基本步骤
1.1 一个运用配置文件的实例
Log4j之所以能成功的原因之一是它的灵活性。但如果只是简单的调用BasicConfigurator.configure()来进行配置工作,那么所有的配置都是在函数中写死的,以后修改配置就要修改原代码,这就不能体现出log4j的灵活性了,所以基本上不会通过BasicConfigurator.configure()来进行配置工作的。
为了增加软件的灵活性,最常用的做法就是使用配置文件,如web.xml之于J2EE,struts-config.xml之于struts一样,log4j也提供了让我们把配置信息从程序转移到配置文件中的方法。Log4j提供了两种方式的配置文件:XML文件和Java的property配置文件。通过把配置信息转移到外部文件中,当我们要修改配置信息时,就可以直接修改配置文件而不用去修改代码了,下面,我们就来完成一个通过配置文件来实现log4j的实例。
例2-a:
package TestLog4j;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority; public class TestLog4j 
{
static Logger logger = Logger.getLogger(TestLog4j.class.getName());
public TestLog4j(){}

public static void main(String[] args)
{
//通过BasicConfigurator类来初始化
//BasicConfigurator.configure();
//(1)通过配置文件来初始化
PropertyConfigurator.configure("F://nepalon//log4j.properties");

logger.debug("Start of the main() in TestLog4j"); //代码(2)
logger.info("Just testing a log message with priority set to INFO");
logger.warn("Just testing a log message with priority set to WARN");
logger.error("Just testing a log message with priority set to ERROR");
logger.fatal("Just testing a log message with priority set to FATAL");
logger.log(Priority.WARN, "Testing a log message use a alternate form");
logger.debug(TestLog4j.class.getName()); //代码(2)
}
}
在这个例子中,我们用PropertyConfigurator.configure("F://nepalon//log4j.properties")代替BasicConfigurator.configure()进行配置。PropertyConfigurator.configure()函数的参数可以是一个properties文件所在路径的String对象,可以是一个properties文件所在路径的URL对象,也可以是一个properties对象。通过PropertyConfigurator.configure()可以通过指定的properties文件来配置信息。如果要用XML文件进行信息配置,可以在代码中调用DOMConfigurator()函数来进行配置工作。在这里,我们只以properties文件来完成例子。接着,我们来看一下log4j.properties文件中都有些什么东西:
例2-b:
log4j.rootLogger = DEBUG, A1
log4j.appender.A1 = org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout = org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c %x - %m%n
运行这个实例,运行结果为
0 [main] DEBUG TestLog4j.TestLog4j - Start of the main() in TestLog4j
20 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
20 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
20 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
20 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
180 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
180 [main] DEBUG TestLog4j.TestLog4j - TestLog4j.TestLog4j
下面,我们分析一下这个配置文件。
1) 由于每一个Logger对旬都有一个级别,文件的第一行就是定义了一个Logger及其级别。在这里定义了一个根记录器(root logger),这涉及到记录器的层次问题,在些暂时不深入讨论,在后面的章节再进行讨论。
2) 第二行定义了一个名为A1的输出流,这个流就是控制台,所以通过Logger对象打印的信息会在控制台输出。
3) 第三行定义了打印信息的布局。在这里我们用PatternLayout作为此记录器的布局,PatternLayout允许你以灵活的格式来打印信息。
4) 第四行指定的打印信息的具体格式,从结果可知,这个实例的打印格式为:当前打印语句所使用的时间 [日志所在的线程] 打印的级别 当前日志所在的类的全名 日志信息。
现在我们来修改一下这个记录器的级别,把第一行的DEBUG改为INFO,再运行程序,结果将变为:
0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
10 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
10 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
10 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
10 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
由于这个Logger的级别变为INFO,而代码(2)是调用debug()函数来输出日志信息时只能当记录器级别为DEBUG时才输出信息,所以代码(2)将不输出信息。
1.2 实例原理
1.2.1 初始化配置信息
如果要通过JAVA的properties文件来配置信息,那么在代码中就要通过PropertyConfigurator.configure()函数从properties文件中加载配置信息,这个函数有三种参数形式:一个properties文件所在路径的String对象,可以是一个properties文件所在路径的URL对象,也可以是一个properties对象。如果要用XML文件来配置信息,则可用类型的
DOMConfigurator()函数来从一个XML文件中加载配置信息。
1.2.2 输出端Appender
在上面的例子中,我们都是简单的把日志信息输出到控制台中。其实在log4j中还可以把日志信息输出到其它的输出端,对于同一个日志信息,我们还可以让它同时输出到多个输出端中,如同时在控制台和文件中进行打印。一个输出端就是一个appender。要在配置文件中定义一个appender有三步:
1) 在定义一个记录器的同时定义出该记录器的输出端appender。在例2的配置文件的第一句log4j.rootLogger = DEBUG, A1中,我们定义了一个根记录器,它的级别为DEBUG,它有一个appender名为A1。定义根记录器的格式为log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN。同一个记录器可有多个输出端。
2) 定义appender的输出目的地。定义一个appender的输出目的地的格式为log4j.appender.appenderName = fully.qualified.name.of.appender.class。log4j提供了以下几种常用的输出目的地:
? org.apache.log4j.ConsoleAppender,将日志信息输出到控制台
? org.apache.log4j.FileAppender,将日志信息输出到一个文件
? org.apache.log4j.DailyRollingFileAppender,将日志信息输出到一个,并且每天输出到一个新的日志文件
? org.apache.log4j.RollingFileAppender,将日志信息输出到一个文件,通过指定文件的的尺寸,当文件大小到达指定尺寸的时候会自动把文件改名,如名为example.log的文件会改名为example.log.1,同时产生一个新的example.log文件。如果新的文件再次达到指定尺寸,又会自动把文件改名为example.log.2,同时产生一个example.log文件。依此类推,直到example.log. MaxBackupIndex,MaxBackupIndex的值可在配置文件中定义。
? org.apache.log4j.WriterAppender,将日志信息以流格式发送到任意指定的地方。
? org.apache.log4j.jdbc.JDBCAppender,通过JDBC把日志信息输出到数据库中。
在例2中,log4j.appender.A1 = org.apache.log4j.ConsoleAppender定义了名为A1的appender的输出目的地为控制台,所以日志信息将输出到控制台。
3) 定义与所选的输出目的地相关的参数,定义格式为:
log4j.appender.appenderName.optionName1 = value1
……
log4j.appender.appenderName.optionNameN = valueN
其中一个最常用的参数layout将在下面介绍。
1.2.3 输出格式(布局)layout
通过appender可以控制输出的目的地,而如果要控制输出的格式,就可通过log4j的layout组件来实现。通过配置文件定义一个appender的输出格式,也通常需要两个步骤:
1) 定义appender的布局模式。定义一个appender的布局模式的格式为log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class。Log4j提供的布局模式有以下几种:
? org.apache.log4j.HTMLLayout,以HTML表格形式布局
? org.apache.log4j.PatternLayout,可以灵活地指定布局模式
? org.apache.log4j.SimpleLayout,包含日志信息的级别和信息字符串
在例2 中log4j.appender.A1.layout = org.apache.log4j.PatternLayout定义了名为A1的appender的布局模式为PatternLayout。
2) 定义与所选的布局模式相关的设置信息,定义格式为:
log4j.appender.appenderName.layout.optionName1 = value1
……
log4j.appender.appenderName.layout.optionNameN = valueN
选择了不同的布局模式可能会有不同的设置信息。实例2所选的布局模式PatternLayout的一个PatternLayout为ConversionPattern ,通过定义这个PatternLayout的值,我们可以指定输出信息的输出格式。在例2的配置文件中的定义如下log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c %x - %m%n。在下面,我们将介绍布局模式PatternLayout的参数ConversionPattern的各个值代表的含义。
1.2.4 ConversionPattern参数的格式含义
格式名 含义
%c 输出日志信息所属的类的全名
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28
%f 输出日志信息所属的类的类名
%l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
%m 输出代码中指定的信息,如log(message)中的message
%n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
%r 输出自应用启动到输出该日志信息所耗费的毫秒数
%t 输出产生该日志事件的线程名
1.3 定义多个输出目的地的实例
从上面的实例原理中我们已经知道,同一个日志信息可以同时输出到多个输出目的地,在这个例子中,我们将实现一个把日志信息同时输出到控制器、一个文件中的实例和数据库中。这个实例的Java代码我们沿用例2中的代码,我们只需修改配置文件即可。这也体现了log4j的灵活性。
例3-a:
create table log4j(
logID int primary key identity,
message varchar(1024),
priority varchar(10),
milliseconds int,
category varchar(256),
thread varchar(100),
NDC varchar(256),
createDate datetime,
location varchar(256),
caller varchar(100),
method varchar(100),
filename varchar(100),
line int
)
例3-b:
#1 定义了两个输出端
log4j.rootLogger = INFO, A1, A2,A3

#2 定义A1输出到控制器
log4j.appender.A1 = org.apache.log4j.ConsoleAppender
#3 定义A1的布局模式为PatternLayout
log4j.appender.A1.layout = org.apache.log4j.PatternLayout
#4 定义A1的输出格式
log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c - %m%n

#5 定义A2输出到文件
log4j.appender.A2 = org.apache.log4j.RollingFileAppender
#6 定义A2要输出到哪一个文件
log4j.appender.A2.File = F://nepalon//classes//example3.log
#7 定义A2的输出文件的最大长度
log4j.appender.A2.MaxFileSize = 1KB
#8 定义A2的备份文件数
log4j.appender.A2.MaxBackupIndex = 3
#9 定义A2的布局模式为PatternLayout
log4j.appender.A2.layout = org.apache.log4j.PatternLayout
#10 定义A2的输出格式
log4j.appender.A2.layout.ConversionPattern = %d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n

#11区 定义A3输出到数据库
log4j.appender.A3 = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.A3.BufferSize = 40
log4j.appender.A3.Driver = com.microsoft.jdbc.sqlserver.SQLServerDriver
log4j.appender.A3.URL = jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=nepalon
log4j.appender.A3.User = sa
log4j.appender.A3.Password = 
log4j.appender.A3.layout = org.apache.log4j.PatternLayout
log4j.appender.A3.layout.ConversionPattern = INSERT INTO log4j (createDate, thread, priority, category, message) values(getdate(), '%t', '%-5p', '%c', '%m')
配置文件中的6、7、8行显示了输出端为RollingFileAppender的特有参数及其运用的方法。11区显示了输出端为JDBCAppender的特有参数及其运用方法。在这着重讲解一下6、7、8行的作用。6行指定日志信息输出到哪个文件,7行指定日志文件的最大长度,最后要详细介绍8行。第8行的参数是设置备份文件的个数的参数,在这里我们设置为3,表示最多有3个备份文件,具体作用为:
1) 当example3.log文件的大小超过K时,就把文件改名为example3.log.1,同时生成一个新的example3.log文件
2) 当example3.log文件的大小再次超过1K,又把文件改名为example3.log.1。但由于此时example3.log.1已存在,则先把example3.log.1更名为example3.log.2,再把example3.log文件改名为example3.log.1
3) 同理,当example3.log文件的大小再次超过1K,先把example3.log.2文件更名为example3.log.3,把example3.log.1文件更名为example3.log.2,再把example3.log文件改名为example3.log.1
4) 当example3.log文件的大小再次超过1K,先把example3.log.2文件更名为example3.log.3,旧的example3.log.3文件将被覆盖;把example3.log.1文件更名为example3.log.2,旧的example3.log.2文件被覆盖;最后把example3.log文件改名为example3.log.1并覆盖掉旧的example3.log.1文件。
运行结果将分为两部分
在控制器中:
0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
11 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
21 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR 21 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
21 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
在文件example3.log中:
2003-12-18 04:23:02:INFO main TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
2003-12-18 04:23:02:ERROR main TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
2003-12-18 04:23:02:FATAL main TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Testing a log message use a alternate form
1.4 配置log4j的总结
这个教程到这里,关于配置log4j的配置文件的基本原理已经讲完了,而且通过例3我们已经可以完成基本的日志工作了。现在,我们就做一个总结。配置一个配置文件的基本步骤如下:
1) 定义一个Logger。在定义Logger时指定该Logger的级别级其输出目的地。定义Logger的格式为
log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN。
2) 定义appender的输出目的地。定义一个appender的输出目的地的格式为
log4j.appender.appenderName = fully.qualified.name.of.appender.class。
log4j提供的输出端有ConsoleAppender、FileAppender 、DailyRollingFileAppender、RollingFileAppender和WriterAppender。
3) 定义appender的除布局模式外的其它相关参数,如例3中第6、7、8定义了A2的相关参数。定义格式为
log4j.appender.appenderName.optionName1 = value1
……
log4j.appender.appenderName.optionNameN = valueN
如果除了布局模式外不需要定义别的参数,可跳过这一步(如例3中的A1)。
4) 定义appender的布局模式。定义一个appender的布局模式的格式为
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class。
布局模式其实也是步骤3)中的一个部分,只是布局模式参数是每一个appender必须定义的参数。Log4j提供的布局模式有HTMLLayout、PatternLayout和SimpleLayout。
5) 定义与所选的布局模式相关的设置信息,定义格式为
og4j.appender.appenderName.layout.optionName1 = value1
……
log4j.appender.appenderName.layout.optionNameN = valueN
2 记录器的层次Logger hierarchy
2.1 何为记录器的层次hierarchy
首先,我们先看一下何为层次,以我们最熟悉的继承为例,下面是一张类图

在这个继承体系中,类B是类C的父类,类A是类C的祖先类,类D是类C的子类。这些类之间就构成一种层次关系。在这些具有层次关系的类中,子类都可继承它的父类的特征,如类B的对象能调用类A中的非private实例变量和函数;而类C由于继承自类B,所以类B的对象可以同时调用类A和类B中的非private实例变量和函数。
在log4j中,处于不同层次中的Logger也具有象类这样的继承关系。
2.2 记录器的层次
如果一个应用中包含了上千个类,那么也几乎需要上千个Logger实例。如何对这上千个Logger实例进行方便地配置,就是一个很重要的问题。Log4J采用了一种树状的继承层次巧妙地解决了这个问题。在Log4J中Logger是具有层次关系的。它有一个共同的根,位于最上层,其它Logger遵循类似包的层次。下面我们将进行介绍。
2.2.1 根记录器root logger
就象一个Java中的Object类一样,log4j中的logger层次中有一个称之为根记录器的记录器,其它所有的记录器都继承自这个根记录器。根记录器有两个特征:
1) 根记录器总是存在。就像Java中的Object类一样,因为用log4j输出日志信息是通过记录器来实现的,所以只要你应用了log4j,根记录器就肯定存在的。
2) 根记录器没有名称,所以不能通过名称来取得根记录器。但在Logger类中提供了getRootLogger()的方法来取得根记录器。
2.2.2 记录器的层次
Logger遵循类似包的层次。如
static Logger rootLog = Logger.getRootLogger();
static Logger log1 = Logger.getLogger("test4j");
static Logger log2 = Logger.getLogger("test4j.test4j2");
static Logger log3 = Logger.getLogger("test4j.test4j2.test4j2");
那么rootLog是log2的祖先子记录器,log1是log2的父子记录器,log3是log2的子记录器。记录器象Java中的类继承一样,子记录器可以继承父记录器的设置信息,也可以可以覆写相应的信息。
首先先看一下记录器层次中的继承有什么用处。假设程序中的每个包都具有一些基本的日志信息,而包中的不同包可能会有些额外的日志信息要输出,这种情况就可以象处理Java中的类一样,运用Logger中的层次关系来达到目的。假设有个名为A的包,我包下的所有类都要把日志信息输出到控制台中;A.B包除了输出到控制台外还要输出到文件中;A.C包除了输出到控制台中还要输出到HTML文档中。这样我们就可以通过定义一个父记录器A,它负责把日志信息输出到控制台中;定义一个A的子记录器A.B,它负责把日志信息输出到文件中;定义一个A的子记录器A.C,它负责把日志信息输出到HTML文档中。
记录器遵循的是类似包的层次,这样做为我们带来了大大的方便。Logger类中的getLogger()方法可以取得Logger对象,这个方法有三种参数形式String、Class和URL,其实不论是用哪一种,最终都是通过记录器的名字来取得记录器对象的。如果要取得一个名为A.B的记录器对象,我们可以Logger.getLogger(“A.B”)。但从上面的例子中,我们都是通过Logger.getLogger(TestLog4j.class.getName())这种方法来取得记录器对象。这是为什么呢?现在我们假设A.B的包下有一个类BClass,那么我们调用BClass.class.getName()得到的是这个类的全名A.B.BClass。所以当调用Logger.getLogger(BClass.class.getName())时,最理想的情况是返回名为A.B.BClass的记录器对象。但是如果不存在名为A.B.BClass的记录器时它会怎样呢?其实通过Logger类的getLogger方法取得记录器时存在下面两种情况:
1) 如果存在与所要找的名字完全相同的记录器,则返回相应的记录器对象。
当调用Logger.getLogger(BClass.class.getName())时,如果定义了名为A.B.BClass的记录器,它就返回该记录器的对象。
2) 但如果找不到,它会尝试返回在记录器层次中与所要找的记录器最接近的记录器对象。
当调用Logger.getLogger(BClass.class.getName())时,如果没有定义了名为A.B.BClass的记录器,那会尝试返回名为A.B的记录器的对象;如果又没有定义名为A.B的记录器,它会尝试返回名为A的记录器的对象;如果也没定义名为A的记录器,它就会返回根记录器的对象,而根记录器是必须存在的,所以你总能得到一个记录器对象。
好了,现在我们回到前面的问题,我们为什么总要通过Logger.getLogger(BClass.class.getName())这种以类全名作为参数来取得记录器对象呢?其实这是为了管理方便。因为我们在定义设计Logger时也遵循类似包的规则,使设计器的名称与程序中的类包对应。如上面的假设中我们的程序中有A包,A包下有B包和C包,B包下又有类BClass,那么我们就可使设计器的名为A、A.B、A.C、A.B.BClass,以此类推。那么当我们通过类命名来取得设计器对象时,总能取到与所要的设计器最接近的设计器对象。
2.3 如何应用记录器的层次
2.3.1 如果定义及获取不同层次的记录器
任何一个记录器的使用都有两个步骤:
1) 在配置文件中定义相应的记录器。
在配置文件中定义记录器的格式有两种
? 定义根记录器的格式为
log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN
? 定义一个非根记录器的格式为
log4j.logger.loggerName1 = [ level ], appendName1,…appendNameN
……
log4j.logger.loggerNameM = [ level ], appendName1, …appendNameN
我们可以定义任意个非根记录器。
2) 在代码中调用Logger类的取得记录器方法取得相应的记录器对象。
要取得根记录器对象可通过Logger.getRootLogger()函数,要取得非根记录器可通过Logger.getLogger()函数。
理论知道就讲到这里,纸上得来终觉浅,下面,我们来小小演练一下。
例4-a:
package TestLog4j;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority;
import TestLog4j.TestLog4j2.TestLog4j2;

public class TestLog4j 
{
static Logger logger = Logger.getLogger(TestLog4j.class.getName()); //(2)
public TestLog4j(){}

public static void main(String[] args)
{
//同时输出到控制台和一个文件的实例并实现了Logger的继承
PropertyConfigurator.configure("F://nepalon//log4j2.properties");

logger.debug("Start of the main() in TestLog4j");
logger.info("Just testing a log message with priority set to INFO");
logger.warn("Just testing a log message with priority set to WARN");
logger.error("Just testing a log message with priority set to ERROR");
logger.fatal("Just testing a log message with priority set to FATAL");
logger.log(Priority.WARN, "Testing a log message use a alternate form");
logger.debug(TestLog4j.class.getName());
TestLog4j2 testLog4j2 = new TestLog4j2(); //(1)
testLog4j2.testLog();
}
}
在类TestLog4j中我们调用了另一个类TestLog4j2,下面看一下类TestLog4j2的代码。
例4-b:
package TestLog4j.TestLog4j2;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority;

public class TestLog4j2 
{
static Logger logger = Logger.getLogger(TestLog4j2.class.getName()); //(1)
public TestLog4j2(){}

public void testLog()
{
//同时输出到控制台和一个文件的实例
PropertyConfigurator.configure("F://nepalon//log4j2.properties");
logger.debug("2Start of the main()");
logger.info("2Just testing a log message with priority set to INFO");
logger.warn("2Just testing a log message with priority set to WARN");
logger.error("2Just testing a log message with priority set to ERROR");
logger.fatal("2Just testing a log message with priority set to FATAL");
logger.log(Priority.DEBUG, "Testing a log message use a alternate form");
logger.debug("2End of the main()");
}
}
最后我们来看一下配置文件。
例4-c:
log4j2.properties文件内容
#1区
#### Use two appenders, one to log to console, another to log to a file
log4j.rootLogger = debug, stdout

#2区
#Print only messages of priority WARN or higher for your category
log4j.logger.TestLog4j= , R
log4j.logger.TestLog4j.TestLog4j2=WARN

#3区
#### 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

#4区
#### Second appender writes to a file
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=F://nepalon//classes//TestLog4j//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=%d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n
先看一下运行结果。
在控制台中的结果为:
DEBUG [main] (?:?) - Start of the main() in TestLog4j
INFO [main] (?:?) - Just testing a log message with priority set to INFO
WARN [main] (?:?) - Just testing a log message with priority set to WARN
ERROR [main] (?:?) - Just testing a log message with priority set to ERROR
FATAL [main] (?:?) - Just testing a log message with priority set to FATAL
WARN [main] (?:?) - Testing a log message use a alternate form
DEBUG [main] (?:?) - TestLog4j.TestLog4j
WARN [main] (?:?) - 2Just testing a log message with priority set to WARN
ERROR [main] (?:?) - 2Just testing a log message with priority set to ERROR
FATAL [main] (?:?) - 2Just testing a log message with priority set to FATAL
输出文件的结果为:
2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - Start of the main() in TestLog4j
2003-12-19 04:19:44:INFO main TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Testing a log message use a alternate form
2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - TestLog4j.TestLog4j
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to WARN
2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to ERROR
2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to FATAL

首先,先来看一下配置文件都有些什么东西。
1) 在1区中定义了一个根记录器。这个根记录器具有DEBUG级别并有一个名称为stdout的输出端appender。
2) 2区中的内容是这一节的重点,也是应用到记录器层次的地方,但其实也只有两句,充分体现了log4j的简单性。在这里,我们定义了两个名称分别为TestLog4j和TestLog4j.TestLog4j2设计器。
? 在定义TestLog4j记录器时没有指定级别,所以它的级别继承自它的父记录器,即要记录器,所以它的级别也为DEBUG。在定义TestLog4j记录器时又定义了一个名称为R的输出端,所以它的输出端有两个,一个从根记录器继承而来的名为stdout的输出端,另一个为在此定义的名为R的输出端。在此需要注意的是,在定义记录器时必须先定义记录器的级别,然后才是记录器的输出端。如果只想定义输出端而不定义级别,则虽然级别可以为空,但逗号分隔符不能省略。如定义TestLog4j记录器的做法。
? 在定义TestLog4j.TestLog4j2记录器时又指定了它的级别,由于一个记录器的级别只能有一个,所以新指定的级别将覆写掉它的父记录器的级别(这就象Java中的多态)。我们没有定义TestLog4j.TestLog4j2记录器的输出端,所以它的输出端将从它的父记录器中继承而来。它的父记录器为estLog4j记录器,所以它和estLog4j记录器一样具有两个名称分别为stdout和R的输出端。
3) 剩下的3区和4区分别设置了两个输出端的参数值。
接下来,回到我们的代码,看一下是如何取得记录器,在取记录器时又发生了什么。
1) 例4-a中的代码(2)中,语句Logger.getLogger()中的参数TestLog4j.class.getName()的值为TestLog4j. TestLog4j,所以此语句的结果是取得一个名为TestLog4j. TestLog4j的记录器的对象。但在配置文件中并没有定义这样的记录器,所以最终将返回与所需的名称TestLog4j. TestLog4j最接近的记录器对象,即名为TestLog4j的记录器的对象。
2) 例4-b中的代码(1)的原理与例4-a中的代码(2)相似,期望取得的是名为TestLog4j.TestLog4j2. TestLog4j2的记录器对象,但最终返回的是TestLog4j.TestLog4j2记录器的对象。
三 log4j与J2EE的结合
到目前为止,这篇文章讲的都是如何在application中应用log4j,而Java现在的应用主流是J2EE和J2ME。现在,我们来看一下要如何在J2EE开发中应用log4j。其实在Web application中应用log4j也很简单,与在application中应用log4j不同之处就是要在所有应用log4j的代码之前对log4j进行初始化。所以,我们在web application中就要把log4j的初始化工作独立出来,把它放在Servlet中。下面,我们看一个例子。
例5-a:
进行初始化的Servlet:
import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* log4j.jar的初始化类,参考web.xml
*/
public class Log4jInit extends HttpServlet 
{
public void init() 
{
//通过web.xml来动态取得配置文件
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");

// 如果没有给出相应的配置文件,则不进行初始化
if(file != null) 
{
PropertyConfigurator.configure(prefix+file); //(1)
}
}

public void doGet(HttpServletRequest req, HttpServletResponse res) 
{} 
}
下面来看一下这个Servlet在web.xml中的定义。
例5-b:
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>TestLog4j.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-init-file</param-name>
<param-value>sort.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
因为log4j的初始化要在所有的log4j调用之前完成,所以在web.xml文件中,我们一定要把对应的Servlet定义的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。
完成了这两个步骤这后,我们就可以象在application开发中一样在web application任何地方应用log4j了。下面是在javabean中的应用的一个例子。
例5-c:
import org.apache.log4j.Logger;

public class InfoForm 
{
static Logger logger = Logger.getLogger(InfoForm.class);

protected String title;
protected String content;

public InfoForm() {}

public void setTitle(Object value) 
{
logger.debug("nepalon:title = " + title);
title = value;
}

public String getTitle() 
{
logger.debug("nepalon:title = " + title);
return title;
}

public void setContent(String value) 
{
content = value;
logger.debug("nepalon: content() = " + content);
}

public String getContent() 
{
logger.debug("nepalon: content = /n" + content);
return content;
}
}

Log4j进阶使用教程与高级配置详解 Log4j是一个灵活且功能强大的Java日志记录框架,它可以帮助开发者记录应用程序中的日志信息。由于其灵活的配置特性,使得Log4j成为最流行的日志框架之一。Log4j不仅支持多种日志输出方式,还能满足不同环境下的日志管理需求。日志级别是日志记录中一个非常关键的概念,它决定了日志消息的重要性和优先级。在Log4j中,常见的日志级别按照严重性从低到高排序如下:DEBUG: 此级别主要用于开发和调试阶段,记录了详细的系统运行信息。这些信息对开发者理解应用程序的执行流程非常有帮助。INFO。 阅读详情

相关推荐

计算机组成原理课设

计算机组成原理课程设计

qq_63306482的博客 8055

log4j2+ELK

问题初衷 最近有个项目需求,需要统计下用户app的使用情况,比如:什么时候登录的,查询了什么内容等信息。 解决方案 1.定义用户轨迹模型,每步操作都写到数据库中,然后在前端展示。 优点:可以针对业务需求自定义模型,操作灵活,有针对性。 缺点:扩展能力需要靠自己设计,统计展示画面需要自己做。 2.用现成的用户数据分析平台,网上有很多成熟...

weixin_34242331的博客 824

2024“华为杯”中国研究生数学建模竞赛(A题)深度剖析_数学建模完整过程+详细思路+代码全解析

目标是优化风力涡轮机的功率调度,使其在给定的实时风速数据下,最小化涡轮机关键组件(如塔架和主轴)的疲劳损伤。问题的挑战在于,考虑通信延迟和测量噪声的同时,要确保功率输出与风速变化的响应快速且准确。

2401_82549447的博客 6629

log4j日志说明

日志论       在应用程序中输出日志有有三个目的: (1 )监视代码中变量的变化情况,把数据周期性地记录到文件中供其他应用进行统计分析工作。 (2 )跟踪代码运行进轨迹,作为日后审计的依据。 (3 )担当集成开发环境中的调试器,向文件或控制台打印代码的调试信息。   Apache 能用日志包(Commons Logging Package )是Apache 的一个开放源代码项目,它

javaerSir的专栏 1111

DAC60501与STM32的I2C通信实战:从寄存器配置到电压输出

本文详细介绍了如何使用STM32通过I2C通信驱动DAC60501数模转换器,实现精确的模拟电压输出。内容涵盖从硬件连接到软件模拟I2C驱动编写,再到DAC寄存器配置与电压计算的全流程实战指南,并提供了关键的驱动实例代码和常见问题调试技巧,帮助开发者快速掌握这一嵌入式开发中的实用技能。

weixin_29197835的博客 367

SpringBoot使用Graylog日志收集

本文介绍SpringBoot如何使用Graylog日志收集。 1.Graylog介绍 Graylog是一个生产级别的日志收集系统,集成Mongo和Elasticsearch进行日志收集。其中Mongo用于存储Graylog的元数据信息和配置信息,ElasticSearch用于存储数据。 架构图如下: 生产环境配置图如下: 2.安装Graylog 在官方文档上推荐了很多种安装的方式,这里以d...

weixin_34419321的博客 385

嵌入式Linux开发:手把手教你调试OV9281摄像头Sensor(基于全志平台DTS配置)

本文详细解析了嵌入式Linux开发中OV9281摄像头Sensor的调试全流程,重点介绍了基于全志平台的DTS配置指南。从硬件信号检测到软件驱动配置,包括设备树关键参数设置、内核驱动适配实战及图像质量调优技巧,为开发者提供了一套完整的调试方案,助力工业视觉和边缘计算设备的开发。

weixin_28716769的博客 371

log4j使用进阶[转]

 转载地址: http://www.chinaitpower.net/A200507/2005-07-24/166960.html二 动态配置log4j1 配置外部配置文件来配置的基本步骤1.1 一个运用配置文件的实例Log4j之所以能成功的原因之一是它的灵活性。但如果只是简单的调用BasicConfigurator.configure()来进行配置工作,那么所有的配置都是在函数中写死的,以后

Blog内容迁移至dolphin8.cn 849

STM32与K210串口通信

这篇文章是为了填上一篇埋下的坑,k210和STM32通过串口通信,我是采用数据包的形式发送数据的,因为K210发送的数据有几种,采用数据包的形式发送比较安全。本文代码运行的平台是STM32F103C8T6和K210 Dock,只涉及到K210发送数据给STM32,stm32将接受到的数据显示到0.96寸OLED屏上。

qq_70715693的博客 3万+

[Bug已解决] CUDA error 尽管 CUDA 可用且 GPU 受支持-通用排查 RuntimeError 解决方案

[Bug已解决] CUDA error 尽管 CUDA 可用且 GPU 受支持-通用排查 RuntimeError 解决方案

一键难忘的博客 2415

log4j使用进阶

动态配置log4j1 配置外部配置文件来配置的基本步骤1.1 一个运用配置文件的实例Log4j之所以能成功的原因之一是它的灵活性。但如果只是简单的调用BasicConfigurator.configure()来进行配置工作,那么所有的配置都是在函数中写死的,以后修改配置就要修改原代码,这就不能体现出log4j的灵活性了,所以基本上不会通过BasicConfigurator.configure()来

旅行人生 1173

假期搞定!2026国社科申报AI全攻略指南:从选题到创新,7大核心要点手把手教你!

最后给大家推荐的400多所高校教师都在用的AI平台——高级学术版专业应用平台,集成了国际主流学术应用,以及ChatGPT、Claude、Gemini、Grok等Al大模型的高级版本平台,还有,可以辅助大家高效完成科研和学术写作任务,当然撰写硕博论文,课题、职称论文、国社科、国自然基金本子也是手拿把掐。你的任务是:用高度凝练的方式说明在(某一明确国家战略 / 政策方向,如:中国式现代化、共同富裕、基层治理现代化、数字中国、文化强国、国家安全等)背景下,我究竟要研究一个什么“具体而可操作的问题”。

智能AI让学术科研更容易 624

log4j使用进阶(转载)

我们在编程时经常不可避免地要使用到一些日志操作,比如开发阶段的调试信息、运行时的日志记录及审计。调查显示,日志代码占代码总量的4%。通常大家可以简单地使用System.out.println()语句输出日志信息,但是在发布时,通常不想在正式的版本中打印这些开发时的调试信息,于是又要手工地把这些语句删除,所以大量的这样的System.out.println()调试语句会带来麻烦。更多做法是把它封闭一

wenzi1984的专栏 551

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Log4j2 进阶使用

点击上方“JAVA乐园”,选择“置顶公众号”有内涵有价值的文章第一时间送达!使用属性在复杂的项目中,可能有一些约定的属性比如项目名称、配置文件路径等等。这些属性可能会在多...

天行健,君子以自强不息;地势坤,君子以厚德载物。 271

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

log4j2到oracle,Log4j2进阶使用(更多高级特性)

# 1.高级进阶说明本文介绍Log4j2高级进阶使用,基于[Log4j2进阶使用(按大小时间备份日志)](https://www.jianshu.com/p/c7ae523f6e82),介绍更多的高级特性,本文基于上文给出的完整log4j2.xml,修改对应的配置项,演示高级特性的使用。基本使用请参考[Log4j2基本使用入门](https://www.jianshu.com/p/a344409c...

weixin_30368405的博客 385

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Log4j2 进阶使用(转载)

使用属性 在复杂的项目中,可能有一些约定的属性比如项目名称、配置文件路径等等。这些属性可能会在多个日志的配置中用到。这样就可以将这些属性配置到Log4j2的配置文件中,方便在多个Logger中共享。 定义属性需要在配置文件中添加properties节点,然后添加多个property。配置完成之后使用${property_name}就可以在项目中引用了。正如下面的一个配置文件中PatternLayo...

向心行者 516

log4j2 pattern 行号_Log4j2进阶使用(Pattern Layout详细设置)

1.进阶说明通过配置Layout打印格式化的日志,Log4j2支持很多的Layouts:CSV GELF HTML JSON Pattern Serialized Syslog XML YAML本文仅介绍Pattern Layouts的详细使用。本文基于Log4j2基本使用入门。请先参考上面的基本使用入门。2.Pattern LayoutsPattern Layouts是一个灵活的布局,是最常用的...

weixin_35172715的博客 1408

Log4j2进阶使用(Pattern Layout详细设置)

1.进阶说明 通过配置Layout打印格式化的日志, Log4j2支持很多的Layouts: CSV GELF HTML JSON Pattern Serialized Syslog XML YAML 本文仅介绍Pattern Layouts的详细使用。 本文基于Log4j2基本使用入门。 请先参考上面的基本使用入门。 2.Pattern Layouts Pattern Layouts是一个灵活的布局, 是最常用的日志格式配置。 该类的目标是格式化一个日志事件并返回结果, 结果的格式取决于转换模式。 转换模

BigManing的博客 5713

javaSE--进阶十八(junit,Log4j)

Junit单元测试 Junit单元测试,它可以让方法独立执行。这样我们每写完一个方法,就可以使用Junit运行,检查方法的正确性。 //运行在@Test直接之前 @Before public void before(){ System.out.println("运行在Test之前"); } //加上@Test注解的方法,可以独立执行。 //绿色:表示正常执行 //红色:执行出现问题 @Test public void show(){ int a=10; int b=20;

zhenyu93的博客 143

log4j使用方法(二)—— log4j配置进阶

  前面的一篇基本能够让log4j跑起来了,这里再稍微深入一点的学习log4j的配置。   log4j的配置方式总共分为两种:通过程序配置和通过配置文件配置。而通过配置文件配置又可以分为两种:XML文件和key-value方式配置。我比较喜欢key-value的配置方式,因为这样清晰,易改,所以这里也就只介绍key-value的配置方式了。   log4j的配置文件主要做了下面几件事情:  ...

weixin_30677073的博客 114
上一篇: Axis配置
下一篇: Java调试技术
baileyfu
博客等级 码龄21年 9粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值