04.SpringBoot 之日志体系

1. Java 日志体系

1.1 市面上常用的日志框架

  • 日志门面技术有 JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging,它们都不提供具体的日志实现

  • 日志实现技术有 Log4j、JUL(java.util.logging)、Log4j2、Logback ,它们都提供了不同的 API 使用
    Java 日志体系

1.2 SLF4J 技术

1.2.1 SLF4J 绑定器
  • 每一个日志的实现框架都有自己的配置文件。使用 SLF4J 以后,配置文件还是做成日志实现框架自己本身的配置文件

  • 用户除了需要引入 SLF4J API 的 jar 包外,还需要引入 SLF4J 对日志实现的绑定包

image

1.2.2 SLF4J 桥接器
  • SLF4J 桥接器是为了解决 Jar 包冲突的问题,即有些第三方 Jar 包可能直接使用 Log4j 打印,然后系统中使用的是 SLF4J + Logback 打印,那么就会出现两种日志

  • 使用 SLF4J 桥接器的步骤是:先把其他日志实现包排除掉,然后使用桥接包来替换,最后导入 SLF4J 绑定器的实现包

image

2. SpringBoot 日志

2.1 SpringBoot 日志关系

  • SpringBoot 底层是使用 SLF4J + Logback 的方式进行日志记录,同时引入了 jul-to-slf4jlog4j-to-slf4j 两个桥接包,从而将 JUL 和 Log4j 的日志转到 SLF4J 上,然后再统一使用 Logback 进行日志输出

image

2.2 SpringBoot 日志使用

代码已经上传至 https://github.com/masteryourself-tutorial/tutorial-spring ,详见 tutorial-spring-boot-core/tutorial-spring-boot-log 工程

2.2.1 配置文件内容
1. application.properties
# 全局日志配置
logging.level.root=info
# 精确到包名
logging.level.pers.masteryourself.tutorial.spring.boot.log=debug
# 可以指定完整的路径, 如 D:/springboot.log, 也可以使用 ./ 表示当前路径
logging.file=./spring.log
# 在当前磁盘的根路径下创建 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
2.2.2 配置文件位置
  • Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy

  • Log4j2: log4j2-spring.xml, log4j2.xml

  • JUL: logging.properties

  • 如果是原生的 log 配置文件,那么会直接被日志框架识别

  • 如果加上了 spring, 例如 logback-spring.xml 或者 log4j2-spring.xml, 那么日志框架不会直接加载日志的配置项, 而是由 SpringBoot 解析,可以使用 SpringBoot 的高级 Profile 功能

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">

    <layout class="ch.qos.logback.classic.PatternLayout">
    
        <!-- 在 dev 环境下生效 -->
        <springProfile name="dev">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
        </springProfile>
        
        <!-- 在非 dev 环境下生效 -->
        <springProfile name="!dev">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
        </springProfile>
    </layout>
    
</appender>

2.3 切换日志框架为 log4j2

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

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

2.4 日志模板

1. logback.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="LOG_HOME" value="/app/log"/>
    <!-- 定义日志文件名称 -->
    <property name="appName" value="tutorial-spring"/>

    <!-- 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="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的名称 -->
        <file>${LOG_HOME}/${appName}.log</file>
        <!--
            当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
            TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
                滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
                %i:当文件大小超过 maxFileSize 时,按照 i 进行文件滚动
            -->
            <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!--
                可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动
                且 maxHistory 是 365,则只保存最近 365 天的文件,删除之前的旧文件
            -->
            <MaxHistory>365</MaxHistory>
            <!--
                当日志文件超过 maxFileSize 指定的大小是,根据上面提到的 %i 进行日志文件滚动
                注意此处配置 SizeBasedTriggeringPolicy 是无法实现按文件大小进行滚动的,必须配置 timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!--
		logger 主要用于存放日志对象,也可以定义日志类型、级别
		name:表示匹配的 logger 类型前缀,也就是包的前半部分
		level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
		additivity:作用在于 children-logger 是否使用 rootLogger 配置的 appender 进行输出
		false:表示只用当前 logger 的 appender-ref
		true:表示当前 logger 的 appender-ref 和 rootLogger 的 appender-ref 都有效
    -->

    <!-- tutorial-spring logger -->
    <logger name="pers.masteryourself.tutorial.spring" level="info"/>

    <!-- Spring framework logger -->
    <logger name="org.springframework" level="info" ref="stdout" additivity="false">
        <appender-ref ref="stdout"/>
    </logger>

    <!--
        root 与 logger 是父子关系,没有特别定义则默认为 root,任何一个类只会和一个 logger 对应
        要么是定义的 logger,要么是 root,判断的关键在于找到这个 logger,然后判断这个 logger 的 appender 和 level
    -->
    <root level="info">
        <appender-ref ref="stdout"/>
        <appender-ref ref="appLogAppender"/>
    </root>

</configuration>
2. log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- log4j2 自身日志级别 -->
<Configuration status="WARN">

    <Properties>
        <!-- 定义日志文件名称 -->
        <Property name="APP_ID" value="tutorial-spring"/>
        <!-- 定义日志的根目录 -->
        <Property name="LOG_PATH" value="/app/log/${APP_ID}"/>
    </Properties>

    <Appenders>
        <RollingFile name="RollingFile" fileName="${LOG_PATH}/app.log"
                     filePattern="${LOG_PATH}/app-%d{yyyyMMdd}-%i.log">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <Policies>
                <!--以天为单位触发滚动操作,modulate 设置为 true,会以 00:00 作为起始时间,每天 00:00 进行一次滚动-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="1GB"/>
            </Policies>
            <!--每天最多保存 5G 日志,最多保存 5 天-->
            <DefaultRolloverStrategy max="5">
                <Delete basePath="${LOG_PATH}" maxDepth="1">
                    <IfFileName glob="app-*.log"/>
                    <IfLastModified age="7d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>

        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <logger name="pers.masteryourself.tutorial.spring" level="warn"/>

        <root level="INFO">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="Console"/>
        </root>
    </Loggers>

</Configuration>
3. log4j.properties
### set log levels ###
log4j.rootLogger=info ,  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=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
#### 输出到日志文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 输出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
#### 保存异常信息到单独文件 ###
#log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.E.File = logs/error.log ## 异常日志文件名
#log4j.appender.E.Append = true
#log4j.appender.E.Threshold = ERROR ## 只输出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
发布了37 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/masteryourself/article/details/105016470
今日推荐