Async Log4J2 和 logrotate 无法正常工作(截断被破坏)
Async Log4J2 and logrotate not working correctly (truncate is broken)
我正在使用 Log4J2 异步记录器来记录我的 Java 应用程序,并且我正在使用 logrotate
每天存储旧日志。
以前,我同步使用 Log4J2,一切正常;因为我切换到异步日志记录 logrotate
停止正常工作。
我想我遇到了同样的问题here:因为我使用的是copytruncate
选项,旧日志文件在复制后被截断,但记录器不知道,因此它继续从“旧”索引开始写入,从而用 NUL
值填充文件中所有先前的 space,这正是我所看到的。
这是我用来启动我的应用程序的命令:
java -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -Dlog4j2.asyncQueueFullPolicy=Discard -Dlog4j2.asyncLoggerRingBufferSize=6553600 -Djava.library.path=my_libs -cp MyApplication.jar:my_libs/* com.gscaparrotti.Main >> logs/other.log
这是我的 log4j2.xml
文件的摘录:
<Configuration status="debug">
<Appenders>
<RandomAccessFile name="LogToFile" fileName="logs/standalone.log" append="true" ImmediateFlush="false">
<PatternLayout>
<Pattern>[MyApp - %t - %d{DATE}] %5p %c{1} - %m%n</Pattern>
</PatternLayout>
</RandomAccessFile>
<RandomAccessFile name="LogAnalyzer" fileName="logs/analyzer.txt" append="true" ImmediateFlush="false">
<PatternLayout>
<Pattern>[%d{DATE}] %5p %c{1} - %m%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<Root level="warn">
<AppenderRef ref="LogToFile"/>
</Root>
<Logger name="analyzer" level="debug" additivity="false">
<AppenderRef ref="LogAnalyzer"/>
</Logger>
</Loggers>
</Configuration>
这是我正在使用的 logrotate
配置(所有日志文件都相同):
/root/logs/analyzer.txt {
copytruncate
daily
rotate 4
compress
missingok
create 640 root root
}
一种解决方案是在 logrotate
之前停止我的应用程序,但这不是一个好的解决方案,因为我想要它 运行.
我还能做些什么来解决这个问题?
您应该将 RandomAccessFileAppender
替换为简单的 FileAppender
。
您的问题不是由使用异步记录器引起的,而是由您使用的附加程序引起的:
- Java的
RandomAccessFile
, which is used by the RandomAccessFileAppender
opens files in read/write mode without the O_APPEND
option (cf. open(2)),
FileOutputStream
,由通常的 FileAppender
使用,以只写模式打开文件 , O_APPEND
选项。
此选项的存在与否会影响写入的执行方式:
O_APPEND
The file is opened in append mode. Before each write(2)
,
the file offset is positioned at the end of the file, as
if with lseek(2)
. The modification of the file offset and
the write operation are performed as a single atomic step.
(来自 man open(2))。
当您截断日志文件时,FileAppender
s 偏移量将重置为 0,而 RandomAccessFileAppender
将继续在之前的位置写入。
备注: Log4j 还提供了一个RollingFileAppender
,它将完全不需要使用logrotate。
编辑:可以找到用于创建管理器使用的对象的确切选项:
- 对于
FileManagerFactory#createManager
中的 FileManager
,
- 对于
RandomAccessFileManagerFactory#createManager
中的 RandomAccessFileManager
。
我正在使用 Log4J2 异步记录器来记录我的 Java 应用程序,并且我正在使用 logrotate
每天存储旧日志。
以前,我同步使用 Log4J2,一切正常;因为我切换到异步日志记录 logrotate
停止正常工作。
我想我遇到了同样的问题here:因为我使用的是copytruncate
选项,旧日志文件在复制后被截断,但记录器不知道,因此它继续从“旧”索引开始写入,从而用 NUL
值填充文件中所有先前的 space,这正是我所看到的。
这是我用来启动我的应用程序的命令:
java -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -Dlog4j2.asyncQueueFullPolicy=Discard -Dlog4j2.asyncLoggerRingBufferSize=6553600 -Djava.library.path=my_libs -cp MyApplication.jar:my_libs/* com.gscaparrotti.Main >> logs/other.log
这是我的 log4j2.xml
文件的摘录:
<Configuration status="debug">
<Appenders>
<RandomAccessFile name="LogToFile" fileName="logs/standalone.log" append="true" ImmediateFlush="false">
<PatternLayout>
<Pattern>[MyApp - %t - %d{DATE}] %5p %c{1} - %m%n</Pattern>
</PatternLayout>
</RandomAccessFile>
<RandomAccessFile name="LogAnalyzer" fileName="logs/analyzer.txt" append="true" ImmediateFlush="false">
<PatternLayout>
<Pattern>[%d{DATE}] %5p %c{1} - %m%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<Root level="warn">
<AppenderRef ref="LogToFile"/>
</Root>
<Logger name="analyzer" level="debug" additivity="false">
<AppenderRef ref="LogAnalyzer"/>
</Logger>
</Loggers>
</Configuration>
这是我正在使用的 logrotate
配置(所有日志文件都相同):
/root/logs/analyzer.txt {
copytruncate
daily
rotate 4
compress
missingok
create 640 root root
}
一种解决方案是在 logrotate
之前停止我的应用程序,但这不是一个好的解决方案,因为我想要它 运行.
我还能做些什么来解决这个问题?
您应该将 RandomAccessFileAppender
替换为简单的 FileAppender
。
您的问题不是由使用异步记录器引起的,而是由您使用的附加程序引起的:
- Java的
RandomAccessFile
, which is used by theRandomAccessFileAppender
opens files in read/write mode without theO_APPEND
option (cf. open(2)), FileOutputStream
,由通常的FileAppender
使用,以只写模式打开文件 ,O_APPEND
选项。
此选项的存在与否会影响写入的执行方式:
O_APPEND The file is opened in append mode. Before each
write(2)
, the file offset is positioned at the end of the file, as if withlseek(2)
. The modification of the file offset and the write operation are performed as a single atomic step.
(来自 man open(2))。
当您截断日志文件时,FileAppender
s 偏移量将重置为 0,而 RandomAccessFileAppender
将继续在之前的位置写入。
备注: Log4j 还提供了一个RollingFileAppender
,它将完全不需要使用logrotate。
编辑:可以找到用于创建管理器使用的对象的确切选项:
- 对于
FileManagerFactory#createManager
中的FileManager
, - 对于
RandomAccessFileManagerFactory#createManager
中的RandomAccessFileManager
。