SLF4j + Log4j
因为log4j2在使用上与logback的适用和配置上比较类似,因此不多赘述。有兴趣的小伙伴可以直接到log4j官网查阅log4j的历史与演变。本文仅简单的在demo项目中引进并使用log4j2,仅考虑普通的软件项目的需求,完成基础的配置文件,并展示使用效果。
关于log4j2和logback的比较
对logback有兴趣的小伙伴可以参考我的另外一篇博文:
Java日志框架 Round One- SLF4J(1.7.25) + Logback(1.2.3)
相信只要掌握了logback和log4j2的一些基础使用,应该就足以应付工作中遇到的小项目的日志记录功能了。
Log4j2是Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。
本文不过多阐述这部分内容,仅展示了解到的差异如下:
- 异步吞吐量高十几倍,延迟降低了几个数量级。
- 支持多种API,而logback只能搭载slf4j。
- 相较于log back低垃圾。
- 都支持自定义日志级别。
- 都具有自动重载,Log4j 2可以在修改后自动重新加载其配置。且不会丢失日志事件。
- log4j2不会导致日志丢失。
- log4j2支持插件架构。
log4j2的使用
下面将以一个简单的springboot 项目来演示slf4j + log4j2的基础使用
maven依赖
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
项目结构
log4j2 支持多种配置形式, 以下摘自中文文档 :
-
通过以 XML,JSON,YAML 或 properties 格式编写的 configuration 文件。
-
以编程方式,通过 creating ConfigurationFactory 和 Configuration implementation。
-
以编程方式,通过调用 Configuration 接口中公开的 API 将组件添加到默认的 configuration。
-
以编程方式,通过调用内部 Logger class 上的方法。
本文将以xml的形式进行日志的配置。 我们还需要了解log4j2的配置检索机制。
log4j 在应用初始化期间自动进行配置。 它将根据一定的规则检索ConfigurationFactory 插件,并最终初始化四个 配置加载的插件, 基于json,基于yaml, 基于properties文件, 基于xml文件。 检索的规则如下:
- Log4j 将检查"log4j.configurationFile" system property,如果设置,将尝试使用与文件扩展名匹配的ConfigurationFactory加载 configuration。
- 如果未设置系统 property,则 properties ConfigurationFactory 将在 classpath 中查找log4j2-test.properties。
- 如果没有找到这样的文件,YAML ConfigurationFactory 将在 classpath 中查找log4j2-test.yaml或log4j2-test.yml。
- 如果找不到这样的文件,JSON ConfigurationFactory 将在 classpath 中查找log4j2-test.json或log4j2-test.jsn。
- 如果没有找到这样的文件,XML ConfigurationFactory 将在 classpath 中查找log4j2-test.xml。
- 如果找不到测试文件,properties ConfigurationFactory 将在 classpath 上查找log4j2.properties。
- 如果找不到 properties 文件,YAML ConfigurationFactory 将在 classpath 上查找log4j2.yaml或log4j2.yml。
- 如果找不到 YAML 文件,JSON ConfigurationFactory 将在 classpath 上查找log4j2.json或log4j2.jsn。
- 如果找不到 JSON 文件,XML ConfigurationFactory 将尝试在 classpath 上找到log4j2.xml。
- 如果找不到 configuration 文件,则将使用DefaultConfiguration。这将导致 logging 输出转到 console。.
因此我们创建一个log4j2.xml文件如下:
<Configuration status="INFO">
<Properties>
<Property name="log.dir">D:\respository_code\resp_github\Kern-demo\demo-slf4j-log4j2\src\main\resources\logs</Property>
</Properties>
<Appenders>
<!-- 控制台-->
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
</Console>
<!-- 文件-->
<File name="file" fileName="${log.dir}/log4j2.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
<!-- 只输出warn及以上的日志-->
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY" />
</File>
<!-- 滚动文件-->
<RollingFile name="rollingFile" filePattern="${log.dir}/%d{yyyy-MM}/log4j2-%d{yyyy-MM-dd}.log">
<!-- 只输出INFO 及以上的日志-->
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="console"/>
<AppenderRef ref="file"/>
<AppenderRef ref="rollingFile"/>
</Root>
</Loggers>
</Configuration>
演示代码
package cn.kerninventory.demoslf4jlog4j2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Kern
* @date 2020/4/23 17:52
* @description
*/
@RestController
@RequestMapping("/test")
public class TestController {
private static Logger logger = LoggerFactory.getLogger(TestController.class);
@GetMapping("")
public String test() {
try {
logger.info("请求信息 : xxxx");
if (!authentication()) {
logger.warn("警告,非法访问!!!");
throw new Exception("非法访问!!!");
}
doingSomething();
logger.info("请求处理结束!");
} catch (Exception e) {
logger.error("test error ! === {}", e.getMessage() , e);
e.printStackTrace();
}
return "success!";
}
private boolean authentication(){
return false;
}
private void doingSomething(){
//NOTHING TO DO !
}
}
postman测试请求
日志输出结果