目录
  • 一、背景
  • 二、需求
  • 三、技术实现
  • 四、代码实现
    • 1、编写xml日志文件
    • 2、编写QQ模块的代码
    • 3、编写login模块的代码
  • 五、运行结果
    • 六、完整代码
      • 七、一个小知识点
        • 总结

          一、背景

          在我们开发的过程中,可能存在如下情况:

          1、有些时候我们需要调用第三方的接口,一般情况下,调用接口,我们都会记录请求的入参和响应的。如果我们自己系统的日志和第三方的日志混合到一个日志文件中,那么可能查找日志就比较麻烦了。那么我们是否可以将第三方系统的日志单独放到另外的文件中呢?

          2、或者有些时候我们系统需要进行数据迁移,如果某条数据迁移失败了,是否单独放到一个日志文件中比较清晰呢?

          二、需求

          Spring如何按业务模块输出日志到不同的文件详解

          从上图中可以看到我们的需求比较简单

          1、系统启动日志和 login 模块日志记录到 springboot-spring.log 文件中。

          2、第三方业务(QQ)模块的日志记录到 springboot-qq.log文件中。

          3、第三方业务(QQ)模块提供了一个login(loginName)方法,方法的入参loginName需要记录到springboot-qqLoginName.log文件中,模拟一、背景中提到的数据迁移失败,记录失败的数据到单独的日志文件中。

          三、技术实现

          1、采用的日志框架

          此处使用logback来完成日志的记录,因为SpringBoot应用程序默认的就是采用的logback来记录日志。

          2、如果实现分模块、分文件记录日志1、 编写appender,这个可以简单的理解日志需要输出到哪里。

          比如:

          <!-- 此处定义的日志输出到控制台 -->
          <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
              <encoder>
                  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [${PID:- }] [%thread] %-5level %logger{50}#%method:%L -%msg%n</pattern>
          
              </encoder>
          </appender>
          
          <!-- 此处定义日志输出到 springboot-qq-日期.第几个.log 文件中 -->
          <appender name="qqAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
              <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                  <fileNamePattern>logs/springboot-qq-%d{yyyy-MM-dd}-.%i.log</fileNamePattern>
              </rollingPolicy>
             
          </appender>
          

          2、如何实现模块输出日志

          此处就需要我们来配置 logger了。logger的name属性指定到具体的全包名,然后引用我们上面定义的appender即可。

          <!-- 在QQ这个包下的日志单独使用 qqAppender 来输出 -->
          <logger name="com.huan.springboot.qq" level="info" additivity="false">
              <appender-ref ref="qqAppender"/>
              <appender-ref ref="stdout"/>
          </logger>
          

          配置logger,logger的name为需要单独生成文件的那个包的全包名,然后在里面引用上面定义的appender

          3、如果实现将loginName输出到指定的文件

          其实还是使用 logger 来实现,logger的name需要和 LoggerFactory.getLogger("此处写具体logger的name的值")

          Spring如何按业务模块输出日志到不同的文件详解

          注意:

          此处可能有一个坑,就是可能会丢失类名,那么我们如何进行解决呢?可以通过MDC来解决。

          .... %X{CLASSNAME}#%method:%L -%msg%n
          
          MDC.put("CLASSNAME", QQService.class.getName());
          qqLoginName.info("登录用户:[{}]", loginName);
          

          即xml中使用%X{CLASSNAME},在java代码中使用MDC存入CLASSNAME的值。

          四、代码实现

          1、编写xml日志文件

          1、编写appender

          1、输出日志到控制台

          <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
              <encoder>
                  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [${PID:- }] [%thread] %-5level %logger{50}#%method:%L -%msg%n</pattern>
                  <charset>UTF-8</charset>
              </encoder>
          </appender>
          

          2、编写login模板的日志

          <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
                  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                      <fileNamePattern>logs/springboot-spring-%d{yyyy-MM-dd}-.%i.log</fileNamePattern>
                      <maxHistory>7</maxHistory>
                      <maxFileSize>1MB</maxFileSize>
                      <totalSizeCap>2GB</totalSizeCap>
                  </rollingPolicy>
                  <encoder>
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [${PID:- }] [%thread] %-5level %logger{50}#%method:%L -%msg%n</pattern>
                      <charset>UTF-8</charset>
                  </encoder>
              </appender>
          

          3、编写qq模板的日志

          <appender name="qqAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
                  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                      <fileNamePattern>logs/springboot-qq-%d{yyyy-MM-dd}-.%i.log</fileNamePattern>
                      <maxHistory>7</maxHistory>
                      <maxFileSize>1MB</maxFileSize>
                      <totalSizeCap>2GB</totalSizeCap>
                  </rollingPolicy>
                  <encoder>
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [${PID:- }] [%thread] %-5level %logger{50}#%method:%L -%msg%n</pattern>
                      <charset>UTF-8</charset>
                  </encoder>
              </appender>
          

          4、编写qq模块loginName单独输出到文件的日志

          <appender name="qqLoginNameAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
                  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                      <fileNamePattern>logs/springboot-qqLoginName-%d{yyyy-MM-dd}-.%i.log</fileNamePattern>
                      <maxHistory>7</maxHistory>
                      <maxFileSize>1MB</maxFileSize>
                      <totalSizeCap>2GB</totalSizeCap>
                  </rollingPolicy>
                  <encoder>
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [${PID:- }] [%thread] %-5level %X{CLASSNAME}#%method:%L -%msg%n</pattern>
                      <charset>UTF-8</charset>
                  </encoder>
              </appender>
          

          2、配置日志输出到具体位置

          1、配置login模块

          <root level="INFO">
              <appender-ref ref="stdout"/>
              <appender-ref ref="file"/>
          </root>
          

          login模块属于我们自己的系统模块,此处使用 root标签来配置。

          2、配置qq模块

          <!-- 在QQ这个包下的日志单独使用 qqAppender 来输出 -->
          <logger name="com.huan.springboot.qq" level="info" additivity="false">
              <appender-ref ref="qqAppender"/>
              <appender-ref ref="stdout"/>
          </logger>
          

          此处name的值直接指定到了qq的全包名路径。

          3、配置loginName单独输出到文

          <!-- 将所有的QQ登录名防止在另外的文件中 -->
          <logger name="qqLoginName" level="info" additivity="false">
              <appender-ref ref="qqLoginNameAppender"/>
              <appender-ref ref="stdout"/>
          </logger>
          

          2、编写QQ模块的代码

          @Component
          public class QQService {
          
              private static final Logger log = LoggerFactory.getLogger(QQService.class);
          
              // getLogger("qqLoginName") 里的 qqLoginName 需要和 logback-spring.xml 中 logger的name一致,才会应用
              private static final Logger qqLoginName = LoggerFactory.getLogger("qqLoginName");
          
              public void login(String loginName) {
                  log.info("QQ业务: 用户:[{}]开始使用QQ来登录系统", loginName);
          
                  MDC.put("CLASSNAME", QQService.class.getName());
                  qqLoginName.info("登录用户:[{}]", loginName);
              }
          }
          

          3、编写login模块的代码

          @RestController
          public class LoginController {
          
              private static final Logger log = LoggerFactory.getLogger(LoginController.class);
          
              @Resource
              private QQService qqService;
          
              @GetMapping("login/{loginName}")
              public String login(@PathVariable("loginName") String loginName) {
                  log.info("自己业务:用户:[{}]进行登录", loginName);
                  qqService.login(loginName);
                  return "ok";
              }
          }
          

          五、运行结果

          Spring如何按业务模块输出日志到不同的文件详解

          可以看到得到了我们期望的结果。

          六、完整代码

          https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-logger-split-file

          七、一个小知识点

          在SpringBoot中,如果我们要覆盖默认的logback配置,推荐使用logback-spring.xml来配置。

          Spring如何按业务模块输出日志到不同的文件详解

          总结

          声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。