Spring Boot 2.x 集成 SLF4j + log4j2 日志框架
目录
Apache log4j2 日志框架概述
Spring Boot 2.x 集成 SLF4j + log4j2 日志框架
monitorInterval 定时读取配置信息
LoggerConfig 动态修改日志记录器(推荐)
Spring boot Actuator 监控与切换日志
为什么将 Logger 对象声明为 private static final
Apache log4j2 日志框架概述
1、Apache log4j2 是对 Log4j 的升级,它提供了对其前身 log4j 1.x 的重大改进,并提供了 Logback 中可用的许多改进,同时修复了 Logback 体系结构中的一些固有问题。
2、Log4j 的 API 是独立于实现的,它向应用程序开发人员明确说明了在确保前向兼容性的同时可以使用哪些类和方法,这允许 Log4j 团队以兼容的方式安全地改进实现。
3、Log4j 2 分为 log4j-api 门面和 log4j-core 实现两个模块,API 和 slf4j 类似,属于日志抽象/门面,而实现部分 log4j-core,才是 Log4j 2 的核心。与 SLF4J 相比,Log4j API 有如下优点:
A、log4j API 支持记录消息,而不仅仅是字符串。
B、log4j API 支持 lambda 表达式。
C、Log4j API 提供了比 SLF4J 更多的日志记录方法。
4、除了 Slf4j 支持的”参数化日志”格式外,Log4j API 还支持使用 java.text.MessageFormat 语法的事件以及 printf 样式的消息。
5、log4j Api 提供 LogManager.shutdown() 方法,基础日志实现必须实现可终止接口,才能使方法生效。
Apache Log4j2 主页:http://logging.apache.org/log4j/2.x/download.html
log4j2 github 开源地址:https://github.com/apache/logging-log4j2
Spring boot 配置 log4j2:https://docs.spring.io/spring-boot/docs/2.1.3.RELEASE/reference/htmlsingle/#howto-configure-log4j-for-logging用户指南(手册):https://logging.apache.org/log4j/2.x/log4j-users-guide.pdf
6、Log4j2 包含基于 LMAX 中断器库的下一代异步记录器,在多线程场景中,异步记录器的吞吐量是 log4j1.x 和 Logback 的 18 倍,延迟也低几个数量级。
7、Log4j2 与 Logback 一样,可以在修改后自动重新加载其配置,与 Logback 不同的是,它在进行重新配置时不会丢失日志事件。
8、延申阅读:
Spring Boot 2.x 日志配置 与 指定 Logback 日志配置文件.
日志框架简述、slf4j 日志框架概述,slf4j + log4j 1.X 日志组合
日志配置级别 | |||||||
---|---|---|---|---|---|---|---|
TRACE | DEBUG | INFO | WARN | ERROR | FATAL | OFF | |
ALL | YES | YES | YES | YES | YES | YES | NO |
TRACE | YES | NO | NO | NO | NO | NO | NO |
DEBUG | YES | YES | NO | NO | NO | NO | NO |
INFO | YES | YES | YES | NO | NO | NO | NO |
WARN | YES | YES | YES | YES | NO | NO | NO |
ERROR | YES | YES | YES | YES | YES | NO | NO |
FATAL | YES | YES | YES | YES | YES | YES | NO |
OFF | NO | NO | NO | NO | NO | NO | NO |
Spring Boot 2.x 集成 SLF4j + log4j2 日志框架
1、spring-boot-starter-web 中的 spring-boot-starter-logging 日志启动器默认使用的 slf4j + logback ,而 Apache 的 log4j2 也是数一数二的日志框架,Spring boot 也对他进行了支持。
2、本文环境 spring-boot 2.3.5.RELEASE + JDK 1.8 + Log4j 2.13.3,先在 pom.xml 中排除掉默认的日志依赖,然后再引入 log4j 启动器。
<!-- web 启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--移除掉 spring boot 默认的日志启动器-->
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引用 log4j2 spring boot 启动器,内部依赖了 slf4j、log4j-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
3、官网参考链接,根据日志记录系统的不同,各自的配置文件文件也不同,在类路径下提供 log4j2 的配置文件 log4j2.xml,格式与 logback 的 logback.xml 基本差不多,示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别从低到高优先级为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。-->
<!--status:设置 log4j2 自身内部的信息输出,可以不设置-->
<!--monitorInterval:监视配置文件变化间隔时间,单位秒,Log4j2 能够自动检测配置文件是否修改,同时更新配置-->
<configuration status="WARN" monitorInterval="30">
<!--先定义所有的 appender 附加器-->
<appenders>
<!--控制台输出配置-->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - [%t] - %l - %m%n"/>
</console>
<!--文件存储文件设置-->
<!--fileName:文件存储路径及名称,可以是绝对路径或者相对路径; 存储的永远是最新的日志信息-->
<!--filePattern:当 fileName 指定的文件大小超过限制,就会根据此文件名规则新建存档目录与文件,同时将 fileName 文件中的
内容剪切到存档文件中,如下配置,会新建存档路径 logs/2021-06/info-2021-06-01-1.log -->
<RollingFile name="RollingFileInfo" fileName="logs/info.log"
filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
<!--日志文件中日志信息的格式-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - [%t] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<!--日志文件大小超过多少时进行存档-->
<SizeBasedTriggeringPolicy size="500 MB"/>
</Policies>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉 spring 和 mybatis 的一些无用的 DEBUG 信息;也可以单独指定自己的某个包-->
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.mybatis" level="INFO"></logger>
<logger name="org.example.log4j2" level="INFO"></logger>
<!--root 与 logger 是父子关系,没有指定 logger 的,全部统一用 root 配置的日志级别处理.-->
<!--通常设置 debug、info、error 基本即可-->
<root level="ALL">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
</root>
</loggers>
</configuration>
如果只引入了 log4j2 依赖,没有提供 log4j2.xml 配置文件,则默认日志输出级别为 INFO,会打印在控制台,但是不会记录到文件中。
5、日志级别输出测试,Log4j2 也支持占位符:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* 面向 log4j-api 原生接口编程
*
* @author wangMaoXiong
* @version 1.0
* @date 2021/6/9 16:50
*/
public class Example1 {
private static final Logger LOGGER = LogManager.getLogger();
public static void main(String... args) {
LOGGER.trace("hello, I am trace!");
LOGGER.debug("hello, I am debug!");
LOGGER.info("hello, I am info!");
LOGGER.warn("hello, I am {}!", "warn");
LOGGER.error("hello, I am {}!", "error");
}
}
gif 演示动图:https://gitee.com/wangmx1993/my-document/blob/master/images/log4j2日志框架使用.gif
monitorInterval 定时读取配置信息
1、热加载配置文件是很有用的,比如服务上线之后,当需要输出详细日志信息排查问题时,可以降低优先级,比如 TRACE 、DEBUG,当完事之后,可以再调高优先级,比如 WARN、ERROR,减少日志记录,提供性能。
2、Log4j2 与 Logback 一样,可以在修改后自动重新加载其配置,与 Logback 不同的是,它在进行重新配置时不会丢失日志事件。
3、使用非常简单只需要在文件开始的 configuration 标签中指定 monitorInterval 属性即可,值大于 0 时会自动创建子线程进行定时扫描,更新配置;不配置或者值为0时,不会进行监控,运行中修改是无效的:
<!--monitorInterval:监视配置文件变化间隔时间,单位秒,Log4j2 能够自动检测配置文件是否修改,同时更新配置-->
<configuration status="WARN" monitorInterval="60">
4、如果是在本地 IDE 编辑器中测试,注意修改的是 classes 编译目录下的 log4j2.xml 文件,而不是 resources 目录的源文件。
5、对于可以手动修改配置文件的时候,此种方式还是很方便的,但是如果应用是打成 .jar、.war 包发布部署,则这种方式还是不太方便,因为仍然得从生产下载 jar、war 包,然后修改配置,重启服务。
LoggerConfig 动态修改日志记录器(推荐)
1、鉴于现在都是微服务开发,分布式部署,而且为了方便管理,基本都是打包后部署在一些平台上面。直接修改日志配置文件不太现实。
2、所以我们可以自己提供一个 Controller 请求接口,用于动态修改日志输出级别,想设置什么级别,只需要调用一下接口,传递一下参数即可,无论是设置整个 root 级别,还是对指定包或者类都能轻松设置,不用重启服务就能立马生效。
3、实现也是非常简单,在线演示源码如下:
https://gitee.com/wangmx1993/java-se/blob/master/src/main/resources/log4j2.xml
https://gitee.com/wangmx1993/java-se/blob/master/src/main/java/org/example/log4j2/Log4j2Controller.java
/**
* Log4j2 动态修改 root(根)日志级别,修改之后配置立刻生效.
* http://localhost:8080/log4j/setRootLevel?level=TRACE
*
* @param level :可选值有:ALL、TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF,否则默认会设置为 DEBUG,不区分大小写。
* @return
*/
@GetMapping(value = "/log4j/setRootLevel")
public Map<String, Object> setRootLevel(@RequestParam(value = "level") String level) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("code", 200);
dataMap.put("msg", "修改root日志级别成功");
try {
//LoggerContext getContext(final boolean currentContext):获取 log4j 日志上下文,false 表示返回合适调用方的上下文
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
//返回当前配置,发生重新配置时,将替换该配置。
Configuration configuration = loggerContext.getConfiguration();
//查找记录器名称的相应 LoggerConfig
LoggerConfig loggerConfig = configuration.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
//设置日志级别
//如果 level 值不属于 ALL、TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF,则默认会设置为 DEBUG.
Level toLevel = Level.toLevel(level);
loggerConfig.setLevel(toLevel);
//根据当前配置更新所有记录器
loggerContext.updateLoggers();
//查询 root(根)日志输出级别结果返回
String root_logger_name = LogManager.getRootLogger().getLevel().name();
dataMap.put("data", root_logger_name);
} catch (Exception e) {
dataMap.put("code", 500);
dataMap.put("msg", e.getMessage());
e.printStackTrace();
}
return dataMap;
}
Spring boot Actuator 监控与切换日志
Spring boot Actuator 监控与管理日志
为什么将 Logger 对象声明为 private static final
1、private:是为了防止其他类使用当前类的日志对象.
2、static:是为了让每个类中的日志对象只生成一份,是属于类的,不是属于具体的实例的.
3、final:是为了避免日志对象在运行时被修改.
还没有评论,来说两句吧...