1. 日志框架

JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…

日志门面(日志的抽象层)

日志的实现

JCL(Jakarta Commons Logging) SLF4j(Simple Logging Facade for Java) jboss-logging

Log4j JUL(java.util.logging) Log4j2 Logback

SpringBoot的底层是Spring框架,Spring框架默认是用JCL;SpringBoot对他们进行了包装选用 SLF4j和logback

2. SLF4j使用

开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法(面向抽象编程)

//给系统里面导入slf4j的jar和  logback的实现jar
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

springboot启动日志不怎么不打印debug的 springboot启动没有日志_xml


可以看到

① 我们的application调用的是SLF4J接口层(SLF4J API),接口层下面是具体的实现(logback);

② 而对于log4j来说,由于他出现在SLF4J开发出来以前,所有中间还有一层转换层(Adaption layer)连接抽象层和实现层来完成我们面向接口编程的目的

每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件; slf4j只是统一抽象层

但是还有一个问题就是,我们使用了 Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx等框架,他们底层的日志都不相同,那我们如何统一日志记录,即使是别的框架和我一起统一使用slf4j进行输出?

我们呢不能直接拿掉框架底层使用的日志框架,否则项目就启动不起来了,而是使用中间包(如jcl-over-slf4j)来替换原有的日志框架;再导入slf4j其他的实现

springboot启动日志不怎么不打印debug的 springboot启动没有日志_spring_02

3. SpringBoot日志关系

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-logging</artifactId>
</dependency>

springboot启动日志不怎么不打印debug的 springboot启动没有日志_xml_03


SpringBoot底层是使用slf4j+logback的方式进行日志记录,并且把其他的日志都使用中间替换包替换成了slf4j

4. 日志的使用

默认配置

SpringBoot默认帮我们配置好了日志;

//记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
	//System.out.println();

	//日志的级别;
	//由低到高   trace<debug<info<warn<error
	//可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效
	logger.trace("这是trace日志...");
	logger.debug("这是debug日志...");
	//SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别
	logger.info("这是info日志...");
	logger.warn("这是warn日志...");
	logger.error("这是error日志...");
	}
日志输出格式:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 
%msg:日志消息,
%n是换行符
TRACE < DEBUG < INFO < WARN < ERROR < FATAL

如果设置为 WARN ,则低于 WARN 的信息都不会输出。
Spring Boot中默认配置ERROR、WARN和INFO级别的日志输出到控制台。
您还可以通过启动您的应用程序 --debug 标志来启用“调试”模式(开发的时候推荐开启),以下两种方式皆可:

  • 在运行命令后加入–debug标志,如:$ java -jar springTest.jar --debug
  • application.properties中配置debug=true,该属性置为true的时候,核心Logger(包含嵌入式容器、hibernate、spring)会输出更多内容,但是你自己应用的日志并不会输出为DEBUG级别

在上面我们每次都要写Logger logger = LoggerFactory.getLogger(getClass());很麻烦,可以使用注解,但是需要使用lombok

springboot启动日志不怎么不打印debug的 springboot启动没有日志_spring_04


SpringBoot修改日志的默认配置

logging.level.com.minifull=trace

#logging.file 指定日志保存的文件
# 不指定路径在当前项目下生成springboot.log日志
# 可以指定完整的路径;
#logging.file=G:/springboot.log

#logging.path 指定日志保存的目录,这个和logging.file使用是冲突的,我们一般选择使用logging.path指定保存到目录,而日志的文件让springboot规定
# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件
logging.path=/spring/log

#  在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n

logging.file

logging.path

Example

Description

(none)

(none)

只在控制台输出

指定文件名

(none)

my.log

输出日志到my.log文件

(none)

指定目录

/var/log

输出到指定目录的 spring.log 文件中

指定配置

使用Spring Boot喜欢在application.propertiesapplication.yml配置,这样只能配置简单的场景,保存路径、日志格式等,复杂的场景(区分 info 和 error 的日志、每天产生一个日志文件等)满足不了,只能自定义配置

给类路径下放上每个日志框架自己的配置文件即可;SpringBoot就不使用他默认配置的了

Logging System

Customization

Logback

logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy

Log4j2

log4j2-spring.xml or log4j2.xml

JDK (Java Util Logging)

logging.properties

Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项

logback.xml: 直接就被日志框架识别了,绕过了springboot

logback-spring.xml :日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot的高级Profile功能:可以指定某段配置只在某个环境下生效

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
      <!--
       日志输出格式:
		%d表示日期时间,
		%thread表示线程名,
		%-5level:级别从左显示5个字符宽度
		%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 
		%msg:日志消息,
		%n是换行符
       -->
       <!--
       dev: 开发环境
       !dev: 非开发环境
       -->
       <layout class="ch.qos.logback.classic.PatternLayout">
           <springProfile name="dev">
               <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
           </springProfile>
           <springProfile name="!dev">
               <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
           </springProfile>
       </layout>
</appender>

如果你即想完全掌控日志配置,但又不想用logback.xml作为Logback配置的名字,application.yml可以通过logging.config属性指定自定义的名字

logging.config=classpath: logging-config.xml

logback-spring.xml

<?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">
	<!-- property 用来定义变量值的标签, 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量 -->
	
    <!-- 定义日志的根目录 -->
    <property name="LOG_HOME" value="/app/log" />
    <!-- 定义日志文件名称 -->
    <property name="appName" value="ll-springboot"></property>
    <!-- appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略 -->
    
    <!-- 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>

    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->  
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
    所以我们使用下面的策略,可以避免输出 Error 的日志-->
    	<filter class="ch.qos.logback.classic.filter.LevelFilter">
       		<!--过滤 Error-->
        	<level>ERROR</level>
        	<!--匹配到就禁止-->
        	<onMatch>DENY</onMatch>
        	<!--没有匹配到就允许-->
        	<onMismatch>ACCEPT</onMismatch>
    	</filter>
    	<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
        如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
        的日志改名为今天的日期。即,<File> 的日志都是当天的。
    	-->
    	<File>${LOG_HOME}/info.${appname}.log</File>
    	<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
    	<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        	<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
        	<FileNamePattern>${LOG_HOME}/info.${appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
        	<!--只保留最近90天的日志-->
        	<maxHistory>90</maxHistory>
        	<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
        	<!--<totalSizeCap>1GB</totalSizeCap>-->
    	</rollingPolicy>
    	<!--日志输出编码格式化-->
    	<encoder>
        	<charset>UTF-8</charset>
        	<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
    	</encoder>
	</appender>


	<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    	<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
    	<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        	<level>Error</level>
    	</filter>
    	<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
        如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
        的日志改名为今天的日期。即,<File> 的日志都是当天的。
    	-->
    	<File>${LOG_HOME}/info.${appname}.log</File>
    	<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
    	<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        	<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
        	<FileNamePattern>${LOG_HOME}/info.${appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
        	<!--只保留最近90天的日志-->
        	<maxHistory>90</maxHistory>
        	<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
        	<!--<totalSizeCap>1GB</totalSizeCap>-->
    	</rollingPolicy>
    	<!--日志输出编码格式化-->
    	<encoder>
        	<charset>UTF-8</charset>
        	<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
    	</encoder>
	</appender>
</configuration>

多环境日志输出

<configuration>
    ...
    
    <!-- 测试环境+开发环境. 多个使用逗号隔开. -->
    <springProfile name="test,dev">
        <logger name="com.example.demo.controller" level="DEBUG" additivity="false">
            <appender-ref ref="consoleLog"/>
        </logger>
    </springProfile>
    
    <!-- 生产环境. -->
    <springProfile name="prod">
        <logger name="com.example.demo.controller" level="INFO" additivity="false">
            <appender-ref ref="consoleLog"/>
        </logger>
    </springProfile>
</configuration>