一、日志概述

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、能够控制日志信息想打什么打什么,不想打的就不打,日志信息是分级别的,有时候只想看错误的信息或者警告的信息,有时候想看到所有的信息调试程序等等。

记录日志信息的作用:

  • 监视代码中变量的变化情况,周期性的记录到文件中供其它应用进行统计分析;
  • 跟踪代码运行时轨迹,作为日后审计的依据;
  • 担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息。

<br>

二、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及以上级别的日志信息都会打印出来):
logging level全设置为info
图片可以看出,很多大部分的INFO日志均来自于Spring Boot框架本身,如果我们想屏蔽它们,可以将日志级别统一先全部设置为ERROR,这样框架自身的INFO信息不会被打印。然后再将应用中特定的包设置为DEBUG级别的日志,这样就可以只看到所关心的包中的DEBUG及以上级别的日志了。

<br>

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());

运行结果:
logging level设置特定包
可见框架自身的INFO级别日志全部藏匿,而指定包中的日志按级别顺利打印。

<br>

3. 将日志输出到某个文件中

application.properties配置:

logging.file=E:/logs/hello.log

运行结果:
日志输出到本地某个文件夹下
使用Spring Boot Logging日志框架,发现虽然日志文件已生成并输出,但控制台中依旧会打印日志,使用Spring Boot Logging无法解决这个问题。

<br>

三、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";
    }
}

运行结果:
使用log4j2控制台没有输出
运行程序发现控制台没有日志输出,而hello2.log文件中有内容,即符合我们的要求。

<br>

四、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

星河滚烫,你是人间理想