Springboot 日志详解

1. 为什么要有日志

1.1 优点

● 开发调试:根据日志调试定位程序以达到正确的状态;
● 系统运行状态留存:应用系统发布运行投入生成,记录系统运行日志,根据日志排查定位问题;
● 数据收集:将应用日志接入大数据平台,收集用户行为数据,分析用户操作习惯、喜好、用户画像等;

1.2 缺点

● 代码冗余:日志并没有实现具体的业务,没有必要打印不必要的日志,在一定程度上增加代码冗余,降低代码可读性;
● 降低系统性能:有不少因大量日志输出导致系统崩溃的例子;

2. Log4J、Logback、Log4J2 发展轨迹

Log4J 最初是有俄罗斯 Ceki Gülcü 基于 JUL 开发的日志框架,被大范围使用后捐献给 Apache 孵化。
Ceki Gülcü 大神后续不满足 Apache 对 Log4J 的管理,后续又开发了 Logback 和 SLF4J ,Logback 改进了 Log4J 的缺点,性能大幅提升,使用方式几乎不变,用户开始将 Log4J 转到 Logback。
Logback 冲击了 Log4J 的市场后,Apache 开发了 Log4J2,借鉴了 Logback,改进了 Log4J 的缺点,同时号称性能完胜 Logback。

3. 门面模式

3.1 传统日志使用(没有门面模式)

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4jTest {

    private static final Logger LOG = LogManager.getLogger(Log4jTest.class);

    public static void main(String[] args) {
        LOG.info("log4j");
    }
}

3.2 现代日志记录(门面模式)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4jTest2 {

    private static final Logger LOG = LoggerFactory.getLogger(Log4jTest2.class);

    public static void main(String[] args) {
        LOG.info("log4j");
    }
}

3.3 为什么用门面模式

如果一直使用 log4j 或 logback,直接使用是可以的。有一天技术经理说要更换日志框架,那就悲催了,需要一个一个改,门面模式本身不记录日志,依赖log4j 或 Logback 记录日志,更换时只需要更换依赖即可。

3.4 门面模式

在这里插入图片描述

● 门面(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的子系统的功能和责任。正常情况下,本橘色会将所有从客户端发来的请求委派到相应的子系统中。
● 子系统(SubSystem)角色:可以同时又一个或多个子系统。每个子系统都不是一个单独的类,而不是一个类的合集。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另一个客户端。
门面模式的优点:
● 解耦:门面模式解耦了客户端与子系统之间的耦合,客户端不需要了解子系统是如何实现的,让子系统更容易扩展和维护;

4. Springboot 集成日志系统

4.1 如何选择日志系统 ?

Springboot 默认使用了 Logback 做日志记录,SLF4J 做门面系统。默认情况下Springboot 提供的日志系统足够使用。考虑到 LOG4J2 的性能出众,可以考虑使用 LOG4J2 + SLF4J 的组合。

4.2 Springboot 默认日志配置示例

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
                 当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>

    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
    <property name="LOG_HOME" value="logs/${APP_NAME}" />

    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最低级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 2. 输出到文件  -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 当前记录的日志文档完整路径 -->
        <file>${LOG_HOME}/log.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} -%5level ---[%15.15thread] %-40.40logger{39} : %msg%n%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的 addtivity 属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
    -->
    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <!-- 开发环境输出至控制台 -->
    <springProfile name="dev">
        <logger name="com.alibaba.nacos" level="OFF" addtivity="false"> </logger>
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>

    <!-- 生产环境输出至文件 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

    <!-- k8s环境输出至文件 -->
    <springProfile name="k8s">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

</configuration>

4.3 LOG4J2 + SLF4J 配置示例

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

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别由低到高: OFF -> FATAL -> ERROR -> WARN -> INFO -> DEBUG -> TRACE -> ALL -->
<!-- Configuration status 属性,用于设置 log4j2 自身内部的信息输出 -->
<!-- Configuration monitorInterval 属性,用于自动检测修改配置文件和重新配置本身,设置间隔秒数 -->
<Configuration status="ERROR" monitorInterval="30">

    <!-- 定义 appender -->
    <Appenders>
        <!-- 控制台输出配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!--<ThresholdFilter level="Debug" onMatch="ACCEPT" onMismatch="ACCEPT" />-->
            <!-- 日志输出的格式-->
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5p] %l - %m%n"/>
        </Console>
        <!-- 日志文件输出-->
        <File name="FileLog" fileName="log/demo.log" append="false">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5p] %l - %m%n"/>
        </File>
        <RollingFile name="RollingFileInfo" fileName="log/rolling-info.log" filePattern="log/$${date:yyyy-MM}/rolling-info-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="info" onMatch="APPCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="50MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="RollingFileWarn" fileName="log/rolling-warn.log" filePattern="log/$${date:yyyy-MM}/rolling-warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="50MB"/>
            </Policies>
        </RollingFile>
        <RollingFile name="RollingFileError" fileName="log/rolling-error.log" filePattern="log/$${date:yyyy-MM}/rolling-error-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="50MB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>

        <root level="info">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
            <appender-ref ref="FileLog"/>
        </root>
    </Loggers>
</Configuration>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值