1. Background
During our development, the following situations may exist:
1. 有些时候我们需要调用第三方的接口
general, when calling the interface, we will record the input parameters and responses of the request. If our own system logs and third-party logs are mixed into one log file, it may be more troublesome to find logs. 那么我们是否可以将第三方系统的日志单独放到另外的文件中呢?
2. Or sometimes our system needs to perform data migration. If a certain data migration fails, 是否单独放到一个日志文件中比较清晰呢?
2. Demand
As can be seen from the above figure, our requirements are relatively simple
1. The system startup log and login
module log are recorded in the springboot-spring.log
file.
2. The log of the third-party business ( QQ
) module is recorded in the springboot-qq.log
file.
3、第三方业务( QQ
)模块login(loginName)
方法, 方法的入参loginName
到springboot-qqLoginName.log
文件中,模拟一、背景
The data migration mentioned in 一、背景
failed, and the failed data was recorded in a separate log file.
3. Technical realization
1. The logging framework used
Here we use logback
to complete the log recording, because SpringBoot
the application default is logback to record the log.
2. If you implement sub-module and sub-file logging
1. Write appender
, which can easily understand where the log needs to be output.
for example:
<!-- 此处定义的日志输出到控制台 -->
<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. How to implement module output log
Here we need to configure logger
. The logger's name
attribute is assigned to the specific full package name, and then quoting the appender
defined above.
<!-- 在QQ这个包下的日志单独使用 qqAppender 来输出 -->
<logger name="com.huan.springboot.qq" level="info" additivity="false">
<appender-ref ref="qqAppender"/>
<appender-ref ref="stdout"/>
</logger>
Configure the logger, the name of the logger is the full package name of the package that needs to generate files separately, and then reference the appender defined above in it
3. If the implementation outputs the loginName to the specified file
In fact, still use logger
to achieve, the logger's name
needs and LoggerFactory.getLogger("此处写具体logger的name的值")
Notice:
There may be a pit here, that is, the class name may be lost, so how do we solve it? It can be solved by MDC
.
.... %X{CLASSNAME}#%method:%L -%msg%n
MDC.put("CLASSNAME", QQService.class.getName());
qqLoginName.info("登录用户:[{}]", loginName);
xml
%X{CLASSNAME}
, java
代码MDC
CLASSNAME
的值。
Fourth, code implementation
1. Write the xml log file
1. Write the appender
1. Output log to console
<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. Write login
template log
<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. Write qq
template 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>
<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. Write the log that the qq module loginName outputs to the file separately
<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. Configure the log output to a specific location
1. Configure the login module
<root level="INFO">
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</root>
login
The module belongs to our own system module, here we use the root
tag to configure.
2. Configure the qq module
<!-- 在QQ这个包下的日志单独使用 qqAppender 来输出 -->
<logger name="com.huan.springboot.qq" level="info" additivity="false">
<appender-ref ref="qqAppender"/>
<appender-ref ref="stdout"/>
</logger>
Here the value of name
is directly assigned to the full package name path of qq
.
3. Configure loginName to output to a file separately
<!-- 将所有的QQ登录名防止在另外的文件中 -->
<logger name="qqLoginName" level="info" additivity="false">
<appender-ref ref="qqLoginNameAppender"/>
<appender-ref ref="stdout"/>
</logger>
2. Write the code of the QQ module
@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. Write the code of the login module
@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";
}
}
5. Running results
It can be seen that the results we expect are obtained.
6. Complete code
https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-logger-split-file
Seven, a little knowledge
In SpringBoot, if we want to override the default logback configuration, it is recommended to use logback-spring.xml
to configure.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。