1. 描述
一个springboot项目使用 logback 记录程序运行过程中的日志, 配置 logback 生成控制台日志和文件日志记录,以及对文件日志以日期和大小进行拆分的 demo示例。
环境:
IDE(idea):2021.3
JDK:1.8
maven:3.8.4
spring boot:2.5.6
logback-classic: 1.2.6 (spring-boot-starter-web --- spring-boot-starter --- spring-boot-starter-logging)
提示:
当前版本SizeAndTimeBasedFNATP 已弃用(SizeAndTimeBasedFNATP is deprecated.Use SizeAndTimeBasedRollingPolicy)
2. 结果
- 控制台日志格式:
- 文件日志格式:
- 日志拆分归档:eg: 日志文件最大10KB,总文件大小20KB,最长时间30天
3. demo
用了个定时任务在打印日志, 输出的日志文件用zip压缩格式进行了归档。文件大小设置的较小,以便于测试。
3.0 项目结构
3.1 pom.xml
- 引入 logback 相关jar包(web依赖中已有)。
<!-- web 包括了spring-boot-starter-logging, 默认使用logback -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.2 SpringBootApplication
- 使用了EnableScheduling 注解,启用定时任务。
@Slf4j
@EnableScheduling // 启用定时任务
@SpringBootApplication
public class DemoLogLogbackApplication {
public static void main(String[] args) {
ConfigurableEnvironment environment = SpringApplication.run(DemoLogLogbackApplication.class, args).getEnvironment();
String port = environment.getProperty("server.port");
String contextPath = environment.getProperty("server.servlet.context-path");
log.info("----- http://localhost:{}{} -----", port, contextPath);
}
}
3.3 application.yml配置
server:
port: 8880
servlet:
context-path: /demo
3.4 logback-spring.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!--
scan: 当此属性设置为 true 时,配置文件如果发生改变,将会被重新加载,默认值为 true.
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒.当 scan 为 true 时,此属性生效.默认的时间间隔为 1 分钟.
debug: 当此属性设置为 true 时,将console上打印出 logback 内部日志信息,实时查看 logback 运行状态, 但这些logback内部日志不会记录到log文件中. 默认值为 false.
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<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="%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${PID:- }){magenta} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %line %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- <property name="FILE_LOG_PATTERN"-->
<!-- value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} %line : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>-->
<!--格式化输出:%d表示日期,%thread或%t表示线程名,%-5level:级别从左显示5个字符宽度, %line: 行号,%msg或%m:日志消息,%n是换行符-->
<property name="FILE_LOG_PATTERN" value="%d ${PID:- } %-5level --- [%t] %-33.33logger{32} %line : %m%n"/>
<property name="LOG_HOME" value="/var/logs"/>
<property name="LOG_NAME" value="demo_log_logback"/>
<property name="LOG_PATH" value="${LOG_HOME}/${LOG_NAME}"/>
<!-- 日志输出:ConsoleAppender-控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder的class属性默认值为PatternLayoutEncoder -->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 日志输出:RollingFileAppender-根据rollingPolicy(滚动策略)和TriggeringPolicy(触发策略)输出日志 -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--ThresholdFilter 过滤掉低于配置级别的-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!--活动日志文件(当前写入日志的文件,没配置时,使用下面的归档日志文件做活动日志文件)-->
<file>${LOG_PATH}/${LOG_NAME}.log</file>
<!-- 滚动策略: TimeBasedRollingPolicy按时间滚动;SizeAndTimeBasedRollingPolicy按日期归档文件,但同时限制每个日志文件的大小-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径&日志文件输出的文件名-->
<FileNamePattern>${LOG_PATH}/info/${LOG_NAME}_%d{yyyy-MM-dd}.part_%i.log.zip</FileNamePattern>
<!--日志文件保留天数(maxHistory属性优先级高于totalSizeCap)-->
<maxHistory>15</maxHistory>
<!-- 总文件超出大小删除老文件(需要设置maxHistory后生效) -->
<!-- <totalSizeCap>1GB</totalSizeCap>-->
<totalSizeCap>20KB</totalSizeCap>
<!-- appender启动时,进行一次日志文件清理(作用:有些存活很短时间的应用,没机会进行文件清理) -->
<!-- <cleanHistoryOnStart>true</cleanHistoryOnStart>-->
<!-- SizeAndTimeBasedFNATP 被弃用. 参考下一个appender配置,Use SizeAndTimeBasedRollingPolicy instead. -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<Pattern>${FILE_LOG_PATTERN}</Pattern>
</encoder>
</appender>
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--LevelFilter 不等于配置级别的日志做过滤或不过略处理-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<!--匹配到(允许-ACCEPT,禁止-DENY)-->
<onMatch>ACCEPT</onMatch>
<!--没有匹配到-->
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${LOG_NAME}_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/error/${LOG_NAME}_error.%d{yyyy-MM-dd}.part_%i.log.zip</FileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>20KB</totalSizeCap>
<maxFileSize>10KB</maxFileSize>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<Pattern>${FILE_LOG_PATTERN}</Pattern>
</encoder>
</appender>
<logger name="com.demo" level="DEBUG"/>
<root>
<level value="INFO"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE_INFO"/>
<appender-ref ref="FILE_ERROR"/>
</root>
</configuration>
3.5 其他代码
- SchedulingConfig.java
/**
* 定时任务配置
*
* @author byrc
* @date 2022/3/14
*/
@Configuration
public class SchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//设定一个长度10的定时任务线程池, 多线程定时任务
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(9));
}
}
- DemoTask.java
@Slf4j
@Component
public class DemoTask {
@Scheduled(cron = "0/30 * * * * ?") //@Scheduled来创建定时任务 这个注解用来标注一个定时任务方法
public void action1() {
log.info("----- Drink water ------------------------");
}
@Scheduled(cron = "33 */1 * * * ?")
public void action2() {
log.debug("----- debug -------------");
log.info("----- info -----------");
log.warn("----- warn -------------");
log.error("----- error -------------");
}
@Scheduled(cron = "0/3 * * * * ?")
public void action3() {
log.debug("---action3-- debug ---1----------");
log.info("---action3-- info -----1------");
log.warn("---action3-- warn -----1--------");
log.error("--action3--- error ----1---------");
log.info("---action3-- info ----2-------");
log.warn("---action3-- warn -----2--------");
log.error("--action3--- error --2-----------");
log.error("--action3--- error -----ADSL飞洒发的---");
}
4. 资料
- logback的官网:https://logback.qos.ch/
- logback github:https://github.com/qos-ch/logback
5. 注
- spirng boot 已在父项目引入(父项目pom.xml配置);
- 部分jar包版本已在父项目管理(如果对应不上,一定、肯定、决定是某些修改,没同步更新文档)。
写在最后:
相比log4j2来看,logback 配置上手难度要低好多l,代码更少,更清晰一些。而log4j2 代码更多,功能扩展更多,更强大,也更细化(仅是Appender的可实例化类就是logback倍数)。 --------- 仅个人感受
- 附上一张logback的appender的类图,对比配置感觉很清晰,很好理解。