Log4j2
Log4j2
Log4j 2 包含了基于 LMAX 分离库的下一代的异步日志系统,在多线程环境下,异步日志系统比 Log4j 1.x 和 Logback 提高了 10 倍性能提升(吞吐量和延迟率),各种框架的对比可以看到如下所示:
Log4j 2 是 Log4j 的升级版本,该版本比起其前任来说有着显著的改进,包含很多在 Logback 中的改进以及 Logback 架构中存在的问题。这是 Log4j 2 的首次发行的版本,值得关注的改进包括:
-
API 分离 – Log4j 的 API 和其实现进行分类(注:我讨厌这样,本来一个 jar 包搞定的,要变成好几个,跟 slf4j 似的的)
-
为日志审计而设计,与 Log4j 1.x 和 Logback 不同的是 Log4j 2 将不会在重新配置期间丢失事件,支持消息可方便进行审计
-
性能方面的提升,在关键领域比 Log4j 1.x 的性能提升不少,大部分情况下性能跟 Logback 差不多
-
支持多 APIs,支持 SLF4J 和 Commons Logging API
-
自动配置重载,支持 XML 和 JSON 格式的配置
-
插件体系架构,所有可配置的组件都是通过 Log4j 插件进行定义,包括 Appender, Layout, Pattern Converter, 等等
-
配置属性支持
配置文件
如果需要使用 Log4j2,首先需要在他的依赖文件里引入如下依赖:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.0-beta9</version>
</dependency>
而后在代码文件中,可以使用 Slf4j,也可以直接使用 Log4j2,如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(Test.class);
如果是直接使用的 log4j2,则只要用 LogManager 的 getLogger 函数获取一个 logger,就可以使用 logger 记录日志,代码如下:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class HelloLog4j {
private static Logger logger = LogManager.getLogger("HelloLog4j");
public static void main(String[] args) {
MyApplication myApplication = new MyApplication();
logger.entry();
logger.info("Hello, World!");
myApplication.doIt();
logger.error("Hello, World!");
logger.exit();
}
}
需要注意的是,log4j 2.0 与以往的 1.x 有一个明显的不同,其配置文件只能采用.xml, .json 或者 .jsn。在默认情况下,系统选择 configuration 文件的优先级如下:
- classpath 下名为 log4j-test.json 或者 log4j-test.jsn 文件
- classpath 下名为 log4j2-test.xml
- classpath 下名为 log4j.json 或者 log4j.jsn 文件
- classpath 下名为 log4j2.xml
Logger 配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- status=debug 可以查看log4j的装配过程 -->
<configuration status="off" monitorInterval="1800">
<properties>
<property name="LOG_HOME">/log/fish</property>
<!-- 日志备份目录 -->
<property name="BACKUP_HOME">{LOG_HOME}/backup</property>
<property name="STAT_NAME">stat</property>
<property name="SERVER_NAME">global</property>
</properties>
<appenders>
<!-- 定义控制台输出 -->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />
</Console>
<!-- 程序员调试日志 -->
<RollingRandomAccessFile name="DevLog" fileName="${LOG_HOME}/${SERVER_NAME}"
filePattern="${LOG_HOME}/${SERVER_NAME}.%d{yyyy-MM-dd-HH}.log">
<PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingRandomAccessFile>
<!-- 游戏产品数据分析日志 -->
<RollingRandomAccessFile name="ProductLog"
fileName="${LOG_HOME}/${SERVER_NAME}_${STAT_NAME}"
filePattern="${LOG_HOME}/${SERVER_NAME}_${STAT_NAME}.%d{yyyy-MM-dd-HH}.log">
<PatternLayout
pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1"
modulate="true" />
</Policies>
</RollingRandomAccessFile>
</appenders>
<loggers>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core" level="info">
</logger>
<logger name="org.springframework.beans" level="info">
</logger>
<logger name="org.springframework.context" level="info">
</logger>
<logger name="org.springframework.web" level="info">
</logger>
<logger name="org.jboss.netty" level="warn">
</logger>
<logger name="org.apache.http" level="warn">
</logger>
<logger name="com.mchange.v2" level="warn">
</logger>
<!-- Game Stat logger -->
<logger name="com.u9.global.service.log" level="info"
additivity="false">
<appender-ref ref="ProductLog" />
</logger>
<!-- Root Logger -->
<root level="DEBUG" includeLocation="true">
<appender-ref ref="DevLog" />
<appender-ref ref="Console" />
</root>
</loggers>
</configuration>
loggers 标签,用于定义 logger 的 lever 和所采用的 appender,其中 appender-ref 必须为先前定义的 appenders 的名称,例如,此处为 Console。那么 log 就会以 appender 所定义的输出格式来输出 log。root 标签为 log 的默认输出形式,如果一个类的 log 没有在 loggers 中明确指定其输出 lever 与格式,那么就会采用 root 中定义的格式。例如以下定义:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<logger name="com.relin.HelloLog4j" level="error" additivity="false">
<appender-ref ref="Console"/>
</logger>
<root level="trace">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
此时,HelloLog4j 则会在 error 级别上输出 log,而其他类则会在 trace 级别上输出 log。需要注意的是 additivity 选项,如果设置为 true(默认值)则 HelloLog4j 的 log 会被打印两次,第二次打印是由于 HelloLog4j 同时也满足 root 里面定义的 trace。在 log4j2 中可以配置不同的 Logger 输出到不同的文件中,如果有时候需要按照不同的级别输出到不同的文件中,则直接在 logger 的 AppenderRef 中定义不同的 level 指向。
<loggers>
<logger name="com.mvc.login" level="info" additivity="false">
<appenderRef ref="LoginController" level="error"/>
<appenderRef ref="InfoController" level="info"/>
</logger>
</loggers>