一、日志概述
1. 日志的级别
Java应用中,日志一般分为以下5个级别:
- ERROR 错误信息
- WARN 警告信息
- INFO 一般信息
- DEBUG 调试信息
- TRACE 跟踪信息
Spring Boot使用Apache的Commons Logging
作为内部的日志框架,其仅仅是一个日志接口,在实际应用中需要为该接口来指定相应的日志实现。Spring Boot默认的日志实现是Java Util Logging
,是JDK自带的日志包,此外Spring Boot当然也支持Log4J、Logback
这类很流行的日志框架。
2. 日志框架的作用
日志框架能控制什么?需要打印的日志都能满足什么样的需求?
1、能够控制日志信息想往哪里打就往哪里打,比如:控制台、文件、邮箱、数据库等等;
2、能够控制日志信息想怎么打就怎么打,比如:想要打印时间、程序的名称、程序的方法名、程序的行号、线程的名称等等;
3、能够控制日志信息想打什么打什么,不想打的就不打,日志信息是分级别的,有时候只想看错误的信息或者警告的信息,有时候想看到所有的信息调试程序等等。
记录日志信息的作用:
- 监视代码中变量的变化情况,周期性的记录到文件中供其它应用进行统计分析;
- 跟踪代码运行时轨迹,作为日后审计的依据;
- 担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息。
二、Spring Boot使用日志
使用slf4j-api
接口,Java Util Logging
作为默认的日志实现
1. 设置level为INFO
application.properties配置:
logging.level.root=INFO
控制器代码如下:
package com.example.loggingdemo.controller;
import com.example.loggingdemo.LoggingdemoApplication;
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.RestController;
@RestController
@RequestMapping("/logging")
public class TestLogging {
private static Logger logger = LoggerFactory.getLogger(LoggingdemoApplication.class);
@GetMapping("/hello")
public String sayHello() {
logger.info("say hello...");
return "hello";
}
}
运行结果(由于将日志等级设置为INFO,因此包含INFO及以上级别的日志信息都会打印出来):
图片可以看出,很多大部分的INFO日志均来自于Spring Boot框架本身,如果我们想屏蔽它们,可以将日志级别统一先全部设置为ERROR,这样框架自身的INFO信息不会被打印。然后再将应用中特定的包设置为DEBUG级别的日志,这样就可以只看到所关心的包中的DEBUG及以上级别的日志了。
2. 控制特定包的日志级别
application.properties配置:
logging.level.root=error
logging.level.com.example.loggingdemo.controller:debug
将root日志级别设置为ERROR,然后再将com.example.loggingdemo.controller
包的日志级别设为DEBUG,即先禁止所有再允许个别包的设置方法。
控制器部分代码:
private Logger logger = LoggerFactory.getLogger(this.getClass());
运行结果:
可见框架自身的INFO级别日志全部藏匿,而指定包中的日志按级别顺利打印。
3. 将日志输出到某个文件中
application.properties配置:
logging.file=E:/logs/hello.log
运行结果:
使用Spring Boot Logging日志框架,发现虽然日志文件已生成并输出,但控制台中依旧会打印日志,使用Spring Boot Logging无法解决这个问题。
三、Spring Boot集成Log4J2日志框架
1. pom.xml中添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2. 在resources目录下新建log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appenders>
<File name="file" fileName="E:/logs/hello2.log">
<PatternLayout pattern="%d{HH:mm:ss,SSS} %p %c (%L) - %m%n"/>
</File>
</appenders>
<loggers>
<root level="ERROR">
<appender-ref ref="file"/>
</root>
<logger name="com.example.loggingdemo.controller" level="DEBUG"/>
</loggers>
</configuration>
3. 控制器代码
package com.example.loggingdemo.controller;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/logging")
public class TestLogging {
private final Logger logger = LogManager.getLogger(this.getClass());
@GetMapping("/hello")
public String sayHello() {
for (int i = 0; i < 1000; i++) {
logger.info("info execute index method");
logger.warn("warn execute index method");
logger.error("error execute index method");
}
return "say hello";
}
}
运行结果:
运行程序发现控制台没有日志输出,而hello2.log文件中有内容,即符合我们的要求。
四、Log4J详细配置
1. log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="warn">
<properties>
<Property name="app_name">springboot-web</Property>
<Property name="log_path">logs/${app_name}</Property>
</properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d][%t][%p][%l] %m%n"/>
</console>
<RollingFile name="RollingFileInfo" fileName="${log_path}/info.log"
filePattern="${log_path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="INFO"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="2 MB"/>
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
<RollingFile name="RollingFileWarn" fileName="${log_path}/warn.log"
filePattern="${log_path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="WARN"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="2 MB"/>
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
<RollingFile name="RollingFileError" fileName="${log_path}/error.log"
filePattern="${log_path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
<ThresholdFilter level="ERROR"/>
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/>
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="2 MB"/>
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>
控制器及其他代码不变,运行结果如下:
日志会根据不同的级别存储在不同的文件,当日志文件大小超过2M以后会分多个文件压缩存储,生产环境的日志文件大小建议调整为20-50MB。
2. SSM框架下Log4j配置(补充)
- 控制器代码
private static Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
// 记录debug级别的信息
logger.debug("This is debug message.");
// 记录info级别的信息
logger.info("This is info message.");
// 记录error级别的信息
logger.error("This is error message.");
}
}
- Log4j.properties
### org.apache.log4j.ConsoleAppender (控制台)
### org.apache.log4j.FileAppender (文件)
### org.apache.log4j.DailyRollingFileAppender (每天产生一个日志文件)
### org.apache.log4j.RollingFileAppender (文件大小到达指定尺寸的时候产生一个新的文件)
### org.apache.log4j.WriterAppender (将日志信息以流格式发送到任意指定的地方)
### ERROR、WARN、INFO、DEBUG 优先级从高到低
### 设置日志输出的等级为DEBUG,低于DEBUG不会输出
### 设置输出到控制台 (stdout)、D、E 三个地方
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
### 第二个地方D, 以滚动的方式输出到文件,文件名是log.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n