Log4j2示例教程–配置,级别,附加程序

时间:2020-02-23 14:37:20  来源:igfitidea点击:

欢迎使用Apache Log4j2示例教程。
如果您向专家开发人员询问有关应用程序的最烦人的事情,答案可能与日志记录有关。
如果在应用程序中没有合适的日志记录,维护将是一场噩梦。

大多数应用程序都经过开发测试,单元测试,集成测试。
但是当涉及到生产时,您将始终面临独特的场景和例外。
因此,找出在特定情况下发生的事情的唯一方法是通过日志进行调试。

许多框架都提供了默认日志记录的某种方式,但是最好始终采用行业标准的日志记录机制。
Apache Log4j是使用最广泛的日志记录框架之一。
下一个版本是Apache Log4j 2,它比Log4j更好。

Log4j示例教程

在此Log4j2示例教程中,您将学习如何开始使用Apache Log4j2。
我们还将探讨Log4j2体系结构,log4j2配置,log4j2日志记录级别,附加程序,过滤器等。

  • Log4j2概述
  • Log4j2架构
  • Log4j2配置
  • Log4j2级别
  • Log4j2查询
  • Log4j2 Appenders
  • Log4j2过滤器
  • Log4j2布局
  • 您应该使用哪个Log4j2级别
  • Log4j2教程摘要

Log4j2概述

在应用程序中使用Logging API并非奢侈,这是必须的。
Log4j是一个开放源代码库,已在Apache软件下发布并获得许可。

您可以使用Eclipse Debugging或者其他一些工具来调试应用程序,但这在生产环境中还不够可行。

日志记录机制将为您提供一些普通调试中找不到的好处。

Category/Operation (Debugging, Logging)DebuggingLogging
Human InterventionThere's a need for human interventionNo need for human intervention
Persistent MediumCan't be integrated with persistent storageCan be integrated with persistent storage (Files, Database, NoSQL database, etc.)
Jan used for AuditingCan't be used for achieving auditingCan be used for achieving auditing if it's used efficiently
Sufficient for complicated structure and flowNot sufficient; you Jan get lost with flow.Sufficient
ProductivityLess productiveMore productive

正如您在上面看到的,使用日志记录机制将更有效,维护成本也更少。

Apache Log4j是用于登录Java应用程序的领先工具,因此您应该使用它。

Log4j2架构

在继续进行Log4j示例教程之前,最好先了解一下Log4j2架构。
下图显示了Log4j2 API中的重要类。

这是上述架构的详细说明:

  • 应用程序将向LogManager询问具有特定名称的Logger。

  • LogManager将找到适当的LoggerContext,然后从中获取Logger。

  • 如果尚未创建Logger,则将根据以下三个选择创建Logger并将其与LoggerConfig关联:将创建具有相同名称的Logger实例并将其与LoggerConfig关联。
    例如getLogger(App.class)中的App.class将被评估为字符串com.theitroad.App。
    LoggerConfig名称与完全限定的类名称(软件组件)相同。

  • 将创建Logger实例并将其与具有相同Loggers父程序包的LoggerConfig关联。
    例如getLogger(" com.theitroad")中的"com.theitroad`。

  • 将创建Logger实例并将其与Root LoggerConfig关联。
    如果没有配置文件,或者获取的记录器名称未在记录器声明中定义,则将使用Root LoggerConfig。

  • LoggerConfig对象是根据配置文件中的Logger声明创建的。
    LoggerConfig还用于处理LogEvents并将它们委派给已定义的Log4j2 Appender。

  • 就其存在而言,根记录器是一个特例。
    它始终存在,并且在任何记录器层次结构的顶部。

  • 您可以使用以下语句获取root记录器:

  • log4j2记录器的名称区分大小写。

  • 除root记录器外,所有记录器都可以通过将其名称传递到LogManager.getLogger()中来获得。

  • LoggerContext是Logging系统的主角,因为您的应用程序内部可能有多个LoggerContext。
    对于每个LoggerContext,应设置一个活动配置。

  • Log4j2配置包含所有Logging系统资产; LoggerConfig,Appender,过滤器等。

  • 通过传递相同的名称来调用LogManager.getLogger()将始终返回完全相同的记录器实例的引用。

  • 日志记录系统的配置通常通过应用程序初始化完成。
    这可以采取不同的形式。
    以编程方式或者通过读取log4j2配置文件。

每个记录器都与一个LoggerConfig对象相关联,LoggerConfig对象集由一个记录器层次结构组成。
这个概念称为Logger层次结构。

Logger层次结构由具有父子关系的LoggerConfig对象集组成。
每个Logger层次结构中最顶层的元素是Root Logger。

如果Log4j2找不到配置文件,则仅将Root Logger用于日志记录级别为ERROR的日志记录。
下图显示了在这种情况下将收到的警告消息。

错误StatusLogger找不到log4j2配置文件。
使用默认配置:仅将错误记录到控制台。

下表显示了Logger层次结构中的父子关系。

LoggerConfig (Is A)Rootcomcom.theitroadcom.theitroad.logging
RootXChilddescendantdescendant
comParentXChilddescendant
com.theitroadAncestorParentXChild
com.theitroad.loggingAncestorAncestorParentX

为了阐明父子关系,上表的内容如下:

  • 根是com的父代。

  • 根是com.theitroad的祖先。

  • 根是com.theitroad.logging的祖先。

  • com是Root的孩子。

  • com是com.theitroad的父级。

  • com是com.theitroad.logging的祖先。

  • com.theitroad.logging是com.theitroad的子级,依此类推。

LoggerConfig的一个实例被称为是另一个LoggerConfig的祖先。
如果其名称后跟一个点是后代名称的前缀。

LoggerConfig的一个实例被称为另一个LoggerConfig的父级;如果两者之间没有交错名称。

Log4j2配置

应用程序中有多种使用Log4j2配置的方法。

  • 使用以XML,JSON,YAML或者属性文件编写的配置文件。

  • 通过创建配置工厂和配置实现以编程方式。

  • 通过调用配置界面中公开的API,以编程方式进行。

  • 通过调用内部记录器类上的方法以编程方式。

我们将主要关注配置文件。
但是,如果您想为某些特定的Logger配置特定的日志记录策略,也应该了解编程方法。

首先,让我们考虑一下您没有提供配置文件的情况。
Log4j2实现假设有一个名为log4j.configurationFile的系统变量来指向log4j2配置文件的位置。

Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
Logger logger = LogManager.getRootLogger();

一个简单的log4j2配置文件如下所示。

configuration.xml:

package com.theitroad;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
  public static void main( String[] args ) {
  	Logger logger = LogManager.getRootLogger();
  	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
  }
}

这是上面列出的代码的详细说明:

  • 应用程序通过调用LogManager的getRootLogger方法引用了Root记录器。

  • 从LogManager引用记录器已启动Log4j系统。

  • Log4j将检查log4j.configurationFile系统属性以确定log4j2配置文件。
    Log4j配置可以用JSON,YAML和XML编写。

  • 我们可以通过`System.setProperties(" log4j.configurationFile"," FILE_PATH")"或者通过将其作为JVM参数传递来设置log4j.configurationFile系统属性,如下图所示。
    还要注意文件协议前缀。

  • 如果未定义系统属性,则配置顺序优先于以下属性:Property ConfigurationFactory将在类路径中查找log4j2-test.properties。

  • YAML ConfigurationFactory将在类路径中查找log4j2-test.yaml或者log4j2-test.yml。

  • JSON ConfigurationFactory将在类路径中查找log4j2-test.jsn或者log4j2-test.json。

  • XML ConfigurationFactory将在类路径中查找log4j2-test.xml。

  • 属性ConfigurationFactory将在类路径中查找log4j2.properties

  • YAML ConfigurationFactory将在类路径中查找log4j2.yml或者log4j2.yaml。

  • JSON ConfigurationFactory将在类路径中查找log4j2.jsn或者log4j2.json。

  • XML ConfigurationFactory将在类路径中查找log4j2.xml。

  • 如果未提供配置文件,则将使用DefaultConfiguration进行配置,这将引导您进行默认行为设置:将使用Root logger。

  • 根记录器级别将设置为ERROR。

  • 根记录器会将记录消息传播到控制台。

  • PatternLayout设置为%d {HH:mm:ss.SSS} [%t]%-5level%logger {36}-%msg%n`

使用log4j2配置文件可使log4j2的配置变得如此简单,但让我们看看如何以编程方式对其进行配置。
这就是使用ConfigurationFactory的全部内容。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="trace">
    <AppenderRef ref="Console"
  </Root>
</Loggers>
</Configuration>
  • 您可以使用Log4j2提供的任何ConfigurationFactory或者使用默认的。
    我们使用XMLConfigurationFactory来获取ConfigurationFactory的实例。

  • 工厂将通过传递相应的配置文件为您提供所需的配置参考实例。

  • 配置实例将与LoggerContext结合使用以启动日志记录系统。

  • 已配置控制台Appender并以默认布局将其添加到配置实例中。
    该Appender会将消息打印到您的控制台中。

  • 已使用提供的名称LEVEL创建了LoggerConfig实例,并且未使用任何过滤器。
    将为该LoggerConfig实例分配创建的Appender。

  • 将LoggerConfig实例添加到配置实例中。

  • 使用定义的名称创建LoggerContext的新实例。

  • 已为LoggerContext实例传递了配置实例,并从后者开始调用。

  • 已从LoggerContext获取记录器实例。
    此记录器实例将用于触发Log事件集。

  • Logger实例触发了三个事件,这将在Log4j2 Levels部分中进行说明。

  • com logger已配置为打印出致命级别的消息。

  • 默认情况下,根记录器配置为打印出级别为ERROR的消息。

  • " com"记录器不会记录错误消息,因为它的级别为"致命"。

可以通过使用YAML,JSON或者属性文件来完成相同的配置。
但是,log4j2属性文件配置与log4j属性文件不同,因此请确保您不尝试将log4j属性文件配置与log4j2一起使用。
它将抛出以下错误;

package com.theitroad;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
public class App
{
  public static void main( String[] args ) throws FileNotFoundException, IOException {
 
  	//Get instance of configuration factory; your options are default ConfigurationFactory, XMLConfigurationFactory,
  	//	YamlConfigurationFactory & JsonConfigurationFactory
  	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
 
  	//Locate the source of this configuration, this located file is dummy file contains just an empty configuration Tag
  	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
 
  	//Get a reference from configuration
  	Configuration configuration = factory.getConfiguration(configurationSource);
 
  	//Create default console appender
  	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
 
  	//Add console appender into configuration
  	configuration.addAppender(appender);
 
  	//Create loggerConfig
  	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
 
  	//Add appender
  	loggerConfig.addAppender(appender,null,null);
 
  	//Add logger and associate it with loggerConfig instance
  	configuration.addLogger("com", loggerConfig);
 
  	//Get context instance
  	LoggerContext context = new LoggerContext("theitroadLoggerContext");
 
  	//Start logging system
  	context.start(configuration);
 
  	//Get a reference for logger
  	Logger logger = context.getLogger("com");
 
  	//LogEvent of DEBUG message
  	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
 
  	//LogEvent of Error message for Logger configured as FATAL
  	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
 
  	//LogEvent of ERROR message that would be handled by Root
  	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
  }
}

处理上面的代码时,将为您提供以下输出:

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

第一行日志来自com logger,第二行来自Root Logger。
com logger错误消息未打印,因为其级别为致命。

Log4j2级别

您可以在上面的代码示例中看到,每次我们定义LoggerConfig时,我们还提供日志记录级别。
默认情况下,log4j2日志记录是累加的。
这意味着当使用特定的记录器时,还将使用所有父记录器。
下图阐明了这种情况。

在此需要澄清:

  • 如前所述,每个记录器都与LoggerConfig实例相关联。
    此loggerConfig已在配置范围内定义。

  • 日志记录的级别可以在LoggerConfig范围内确定。

  • 您可以通过其名称,父程序包或者指向根记录器本身来获取记录器。

  • 根记录器是每个LoggerConfig层次结构的顶级节点。

  • 一旦您获得com.theitroad记录器并启动logEvent进行记录,loggerConfig(net.theitroad)将记录该消息,并且该消息还将在层次结构中向上传播,而无需考虑父级记录级别。
    因此,日志事件将传播到com和Root记录器,它们还将根据定义的级别分别记录消息。

  • 获得com记录器并启动logEvent进行记录后,loggerConfig(com)将记录该消息,并且该消息也将在层次结构中向上传播,而无需考虑父级的记录级别。
    也就是说,根记录器将传播日志事件,并且还将记录消息。

  • net.theitroad层次结构的情况相同。

  • 在接下来的几节中,将添加更多关于添加剂概念的说明。

  • 父母可以通过使用筛选器概念或者将添加指示器设置为false来忽略该消息,因此日志事件不会传播到父母。

  • 如果各个loggerConfig的级别高于日志事件级别,则记录器有可能忽略该消息。

现在,让我们看一下与上述可加性概念相关的示例:

Logger Name :: com :: Passed Message ::
00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages
import net.NetApp;
import net.theitroad.NettheitroadApp;
import com.ComApp;
import com.theitroad.localtheitroadApp;
public class Main {
	public static void main(String [] args){
		new ComApp();
		new ComtheitroadApp();
		new NetApp();
		new NettheitroadApp();
	}
}
package com.theitroad;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ComtheitroadApp {
	public ComtheitroadApp(){
		Logger logger = LogManager.getLogger(ComtheitroadApp.class);
		logger.trace("COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::");
	}
}
package net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetApp {
	public NetApp(){
		Logger logger = LogManager.getLogger(NetApp.class);
		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
	}
}

而log4j2配置文件如下所示:

package net.theitroad;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NettheitroadApp {
	public NettheitroadApp(){
		Logger logger = LogManager.getLogger(NettheitroadApp.class);
		logger.error("NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::");
	}
}

如果执行Main类,则会发现以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="ERROR">
    <AppenderRef ref="Console"
  </Root>
	<logger name="com" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net.theitroad" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
</Loggers>
</Configuration>

以下是上面列出的代码的详细说明:

  • 配置文件包含五个已定义的loggerConfig实例,分别是Root,com,com.theitroad,net和net.theitroad。
    就像上面显示的Logger层次结构一样。

  • 根目录级别配置为ERROR,实际上是默认值。

  • com&com.theitroad级别配置为TRACE。

  • net&net.theitroad级别配置为ERROR。

  • 您可能会注意到,ComAPP和ComtheitroadApp记录器消息分别显示了两次和三次。
    这些消息根据ComApp和ComtheitroadApp的Logger层次结构分别显示在com&com.theitroad软件包中。
    对于NetApp和NettheitroadApp类,我们也有类似的情况。

  • 默认情况下,将加性指标设置为true来传播父级。

10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.170 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
10:34:47.170 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
10:34:47.170 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
10:34:47.171 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
10:34:47.171 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

因此,如果我们将Log的com的LoggerConfig更改为INFO并保留整个程序不变,该怎么办:

<p>Logging Space takes into consideration Levels of log events and the loggerConfig's level in addition to Logger Hierarchy.</p>

然后结果如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="ERROR">
    <AppenderRef ref="Console"
  </Root>
	<logger name="com" level="INFO">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net.theitroad" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
</Loggers>
</Configuration>
  • 当然,您可能会注意到ComAPP日志事件已被忽略,这是由于com程序包的loggerConfig定义了级别。
    INFO(400)级别小于日志事件的级别TRACE(600)。
    因此,ComApp的消息将不再显示,并且要使其显示,您需要将LoggerConfig的com级别修改为TRACE(600)或者ALL(Integer.MAX_VALUE)。
11:08:10.305 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
11:08:10.305 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
11:08:10.305 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.308 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
11:08:10.308 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
11:08:10.308 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

下表显示了log4j2级别和每个级别的权重:

LEVELWeight
OFF0
FATAL100
ERROR200
WARN300
INFO400
DEBUG500
TRACE600
ALLInteger.MAX_VALUE

可以肯定的是,上面的表对语言的解释远不止于此,它可以为您说明在LoggerConfig级别为INFO时未显示日志事件TRACE的主要原因。

<p>To make sure Log events have been displayed, the LoggerConfig's Level should be greater than or equal to Log event's level.</p>

但是,如果我们从配置中删除com.theitroad的LoggerConfig并为com.theitroad.logging添加了一个新文件以使配置文件如下所示,将会发生什么:

<p>Notice that the propagation of log events up in the logger hierarchy is beyond this computation and it ignores the levels.</p>

您可能会发现下图更方便您了解上述log4j2配置中发生的情况。

以下是对上面显示的图的一些说明,以及它如何影响记录事件的行为:

  • 当名为com.theitroad.logging的Logger引发日志事件时,与该名称关联的LoggerConfig(即com.theitroad.logging)已用于处理它并打印出消息。

  • 由于com.theitroad.logging的LoggerConfig的additive属性默认设置为true,因此已为父级传播了日志事件,在本例中为com.theitroad。

  • 未在配置中定义com.theitroad LoggerConfig,因此不会执行任何操作,并且Log事件将传播到com,然后传播到Root LoggerConfig实例。

  • Com&Root将接收Log事件并打印出来,而不管发送的级别如何。

作为上述要点的结果,您将看到以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="ERROR">
    <AppenderRef ref="Console"
  </Root>
	<logger name="com" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad.logging" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net.theitroad" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
</Loggers>
</Configuration>

您可能会注意到以下几点:

  • com软件包中的日志事件已显示两次。
    一个用于com,第二个用于Root。

  • com.theitroad上的日志事件已显示两次。
    一个用于com,第二个用于Root。
    即使以前是3次,但目前com.theitroad的LoggerConfig都不存在,因此com.theitroad软件包可能没有日志记录,并且该事件将传播给com和Root。

  • com.theitroad.logging的日志事件已显示三次,一次用于com.theitroad.logging软件包,第二次用于com,第三次用于Root。
    根据Logger层次结构传播,应该四次显示它,但是由于缺少com.jounraldev LoggerConfig,它显示了三遍。

14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.636 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
14:08:37.636 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
14:08:37.637 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.640 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:08:37.640 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:08:37.640 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

但是,如果您在配置文件中定义了com.theitroad LoggerConfig却错过了指定LoggerConfig的级别时该怎么办。

幸运的是,Logger层次结构的概念将在这里节省您的时间,而com.theitroad将从其父级继承其级别值。
以下是一个示例配置文件,后跟用于每个记录器配置的记录级别的表。

<p>In case you've defined a com.theitroad LoggerConfig instance with no Level specified, it will inherit Level of its parent.</p>
Logger NameAssigned LoggerConfigLoggerConfig LevelLogger Level
RootRootERRORERROR
comcomTRACETRACE
com.theitroadcomTRACETRACE
com.theitroad.loggingcom.theitroad.loggingTRACETRACE
  • com.theitroad.logging软件包已经与Log级TRACE的LoggerConfig关联。

  • com.theitroad软件包已与LoggerConfig关联,但未指定日志级别,因此它将继承其父日志级别,并确保该值将为com软件包的TRACE。

  • com软件包已经与Logger级别为TRACE的Loggerconfig关联。

  • 默认情况下,根将ERROR作为日志级别。

  • 如果未声明com软件包,则com.theitroad LoggerConfig将继承Root的日志级别。

以下是com.theitroad继承com日志级别时的执行结果:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="ERROR">
    <AppenderRef ref="Console"
  </Root>
	<logger name="com" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad.logging" level="TRACE">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net.theitroad" level="ERROR">
		<AppenderRef ref="Console"
	</logger>
</Loggers>
</Configuration>

而以下结果将是如果您删除为com软件包声明LoggerConfig的情况:

14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.421 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
14:41:37.421 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
14:41:37.421 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
14:41:37.422 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:41:37.423 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:41:37.423 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

您可能会注意到,没有关于com和com.theitroad的消息已记录,原因如下。

  • 删除与com软件包关联的LoggerConfig,将忽略该软件包处提到的所有Log事件。

  • 由于配置中没有为com程序包定义LoggerConfig,因此与com.theitroad关联的LoggerConfig将从其父级继承Log Level。
    未定义Com,并且Logger层次结构已到达顶部,现在是指Root。
    根Log级别为ERROR(200),com.theitroad中的Log事件级别为TRACE(600)–请参阅ComtheitroadApp –根据定义的先前公式,LoggerConfig级别应大于或者等于Log Event,并且为false,因此否邮件将在此处显示com.theitroad。

最后但并非最不重要的是,下表显示了使用日志记录系统时可能遇到的所有可能的日志记录方案:

X (N/A)LoggerConfig LevelOFF(0)FATAL(100)ERROR(200)WARN(300)INFO(400)DEBUG(500)TRACE(600)ALL(MAX)
Event LevelXXXXXXXXX
OFF(0)XYESNONONONONONONO
FATAL(100)XNOYESYESYESYESYESYESYES
ERROR(200)XNONOYESYESYESYESYESYES
WARN(300)XNONONOYESYESYESYESYES
INFO(400)XNONONONOYESYESYESYES
DEBUG(500)XNONONONONOYESYESYES
TRACE(600)XNONONONONONOYESYES
ALL(MAX)XNONONONONONONOYES
  • 没有直接方法可用于引发OFF/ALL日志事件。

  • 主要是,要抛出OFF/ALL日志事件,可以分别使用logger.log(Level.OFF," Msg")或者logger.log(LEVEL.ALL," Msg")。

  • log方法负责根据提到的公式处理对数事件。

14:43:28.809 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.812 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:43:28.812 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::
14:43:28.812 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

日志事件将被接受以进行进一步处理-这非常重要,因为即使使用Log4j2过滤器也可以阻止处理某些事件,但您有能力防止该事件被处理。

您可以将添加剂属性设置为false,以避免日志事件传播到父记录器。

在下面的示例中,您之前看到的示例相同,但是这次具有可加性属性,因此您可能会注意到其中的区别。

<p>Handling equation says: If the LoggerConfig Level's is greater than or equal to Log event's level the event would be accepted for further processing.</p>

执行结果如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
  <Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
  </Console>
</Appenders>
<Loggers>
  <Root level="ERROR">
    <AppenderRef ref="Console"
  </Root>
	<logger name="com" level="TRACE" additivity="false">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad" additivity="false">
		<AppenderRef ref="Console"
	</logger>
	<logger name="com.theitroad.logging" level="TRACE" additivity="false">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net" level="ERROR" additivity="false">
		<AppenderRef ref="Console"
	</logger>
	<logger name="net.theitroad" level="ERROR" additivity="false">
		<AppenderRef ref="Console"
	</logger>
</Loggers>
</Configuration>

您可能会注意到,日志事件没有传播到其父级记录器。

Log4j2查询

理想情况下,您可以将查找定义为可以为Logging配置文件传递值的一种方式。
Log4j2为您提供了一组不同的查询,这些查询可以独立用于设置来自不同上下文的值:

  • 上下文映射查找
  • 日期查询
  • 环境查询
  • Java查询
  • JNDI查找
  • JVM输入参数查找(JMX)
  • 主要参数查询
  • 地图查询
  • 结构化数据查询
  • 系统属性查询
  • 网页查询

您可以参考Log4j2文档以获取有关每种类型的查找的更多详细信息,但让我们在此处查看一些示例来介绍Log4j2查找的基础。

Environment Lookup表示传递环境值的方式(通过Linux etc/profile,Windows系统环境或者应用程序的启动脚本)。

如我们大多数人所知,我们能够定义一组环境值供Application使用。
让我们来看看定义环境变量的最著名的方法。

  • 使用Windows环境工具定义环境变量:右键单击计算机图标,然后选择属性。
    应显示控制面板主页。

  • 单击高级系统设置,然后打开环境变量窗口。

  • 在系统变量部分下,使用theitroad值定义变量theitroadVar。

  • 更新log4j2.xml中的PatternLayout以包含新添加的变量。

  • 通过使用启动脚本工具来定义环境变量。
    您可以使用Eclipse IDE运行脚本工具,而不是使用普通的默认脚本,单击运行菜单并选择运行配置。

  • 导航到"环境"选项卡并其中定义变量。

现在查看修改后的log4j2.xml文件,并注意环境变量的使用。

17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
17:55:30.560 [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
17:55:30.561 [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
17:55:30.562 [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

执行结果如下所示:

<Console name="Console" target="SYSTEM_OUT">
  <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:theitroadVar} $${env:theitroadSecondVar} [%t] %-5level %logger{36} - %msg%n"
</Console>

但是您在这里可能会遇到一些问题,尤其是在定义操作系统的环境变量(即Eclipse缓存)时。
理想情况下,Eclipse在运行时会缓存所有系统变量,您可以在"运行" –"运行配置" –"环境"选项卡–单击"选择"按钮下找到所有这些系统变量。

因此,当您定义它但应用程序无法识别它时,您可能会感到困惑。
即使重新启动Eclipse,也不会获得解决方案,要解决该问题,必须在安装Eclipse时执行eclipse.exe -clean。

为确保正确定义环境变量,并且系统愿意找到它们,您可以使用Log4j2 API提供的对应插件类型。

创建一个EnvironmentLookup的实例,并要求其查找某些变量以及是否已定义它,因此您可以轻松找到它们。

23:57:02.511 theitroad www.theitroad.local [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
23:57:02.517 theitroad www.theitroad.local [main] TRACE com.theitroad.localtheitroadApp - COM :: theitroad :: LEVEL :: ComtheitroadApp TRACE Message ::
23:57:02.520 theitroad www.theitroad.local [main] TRACE com.theitroad.logging.ComJounralDevLoggingApp - COM :: theitroad :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
23:57:02.523 theitroad www.theitroad.local [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
23:57:02.527 theitroad www.theitroad.local [main] ERROR net.theitroad.NettheitroadApp - NET :: theitroad :: LEVEL :: NettheitroadApp ERROR Message ::

Log4j2 Appenders

您之前已经看过如何使用查阅将变量注入配置文件中。
但是,您可能需要修改消息通过的媒介。

您可能不希望直接使用控制台,而希望使用这样的文件或者数据库存储库来确保您的消息被永久保留。
Log4j2提供了许多Appender,您可以参考log4j2文档以获取有关Appender的更多详细信息。

简单来说,下面是所有Log4j2 Appender的列表。

  • ConsoleAppender
  • AsyncAppender
  • 故障转移
  • FileAppender
  • FlumeAppender
  • JDBCAppender
  • JMSAppender
  • JPAAppender
  • MemoryMappedFileAppender
  • NoSQLAppender
  • OutputStreamAppender
  • RandomAccessFileAppender
  • RewriteAppender
  • RollingFileAppender
  • RollingRandomAccessFileAppender
  • RoutingAppender
  • SMTPAppender
  • SocketAppender
  • SyslogAppender

用于记录事件的最著名的媒介是控制台,文件和数据库。
由于该文件将保存您的消息,因此数据库可用于审核消息。
为此,本节将重点介绍如何有效地使用JDBCAppender。

JDBCAppender

JDBCAppender的主要目标是通过JDBC连接将Log事件写入关系表中。
我们不会花费太多时间来解释如何优化连接池,因为本教程并非旨在用于此目的。

但是可以肯定的是,您将获得一个完整的功能示例,该示例有助于将日志事件写入数据库。
在继续进行之前,让我们看一下所有必要的参数以及每个参数的描述,以正确配置JDBCAppender。

Parameter NameTypeDescription
NameStringRequired, The name of the Appender
ignoreExceptionsbooleanDefault value is set to true, making exceptions thrown to be logged also and then ignored.False value means the exception will be propagated for the caller.
filterFilterThe filter that should be used to make a decision whether the log events are going to behandled by this Appender or not.
bufferSizeintDefault value is zero, indicating there's no buffering have been done upon log events.Value greater than 0 would lead the Appender to buffer log events and then flush themonce the buffer reaches the limit specified.
connectionSourceConnectionSourceRequired, the connections source from which the database connections should be retrieved.
tableNameStringRequired, the name of the Table on which your log events should be persisted.
columnConfigsColumnConfig[]Required, additional information Jan be set upon those used columns and how the datashould be persisted on each of them. This can be handled with multiple <Column> elements.
Parameter NameTypeDescription
jndiNameStringRequired, full prefixed JNDI name that the javax.sql.Datasource is bound to.
Parameter NameTypeDescription
classStringRequird, The fully qualified name for a class containg a static factory method for obtaining JDBC connections.
methodbooleanRequired, The name of the static factory method for obtaining JDBC connections.
Parameter NameTypeDescription
nameStringRequired, the name of the database column
patternStringAbility to specify any legal pattern that Log event would be formatted with
literalStringAbility to specify literal value in this column (i.e. SEQ.NEXTVAL)
isEventTimestampbooleanIndicating whether the event would consider Timestamp
isUnicodebooleanFor unicode purpose as you Jan refer for Log4j2 documentationfor further details
isClobbooleanFor storing character large object, you Jan refer for Log4j2 documentationfor further details.

由于您必须使用JNDI,因此我们的示例将为Oracle数据库和Apache Tomcat 7配置连接数据源。

  • 如果您没有将Oracle数据库安装到您的环境中,可以的话,我们将不胜感激。
    如果您不太了解Oracle,建议您安装Oracle Express Edition。

  • 将Apache Tomcat 7安装到您的环境中。

  • 在Eclipse中创建一个Maven WebApp项目。

  • 确保成功创建了项目,并且如果在pom上发现任何错误,请确保对其进行修复。

  • 添加Log4j2依赖项。

EnvironmentLookup lookup = new EnvironmentLookup();
LogManager.getRootLogger().error(lookup.lookup("theitroadSecondVar"));
  • 配置上下文以包含MySQL数据源声明。
    根据Apache文档,此文件应位于Web应用程序META-INF文件夹中。
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-api</artifactId>
 <version>2.2</version>
</dependency>
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-core</artifactId>
 <version>2.2</version>
</dependency>
  • 配置数据库并创建日志表,
<Context path="/theitroadWebLogging"
	privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<Resource name="jdbc/theitroadDB" auth="Container"
			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
			url="jdbc:mysql://localhost:3306/theitroad" 
</Context>
  • 配置您的log4j2.xml如下所示:
CREATE TABLE `logging` (
`EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
`EVENT_DATE` datetime DEFAULT NULL,
`LEVEL` varchar(45) DEFAULT NULL,
`LOGGER` varchar(45) DEFAULT NULL,
`MSG` varchar(45) DEFAULT NULL,
`THROWABLE` varchar(45) DEFAULT NULL,
PRIMARY KEY (`EVENT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • 创建任何Web资源,使您无法获取记录器的引用,然后记录事件。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} $${env:theitroadVar} $${env:theitroadSecondVar} [%t] %-5level %logger{36} - %msg%n" 
		</Console>
		<JDBC name="databaseAppender" tableName="theitroad.logging">
			<DataSource jndiName="java:/comp/env/jdbc/theitroadDB" 
			<Column name="EVENT_DATE" isEventTimestamp="true" 
			<Column name="LEVEL" pattern="%level" 
			<Column name="LOGGER" pattern="%logger" 
			<Column name="MSG" pattern="%message" 
			<Column name="THROWABLE" pattern="%ex{full}" 
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" 
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" 
		</logger>
		<logger name="com.theitroad" additivity="false">
			<AppenderRef ref="databaseAppender" 
		</logger>
	</Loggers>
</Configuration>
  • 您可以选择配置ServletContextListener,以确保正确完成数据源的初始化。
package com.theitroad;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class theitroadServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
			Logger logger = LogManager.getLogger(theitroadServlet.class);
			logger.trace("theitroad Database Logging Message !");
	}
}
  • 在web.xml文件中定义Servlet。

  • 运行应用程序并访问上面定义的Servlet。
    您将在下面看到日志。

package com.theitroad;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
public class theitroadServletContextListener implements ServletContextListener{
	private InitialContext context = null;
	public void contextDestroyed(ServletContextEvent event) {
	}
	public void contextInitialized(ServletContextEvent event) {
		try {
			//Get initial context
			context = new InitialContext();
			//Get a reference for sub context env
			Context envContext = (Context)context.lookup("java:comp/env");
			//Get a reference for sub context jdbc and then locating the data source defined
			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("theitroadDB"));
		} catch (NamingException e) {
			LogManager.getRootLogger().error(e);
		}
	}
}

Log4j2过滤器

即使有用于处理Log事件的LoggerConfig候选对象,您也可以将其配置为拒绝将Log事件传递给后端Appender。
这可以通过log4j2过滤器完成。

本部分并非旨在为您提供有关在Log4j2中使用过滤器的大量侵入性教程,因为它们需要大量涉及每个过滤器的文章。
但是其中您将看到如何使用最简单的过滤器来学习该概念。

您可以使用的最简单的过滤器之一是BurstFilter,它为您提供了一种机制,可以通过在达到最大限制后通过静默丢弃事件来控制LogEvent的处理速率。

现在,您可能会在下面看到使用BurstFilter所需的所有详细信息。

Parameter NameTypeDescription
levelStringLevel of messages to be filtered
ratefloatThe average number of events per second to allow
maxBurstintegerThe maximum number of events that can occur before events are filtered for exceeding the average rate.The default is 10 times the rate.
onMatchStringAction to take when filter matches. Jan be Accept, DENY or NEUTRAL. The default is NEUTRAL
onMismatchStringAction to tale when filter doesn't match. Jan be Accept, DENY or NEUTRAL. The default is NEUTRAL

现在,查看数据库Appender中BurstFilter的位置。

Mar 15, 2014 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\theitroad\eclipse;;.
Mar 15, 2014 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:theitroadWebLogging' did not find a matching property.
Mar 15, 2014 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Mar 15, 2014 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2014 2:31:41 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1020 ms
Mar 15, 2014 2:31:41 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Mar 15, 2014 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/theitroad; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
Mar 15, 2014 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 15, 2014 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2014 2:31:43 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1909 ms
  • Database Appender会考虑使用BurstFilter,而Console Appender不会考虑。

  • 虽然使用Console logger会导致您记录完整的日志事件,但是数据库Appender不会这样做,因为BurstFilter会拒绝其中的某些事件。

  • 即使使用的记录器是处理LogEvent的候选对象,也可以实现此LogEvents拒绝。
    如此合理,如下面的theitroadServlet所示。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" 
		</Console>
		<JDBC name="databaseAppender" tableName="theitroad.logging">
			<DataSource jndiName="java:/comp/env/jdbc/theitroadDB" 
			<BurstFilter level="TRACE" rate="20" maxBurst="2"
			<Column name="EVENT_DATE" isEventTimestamp="true" 
			<Column name="LEVEL" pattern="%level" 
			<Column name="LOGGER" pattern="%logger" 
			<Column name="MSG" pattern="%message" 
			<Column name="THROWABLE" pattern="%ex{full}" 
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" 
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" 
		</logger>
		<logger name="com.theitroad" additivity="false">
			<AppenderRef ref="databaseAppender" 
		</logger>
	</Loggers>
</Configuration>
package com.theitroad;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class theitroadServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Logger logger = LogManager.getLogger(theitroadServlet.class);
		for(int i = 0 ; i < 1000 ; i++){
			logger.trace("Index :: "+i+" :: theitroad Database Logging Message !");
			LogManager.getRootLogger().error("Index :: "+i+" :: theitroad Database Logging Message !");
		}
	}
}

Log4j2布局

由于使用日志事件的Appender不同,并且每个追加程序的性质也不同,因此采用布局形式形成LogEvent的格式可以满足使用日志事件的人的需求。

在Log4j 1.x和Logback API中,Log Events的布局转换为字符串,而Log4j2布局考虑了另一种转换方式。
这就是通过将LogEvent转换为字节数组。

这种新的转换类型将强制您配置字符集,以确保字节数组包含正确的值。
强烈建议您返回Apache Log4j2官方,并详细了解Log4j2提供的布局和其他类型。

在本节中,我们将考虑大多数开发人员始终使用的最著名的Layout,并确保您可能会听说过它。
它是PatternLayout。

Log4j2 PatternLayout

模式布局是一种可配置的,灵活的String模式,旨在格式化LogEvent。
这种格式取决于转换模式的概念。
本节将向您介绍模式布局所提供的最重要的功能。

转换模式与语言C中的printf提供的转换模式有关。
通常,转换模式由文字文本和称为转换说明符的格式控件表达式组成。

下图描述了转换模式由哪些部分组成:

上图是简化转换模式的尝试,但是可以肯定的是,最好参考Apache Log4j2文档以获取有关布局和模式布局的更多详细信息。
另外,您可以在上面参考日志事件,并每次查看格式化消息所用的转换模式。

您应该使用哪个Log4j2级别

您可能会问自己的最大问题是,何时应使用特定的日志事件级别。
在开发领域,通常使用DEBUG日志事件,而在生产环境中,我们应该使用INFO或者WARN级别。

下表应指导您在这种情况下应使用哪个log4j2级别。

Log Event LevelWhen It Should Be Used
OFFWhen no events will be logged
FATALWhen a severe error will prevent the application from continuing
ERRORWhen an error in the application, possibly recoverable
WARNWhen an event that might possible lead to an error
INFOWhen an event for informational purposes
DEBUGWhen a general debugging event required
TRACEWhen a fine grained debug message, typically capturing the flow through the application
ALLWhen all events should be logged