现象
spring boot 2.1.6
CentOS 7.4
jdk 1.8
logback 1.2.3
- 一个普通的spring boot项目,在一个磁盘空间相对较小的机器上运行一段时间后总会导致磁盘占满
分析
- spring boot使用logback作为日志组件,并且有日志滚动策略,并且日志滚动策略为
RollingFileAppender
:最多生成10个日志文件,每个日志文件最多10M,理论情况下,日志应该最多占用110M空间,实际情况也是如此,因此排除日志文件写满磁盘的原因; - 使用
du -h / --max-depth=1
查看各个根目录占用的磁盘空间,发现/var
目录存在异常:
- 进一步排查发现是
/var/log/message*
占用较大的磁盘空间:
- 查看任何一个文件,发现内容竟然是spring boot项目的日志,甚至是已经滚动覆盖了的日志;
- 进一步查询搜索得知,linux系统下的
/var/log/message
是记录系统服务启动后产生的日志的,也就是说spring boot项目是由一个系统服务启动的,实际情况也正是如此,我们使用systemctl status <jar_pid>找到了启动该项目的服务文件:
- 是不是说所有使用系统服务启动的进程,日志都会保存到
/var/log/message
呢?经过进一步验证得知,只要进程启动后不在控制台输出日志,/var/log/message
就不会记录该进程的日志,因此猜测spring boot项目除了往日志文件打印日志外,应该也向控制台打印了日志,查看项目使用的logback.xml后,果真如此:
名称为<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <property name="logHome" value="/path/to/log/"/> <property name="maxHistory" value="7"/> <property name="maxFileSize" value="10MB"/> <property name="totalSizeCap" value="200MB"/> <property name="minIndexNum" value="1"/> <property name="maxIndexNum" value="10"/> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] [%p] [%class:%line] %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logHome}/info.log</file> <append>true</append> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>${logHome}/info.%i.log.zip</fileNamePattern> <minIndex>${minIndexNum}</minIndex> <maxIndex>${maxIndexNum}</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>${maxFileSize}</maxFileSize> </triggeringPolicy> <encoder> <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] [%p] [%class:%line] %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <root level="INFO"> <appender-ref ref="STDOUT"/> <appender-ref ref="INFO"/> </root> </configuration>
STDOUT
的appender即为输出日志到控制台的配置,注释掉<appender-ref ref="STDOUT"/>
后,发现项目不再输出日志到/var/log/message
原因
可以总结出问题产生的原因:
- 项目由系统服务启动
- 项目有日志输出到控制台,特别是所有日志都输出到控制台
- 系统日志没有排除sprint boot产生的日志
解决方案
- 对于使用logback.xml的sprint boot项目,问题解决很简单:直接检查并禁止控制台输出即可,但禁止后会导致本地调试较难,因为没有控制台日志,可以考虑不同环境使用不同的profile;
- 对于直接使用application.properties配置日志的项目,可以添加或修改一行配置:
logging.pattern.console=
,没错,value为空,这样可以阻止spring boot项目输出日志到控制台,但这仅仅是一个hack方法,不是logging.pattern.console
参数的正常表现,甚至是一个BUG,不保证在后续版本中依然生效;
以上两种解决方案都是在不修改系统配置的情况下,仅改变项目本身的配置或部署流程来解决该问题。
- 同时也可以修改系统日志配置,比如
CentOS 7
可以修改/etc/rsyslog.conf
(其他发行版本和小版本可能路径有差异),将/var/log/message
的日志监听,排除掉自己的项目,甚至禁止所有日志输出到/var/log/message
:/var/log/messages迅速增大的问题