SpringBoot 默认采用 Logback 日志作为记录日志的框架。在项目中,一般分为 dev 环境(开发环境)、test环境(测试环境)和 prd 环境(生产环境)。而一般开发环境和测试环境可以把日志级别设置成 info 级别,方便在联调与测试中解决遇到的bug,但是生产环境因为存在大量的业务,如果采用 info 级别的日志, 那么每一笔交易或者业务都打印大量的日志。这样的花需要大量的磁盘空间来保存日志。如果日志需要保存一年半载,或者有些业务场景,例如财务数据的日志需要保存更久。将给公司造成很大的财务浪费。今天分享一个小方案,动态改变日志的级别,方便在生产环境也能方便快捷的从 warn 或者 error 级别切换到 debug 或者 info 级别。
0x01:pom.xml 引入依赖
代码语言:javascript复制<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.olive</groupId>
<artifactId>valid-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath />
</parent>
<name>valid-demo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
0x02:logbak-spring.xml 配置
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<root level="info">
<!-- 控制台输出日志-->
<appender-ref ref="stdout" />
</root>
</configuration>
为了演示,这里只配置了一个 rootLogger
0x03:编写 Controller
该 Controller 主要包含以下三个API
主要框架
代码语言:javascript复制package com.olive.controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
@RestController
public class LoggerController {
private final static Logger logger = LoggerFactory.getLogger(LoggerController.class);
// TODO
}
- 打印各日志级别的日志
@RequestMapping("/logger/print")
public Map loggerPrint(){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
logger.debug("loggerPrint debug>>>>");
logger.info("loggerPrint info>>>>");
logger.warn("loggerPrint warn>>>>");
logger.error("loggerPrint error>>>>");
return result;
}
- 打印日志对象 Logger
@RequestMapping("/logger/printAllLogger")
public Map printAllLogger(){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
List<ch.qos.logback.classic.Logger> loggers = loggerContext.getLoggerList();
Iterator<ch.qos.logback.classic.Logger> iter = loggers.iterator();
System.out.println("printAllLogger begin>>>>>>>>");
while(iter.hasNext()){
System.out.println(iter.next().getName());
}
System.out.println("printAllLogger end>>>>>>>>");
return result;
}
该方法打印所有存在的日志对象 Logger
- 设置 ROOT 日志对象的日志级别
@RequestMapping("/logger/level")
public Map loggerLevelChange(String level){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
String loggerFactoryClassStr = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr();
System.out.println("loggerFactoryClassStr>>>>" loggerFactoryClassStr);
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
ch.qos.logback.classic.Logger logger = loggerContext.getLogger("ROOT");
switch (level) {
case "debug":
logger.setLevel(Level.DEBUG);
break;
case "info":
logger.setLevel(Level.INFO);
break;
case "warn":
logger.setLevel(Level.WARN);
break;
case "error":
logger.setLevel(Level.ERROR);
break;
default:
break;
}
return result;
}
0x04:编写引导类与测试
代码语言:javascript复制import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
}
启动服务
- 打印日志对象 Logger
可以在控制台看到如下日志
代码语言:javascript复制printAllLogger begin>>>>>>>>
ROOT
com.olive.Application
com.olive.controller.LoggerController
// 省略一万条记录
printAllLogger end>>>>>>>>
- 打印各日志级别的日志
目前 logback-spring.xml 配置的 ROOT 的日志级别是 info 级别
可以看到控制台只打印 info 级别及 info 级别以上的日志
代码语言:javascript复制2021-05-12 22:10:27.959 [http-nio-8080-exec-3] INFO com.olive.controller.LoggerController - loggerPrint info>>>>
2021-05-12 22:10:27.959 [http-nio-8080-exec-3] WARN com.olive.controller.LoggerController - loggerPrint warn>>>>
2021-05-12 22:10:27.960 [http-nio-8080-exec-3] ERROR com.olive.controller.LoggerController - loggerPrint error>>>>
- 设置 ROOT 日志对象的日志级别
调用完以上接口后,再次调用 http://127.0.0.1:8080/logger/print 接口。可以看到控制台
打印了大量 debug 级别及 debug 级别以上的日志