京东6.18大促主会场领京享红包更优惠

 找回密码
 立即注册

QQ登录

只需一步,快速开始

为啥每次要重启服务之后日志才写到日志文件里面

2025-11-27 10:50| 发布者: zhaojun917| 查看: 5| 评论: 0

摘要: 每次重启服务后日志才写入文件,通常是日志框架的缓冲策略、配置错误、权限问题或 Appender 未正确触发导致的实时写入失效,重启时触发了缓冲刷新或配置重新加载才完成写入。以下是具体原因及解决方案:一、日志框架 ...
 每次重启服务后日志才写入文件,通常是日志框架的缓冲策略、配置错误、权限问题或 Appender 未正确触发导致的实时写入失效,重启时触发了缓冲刷新或配置重新加载才完成写入。以下是具体原因及解决方案:

一、日志框架的缓冲 / 刷新策略未配置实时刷新

Logback/Log4j2 等框架为了性能,默认会对文件输出做内存缓冲(批量写入磁盘),而非实时刷新。如果缓冲未达到阈值(如大小、时间),日志会暂存内存,重启时 JVM 关闭才强制刷新到文件,导致 “只有重启才看到日志” 的现象。

典型场景(Logback 示例):

FileAppender/RollingFileAppender 默认配置中,immediateFlush属性为false(或未显式开启),且缓冲大小 / 时间未到触发条件。

解决方法:

在 XML 配置中显式开启实时刷新,并调整缓冲参数:
xml
<!-- Logback的FileAppender/RollingFileAppender中添加 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_PATH}/app.log</file>
    <immediateFlush>true</immediateFlush> <!-- 关键:实时刷新到磁盘 -->
    <encoder>...</encoder>
    <rollingPolicy>...</rollingPolicy>
    <!-- 可选:调整缓冲大小(默认8KB),减小缓冲 -->
    <bufferSize>1KB</bufferSize>
</appender>
Log4j2 的配置类似,需开启immediateFlush
xml
<RollingFile name="FILE" fileName="${LOG_PATH}/app.log" filePattern="..." immediateFlush="true">
    ...
</RollingFile>

二、滚动策略配置错误导致日志未触发写入

如果配置了日志滚动(如按日期 / 大小分割),但滚动策略的触发条件未满足,日志可能暂存于临时缓冲或未正确路由到目标文件,重启时策略重新计算才触发写入。

常见错误场景:

  1. TimeBasedRollingPolicy 的时间格式错误:比如fileNamePattern用了%d{yyyy-MM-dd HH}但实际按天分割,导致时间粒度不匹配,触发时机延迟;
  2. SizeAndTimeBasedFNATP 的maxFileSize设置过大:比如设为 1GB,而实时日志量远未达到,导致日志一直堆积在主文件的缓冲中;
  3. 滚动策略未关联到 Appender:比如漏配<rollingPolicy><triggeringPolicy>,导致滚动失效。

解决方法:

修正滚动策略配置,确保触发条件合理:
xml
<!-- Logback正确的按日期+大小滚动配置 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>10MB</maxFileSize> <!-- 减小单文件大小阈值 -->
    </timeBasedFileNamingAndTriggeringPolicy>
    <maxHistory>30</maxHistory>
</rollingPolicy>

三、日志目录 / 文件的权限问题

应用运行的用户(如 Tomcat 用户、普通用户)没有日志目录的写入权限日志文件的修改权限,导致实时写入失败(日志框架会静默失败,不会抛错),重启时可能因用户 / 权限上下文变化(如 sudo 启动)才获得权限,完成写入。

排查方法:

  1. 检查日志目录的权限:
    bash
    运行
    ls -ld /path/to/logs/  # 确保用户有rwx权限
    
  2. 检查日志文件的权限:
    bash
    运行
    ls -l /path/to/logs/app.log  # 确保用户有rw权限
    

解决方法:

给日志目录 / 文件赋予正确权限:
bash
运行
# 递归赋予目录读写执行权限(示例用户为appuser)
chown -R appuser:appuser /path/to/logs/
chmod -R 755 /path/to/logs/

四、Appender 未正确关联到 Logger

配置中虽然定义了文件 Appender,但未将 Logger(或 Root Logger)关联到该 Appender,导致日志只输出到控制台,重启时配置加载异常 “意外” 关联成功(或用户误判)。

典型错误:

  • 漏写<appender-ref ref="FILE"/>
  • additivity="false"导致日志未传递到 Root Logger 的 FileAppender。

解决方法:

确保 Logger/Root 正确关联 FileAppender:
xml
<!-- Root Logger关联FILE和CONSOLE Appender -->
<root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/> <!-- 必须添加! -->
</root>

<!-- 自定义Logger需确保additivity不影响传递(或显式关联) -->
<logger name="com.example.controller" level="DEBUG" additivity="true">
    <appender-ref ref="FILE"/>
</logger>

五、异步 Appender 配置异常导致日志堆积

如果使用了AsyncAppender(异步日志),但配置了不合理的队列参数(如队列满、无丢弃策略),导致日志堆积在内存队列中,重启时队列刷出才写入文件。

常见错误:

  • queueSize过小且neverBlock="true",导致日志被丢弃;
  • 未配置discardingThreshold,队列满后阻塞但未处理。

解决方法:

修正 AsyncAppender 配置:
xml
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE"/>
    <queueSize>1024</queueSize> <!-- 合理的队列大小 -->
    <discardingThreshold>0</discardingThreshold> <!-- 不丢弃日志 -->
    <neverBlock>false</neverBlock> <!-- 队列满时阻塞,确保日志不丢失 -->
    <includeCallerData>false</includeCallerData>
</appender>

<!-- Root关联异步Appender -->
<root level="INFO">
    <appender-ref ref="ASYNC_FILE"/>
</root>

六、配置文件未热加载,或环境 Profile 不匹配

  1. 配置文件未开启热扫描:Logback 默认不开启配置热加载,若修改配置后未重启,旧配置(如未关联 FileAppender)仍生效,重启后新配置才加载;
  2. Spring Profile 不匹配:若用springProfile标签指定环境(如<springProfile name="prod">),但运行时未激活对应 Profile,导致 FileAppender 未生效,重启时激活 Profile 才生效。

解决方法:

  • Logback 开启配置热扫描:
    xml
    <configuration scan="true" scanPeriod="30 seconds"> <!-- 每30秒扫描配置变更 -->
        ...
    </configuration>
    
  • 确保运行时激活正确的 Profile:
    bash
    运行
    java -jar your-app.jar --spring.profiles.active=prod
    

七、相对路径导致日志文件写入位置 “隐形”

若日志文件路径用了相对路径(如./logs/app.log),应用的 ** 工作目录(Working Directory)** 可能不是预期目录,导致日志实际写入到其他位置(如 Tomcat 的 bin 目录),用户误以为 “没写入”,重启时工作目录变化才写入到预期位置。

排查方法:

在代码中打印日志文件的绝对路径(以 Logback 为例):
java
运行
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.FileAppender;

public class LogPathChecker {
    public static void printLogFilePath() {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        FileAppender<?> fileAppender = (FileAppender<?>) loggerContext.getLogger("ROOT").getAppender("FILE");
        if (fileAppender != null) {
            System.out.println("日志文件绝对路径:" + fileAppender.getFile());
        }
    }
}

解决方法:

使用绝对路径配置日志文件:
xml
<property name="LOG_PATH" value="/var/logs/my-app"/> <!-- 绝对路径 -->
<file>${LOG_PATH}/app.log</file>

总结排查步骤

  1. 检查日志框架的immediateFlush是否开启;
  2. 验证日志目录 / 文件的权限;
  3. 确认 Appender 与 Logger 的关联是否正确;
  4. 检查滚动策略 / 异步 Appender 的配置;
  5. 打印日志文件绝对路径,确认写入位置;
  6. 确保运行环境 Profile 与配置匹配。
通过以上步骤,基本能定位 “重启才写入日志” 的根源,核心是解决实时刷新、权限、配置关联这三类问题。

QQ|手机版|小黑屋|梦想之都-俊月星空 ( 粤ICP备18056059号 )|网站地图

GMT+8, 2025-11-27 20:33 , Processed in 0.067130 second(s), 17 queries .

Powered by Mxzdjyxk! X3.5

© 2001-2025 Discuz! Team.

返回顶部