热部署与日志

  1. springboot 中 devtools 热部署

    1. 1 引言

      ​ 为了进一步提高开发效率,springboot 为我们提供了全局项目热部署,日后在开发过程中修改部分代码以及相关配置文件后,不需要每次重启使修改生效,在项目中开启了 springboot 全局热部署之后只需要在修改之后等待几秒即可使修改生效。

    2. 2 开启热部署

      1. 21 项目中引入依赖

        <!-- 1. devtools 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
      2. 22 当我们修改了类文件后,idea 不会自动编译,得修改 idea 设置。

        • File-Setting-Compiler-Build Project automatically

          image-20220505164635699

        • ctrl + shift + alt + /,选择 Registry,勾上 Compiler autoMake allow when app running

          image-20220505164651913

          image-20220505164728718

  2. 带你弄清混乱的 JAVA 日志体系

    1. 1 日志框架

      日志实现日志门面
      log4jJCL
      jul java.util.loggingSJF4J
      log4j2
      logback(推荐使用)
    2. 2 代码实现

      1. 21 日志实现

        1. 211 jul(注意包名)

          package com.springboot;
          
          import java.util.logging.Logger;
          
          public class JulMain {
              public static void main(String[] args) {
                  Logger logger = Logger.getLogger(JulMain.class.getName());
                  logger.info("崇尚官方开发组:Jul");
              }
          }

          image-20220428214936443

        2. 212 log4j(注意包名)

          导包:

          <!-- log4j 的核心依赖 -->
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.17</version>
          </dependency>

          添加 log4j.properties 文件:

          log4j.rootLogger=trace, stdout
          log4j.appender.stdout=org.apache.log4j.ConsoleAppender
          log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
          log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

          java 代码实现:

          package com.springboot;
          
          import org.apache.log4j.Logger;
          
          public class Log4jMain {
              public static void main(String[] args) {
                  Logger logger = Logger.getLogger(Log4jMain.class.getName());
                  logger.info("崇尚开源开发组:Log4j");
              }
          }

          image-20220428214918691

      2. 22 日志及日志门面实现

        开发标准:记录日志不能直接使用日志实现框架,必须通过日志门面来实现。

        1. 221 Jul (实现) + JCL (门面)

          导包:

          <!-- 引入 JCL 门面依赖 -->
          <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
          </dependency>

          添加 commons-logging.properties 文件:

          org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger

          java 实现:

          package com.springboot;
          
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          
          public class JulMain {
              public static void main(String[] args) {
                  Log log = LogFactory.getLog(JulMain.class.getName());
                  System.out.println(log.getClass());
                  log.info("崇尚官方开发组:Jul");
              }
          }
        2. 222 log4j (实现) + slf4j (门面)

          导包:

          <!-- slf4j 的核心依赖 -->
          <dependency>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-api</artifactId>
          </dependency>
          <!-- 加上桥接器 -->
          <dependency>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-log4j12</artifactId>
          </dependency>

          java 实现:

          package com.springboot;
          
          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          
          public class Log4jMain {
              public static void main(String[] args) {
                  Logger logger = LoggerFactory.getLogger(Log4jMain.class);
                  System.out.println(logger.getClass());
                  logger.info("崇尚开源开发组:Log4j");
              }
          }
  1. 3 桥接器

    image-20220428220818406

  2. 4 将 JCL 转化到 slf4j

    使用 jcl-over-slf4j 或者 jul-to-slf4j

    <!-- 为了日志统一实现,将 JCL 转化到 slf4j
         添加 JCL-slf4j 的适配器
    -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
    </dependency>
  1. logback 日志的集成

    image-20220428232620876

    1. SpringBoot 底层也是使用 slf4j + logback 的方式进行日志记录

      logback 桥接:logback-calssic

    2. SpringBoot 也把其他的日志都替换成了 slf4j;

      • log4j 适配:log4j-over-slf4j
      • jul 适配:jul-to-slf4j
      • jcl-over-slf4j
  2. SpringBoot 日志使用

    • 日志级别

      可以设置 TRACE,DEBUG,INFO,WARN,ERROR 或 OFF 之一

      logging:
        level:
          root: "warn"
          org.springframework.web: "debug"
          org.hibernate: "error"
  • 日志格式

    2022-04-29 16:18:09.667 TRACE 78860 --- [           main] com.springboot.Application               : 跟踪
    2022-04-29 16:18:09.667 DEBUG 78860 --- [           main] com.springboot.Application               : 调试
    2022-04-29 16:18:09.667  INFO 78860 --- [           main] com.springboot.Application               : 信息
    2022-04-29 16:18:09.667  WARN 78860 --- [           main] com.springboot.Application               : 警告
    2022-04-29 16:18:09.667 ERROR 78860 --- [           main] com.springboot.Application               : 异常

    详细介绍:

    可以使用 logging.pattern.console 修改默认的控制台的日志格式:

    %clr(%d{${LOG_DATEFORMAT_PATTERN:-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}
    • 2022-04-29 16:18:09.667

      • 日期和时间:毫秒精度,易于排序。
      • %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint}

        • %clr 代表当前内容的颜色 {faint}
        • (%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}) 括号中表示显示的内容

          • ${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}

            使用了 ${value:value2} springboot 的占位符 + null 条件的表达式(如果 value 为 null 则使用 value2)

            LOG_DATEFORMAT_PATTERN:系统环境变量中的值,springboot 底层会根据对应的配置项将值设置到对应的环境变量中 LOG_DATEFORMAT_PATTERN=logging.pattern.dateformat 可通过 dateformat: -yyyy-MM-dd 设置

          • %d{-yyyy-MM-dd HH:mm:ss.SSS}

            %d 表示 logback 的日期显示方式

            {-yyyy-MM-dd HH:mm:ss.SSS} 表示日期的格式

    • TRACE

      • 日志级别。
      • %clr(${LOG_LEVEL_PATTERN:-%5p})

        • %clr 表示内容的颜色,会根据不同的日志级别输出对应的颜色
        • ${LOG_LEVEL_PATTERN:-%5p}

          • %5 代表当前内容所占字符长度
          • p 表示输出日志的级别
    • 78860

      • 进程 ID。
      • %clr(${PID:- }){magenta}

        • %clr 表示当前内容的颜色为 {magenta}
        • ${PID:- } springboot 的占位符 + null 条件的表达式(如果 value 为 null 则使用 value2)
        • PID 是系统环境变量中的进程 ID (由系统分配)
    • ---

      • 一个 --- 分离器来区分实际日志消息的开始。
    • [ main]

      • 线程名称:用方括号括起来(对于控制台输出可能会被截断)。
    • com.springboot.Application

      • 记录日志的类。
    • 跟踪

      • 日志消息
  • 文件输出

    默认情况下,Spring Boot 仅记录到控制台,不写日志文件。如果除了控制台输出外还想写日志文件,则需要设置一个 logging.file.name 或 logging.file.path 属性(例如,在中 application.properties)。

    下表显示了如何 logging.* 一起使用这些属性:

    logging.file.namelogging.file.path实例描述
    (没有)(没有) 仅控制台记录
    指定文件名(没有)my.log写入指定的日志文件
    (没有)具体目录/var/log写入 spring.log 指定的目录
    • logging.file.name

      • 可以设置文件的名称,如果没有设置路径会默认在项目的相对路径下创建
      • 还可以指定路径 + 文件名: D:/my.log
    • logging.file.path

      • 不可以指定文件的名称,必须要指定一个物理文件夹路径,会默认使用 spring.log 为文件名称
  • Spring Boot 的默认日志级别是 INFO

    @SpringBootApplication
    public class Application {
    
        //1. 声明日志记录器
        static Logger logger = LoggerFactory.getLogger(Application.class);
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
    
            logger.trace("跟踪");
            logger.debug("调试");
            //Spring Boot 的默认日志级别是 INFO
            logger.info("信息");
            logger.warn("警告");
            logger.error("异常");
        }
    
    }

    image-20220429155655577

  • 日志迭代(轮转)

    如果您使用的是 Logback,则可以使用 application.properties 或 application.yaml 文件微调日志轮播设置。对于所有其他日志记录系统,您需要直接配置轮转设置(例如,如果使用 Log4J2,则可以添加 log4j.xml 文件)。

    名称描述
    logging.logback.rollingpolicy.file-name-pattern归档的文件名
    logging.logback.rollingpolicy.clean-history-on-start如果应在应用程序启动时进行日志归档清理
    logging.logback.rollingpolicy.max-file-size归档前日志文件的最大大小
    logging.logback.rollingpolicy.total-size-cap删除日志档案之前可以使用的最大大小
    logging.logback.rollingpolicy.max-history保留日志存档的天数(默认为7)
    • logging.logback.rollingpolicy.file-name-pattern

      • ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz

        • ${LOG_FILE} 对应 logging.file.name
        • %d{yyyy-MM-dd} 日期 年-月-日
        • %i 索引,当文件超出指定大小后进行的文件索引递增
  • 自定义日志配置文件

    可以通过在类路径中包含适日志配置文件来激活各种日志记录系统或使用 logging.config

    Logging SystemCustomization
    Logbacklogback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy
    log4j2log4j2-spring.xml or log4j2.xml
    JDK(Java Util Logging)logging.properties

    注意:

    • 如果使用自定义日志配置文件,会使 springboot 中全局配置文件的 logging 相关配置失效。
    • 可以结合 springboot 提供的 Profile 来控制日志的生效

      • 要注意的是,一定要将日志配置文件的文件名改成 logback-spring.xml, 因为 logback.xml 会在 springboot 容器加载之前先被 logback 给加载到,那么由于 logback 无法解析 springProfile 将会报错

        image-20220429181012835

      image-20220429181043577

  • 切换日志框架

    • 将 logback 切换成 log4j2

      添加 spring-boot-starter-log4j2 依赖(场景启动器)

      <!-- log4j2 的场景启动器 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-log4j2</artifactId>
      </dependency>

      排除 logback 的场景启动器

      <!-- starter-web 里面自动添加了 starter-logging 也就是 logback 的依赖 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <exclusions>
              <!-- 排除 starter-logging 也就是 logback 的依赖 -->
              <exclusion>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-slf4j-impl</artifactId>
              </exclusion>
              <exclusion>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-jul</artifactId>
              </exclusion>
              <exclusion>
                  <groupId>org.slf4j</groupId>
                  <artifactId>jul-to-slf4j</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>*</groupId>
                  <artifactId>*</artifactId>
              </exclusion>
          </exclusions>
      </dependency>

      添加 log4j2.xml 文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <configuration status="OFF">
          <appenders>
              <Console name="Console" target="SYSTEM_OUT">
                  <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} +++++++ %msg%n"/>
              </Console>
          </appenders>
          <loggers>
              <root level="info">
                  <appender-ref ref="Console"/>
              </root>
          </loggers>
      </configuration>
 

 - 将 logback 切换成 log4j

   1. 首先将 logback 的桥接器排除

      ```xml
      <!-- starter-web 里面自动添加了 starter-logging 也就是 logback 的依赖 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
              </exclusion>
              <exclusion>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-slf4j-impl</artifactId>
              </exclusion>
              <exclusion>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-jul</artifactId>
              </exclusion>
              <exclusion>
                  <groupId>org.slf4j</groupId>
                  <artifactId>jul-to-slf4j</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>*</groupId>
                  <artifactId>*</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      ```

   2. 添加 log4j 的桥接器

      ```xml
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
      </dependency>
      ```

   3. 添加 log4j 的配置文件

      ```properties
      log4j.rootLogger=trace, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] ======== %m%n
      ```