一、背景

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

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

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

二、需求



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

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的值")



注意:

此处可能有一个坑,就是可能会丢失类名,那么我们如何进行解决呢?可以通过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";
}
}

五、运行结果



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

六、完整代码

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

七、一个小知识点

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

Spring按业务模块输出日志到不同的文件的更多相关文章

  1. SpringBoot+logback实现按业务输出日志到不同的文件

        公司有个项目,需要和几个第三方系统对接.这种项目,日志一定要记录详细,不然出了问题就是各种甩锅.虽然项目里面和第三方系统对接相关的业务记录的日志很详细,但是由于整个项目的日志都在一个文件中,排 ...

  2. spring boot使用slf4j输出日志

    spring boot使用slf4j输出日志 https://blog.csdn.net/qq442270636/article/details/79406346 Spring Boot SLF4J日 ...

  3. python3:logging模块 输出日志到文件

    python自动化测试脚本运行后,想要将日志保存到某个特定文件,使用python的logging模块实现 参考代码: import logging def initLogging(logFilenam ...

  4. Python Logging模块 输出日志颜色、过期清理和日志滚动备份

    # coding:utf-8 import logging from logging.handlers import RotatingFileHandler # 按文件大小滚动备份 import co ...

  5. logback怎么写?分类输出日志到不同的文件

    此appender有顺序,最好不要乱调顺序,输出日志如下: drwxr-xr-x 2 root root 4096 Dec 3 00:00 2019-12-02drwxr-xr-x 2 root ro ...

  6. Spring boot配置log4j输出日志

    1. pom.xml文件中配置parent,版本选定[1.2.5.RELEASE] 关于为什么要选这个版本:我尝试使用[1.4.1.RELEASE],但该版本库里没有[spring-boot-star ...

  7. 通过python的logging模块输出日志文件

    import logging import sys #获取logger实例 logger = logging.getLogger("baseSpider") # 括号后面填运行的文 ...

  8. Log4j日志根据配置输出到多个自定义文件

    最近工作中遇到所有日志需要记录到一个文件,而错误的sql执行记录到另一个文件中,查询了一些资料搞定,记录下来.顺便吐槽下公司限制印象笔记的使用. ##log4j.rootLogger=INFO, CO ...

  9. logback不同业务的日志打印到不同文件

    logback不同业务的日志打印到不同文件    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/mggwct/article/details/777 ...

随机推荐

  1. Shiro快速使用

    INI的文件的介绍:https://baike.baidu.com/item/ini%E6%96%87%E4%BB%B6/9718973?fr=aladdin Shiro的INI配置文件:http:/ ...

  2. 解释 WEB 模块?

    Spring 的 WEB 模块是构建在 application context 模块基础之上,提供一个适 合 web 应用的上下文.这个模块也包括支持多种面向 web 的任务,如透明地处理 多个文件上 ...

  3. Java 中,编写多线程程序的时候你会遵循哪些最佳实践?

    这是我在写 Java 并发程序的时候遵循的一些最佳实践: a)给线程命名,这样可以帮助调试. b)最小化同步的范围,而不是将整个方法同步,只对关键部分做同步. c)如果可以,更偏向于使用 volati ...

  4. Centos最小化安装

    1.选择最小安装: 2.选择相应的安装包 老男孩提示: 1.根据经验,选择安装包时应该按最小化原则,即不需要的或者不确定是否需要的就不安装,这样可以最大程度上确保系统安全. 2.如果安装过程落了部分包 ...

  5. js技术之如何在JS中获取input的值

    在JavaScript中获取input元素value的值: 方法一:var variations_number = $("#input的id名").val(); 1 <!DO ...

  6. can总线第二讲

    一 CAN总线拓扑结构CAN是一种分布式的控制总线,总线上的每一个节点一般来说都比较简单,使用MCU控制器处理CAN总线数据,完成特定的功能:通过CAN总线将各节点连接只需较少的线缆(两根线:CAN_ ...

  7. 三、原理图生成网表并导入PCB放置元件

    1.生成网表 2.成功标志 3.新建PCB文件 4.导入网表至PCB 5.导入网表成功标志 6.创建.psm文件(绘制的封装格式为.dra文件,在PCB里面要以.psm的文件存在)  将丝印做成封装需 ...

  8. TOGAF D阶段:技术架构

    11. Phase D: Technology Architecture (opengroup.org) Phase D: Technology Architecture D阶段:技术架构 11.1 ...

  9. logback日志级别动态切换的终极方案(asm使用)

    背景 一切皆有因果,所有事情,都有事件驱动.本方案的日志级别切换是由这样的背景下产生的: 单个生产环境上,有几百近千个微服务 日志级别切换不重启服务,要求即时生效果 由业务开发人员去修改代码或增加相关 ...

  10. JavaScript の 内容属性(HTML属性attribute)和 DOM 属性(property)

    [博文]内容属性(HTML属性)和 DOM 属性 标签: 博文 JavaScript 粗略解读(与jQuery做对比) 内容属性(HTML属性) : attribute DOM 属性(Element属 ...