如何刷新缓冲的log4j FileAppender?

时间:2010-06-17 09:03:26

标签: java log4j buffer

在log4j中,当使用具有BufferedIO = true和BufferSize = xxx属性的FileAppender(即启用了缓冲)时,我希望能够在正常关闭过程中刷新日志。关于如何做到这一点的任何想法?

7 个答案:

答案 0 :(得分:37)

管理回答我自己的问题: - )

关闭LogManager时:

LogManager.shutdown();

所有缓冲的日志都被刷新。

答案 1 :(得分:6)

public static void flushAllLogs()
{
    try
    {
        Set<FileAppender> flushedFileAppenders = new HashSet<FileAppender>();
        Enumeration currentLoggers = LogManager.getLoggerRepository().getCurrentLoggers();
        while(currentLoggers.hasMoreElements())
        {
            Object nextLogger = currentLoggers.nextElement();
            if(nextLogger instanceof Logger)
            {
                Logger currentLogger = (Logger) nextLogger;
                Enumeration allAppenders = currentLogger.getAllAppenders();
                while(allAppenders.hasMoreElements())
                {
                    Object nextElement = allAppenders.nextElement();
                    if(nextElement instanceof FileAppender)
                    {
                        FileAppender fileAppender = (FileAppender) nextElement;
                        if(!flushedFileAppenders.contains(fileAppender) && !fileAppender.getImmediateFlush())
                        {
                            flushedFileAppenders.add(fileAppender);
                            //log.info("Appender "+fileAppender.getName()+" is not doing immediateFlush ");
                            fileAppender.setImmediateFlush(true);
                            currentLogger.info("FLUSH");
                            fileAppender.setImmediateFlush(false);
                        }
                        else
                        {
                            //log.info("fileAppender"+fileAppender.getName()+" is doing immediateFlush");
                        }
                    }
                }
            }
        }
    }
    catch(RuntimeException e)
    {
        log.error("Failed flushing logs",e);
    }
}

答案 2 :(得分:3)

public static void flushAll() {
    final LoggerContext logCtx = ((LoggerContext) LogManager.getContext());
    for(final org.apache.logging.log4j.core.Logger logger : logCtx.getLoggers()) {
        for(final Appender appender : logger.getAppenders().values()) {
            if(appender instanceof AbstractOutputStreamAppender) {
                ((AbstractOutputStreamAppender) appender).getManager().flush();
            }
        }
    }
}

答案 3 :(得分:1)

也许您可以覆盖WriterAppender#shouldFlush( LoggingEvent ),因此它会返回true作为特殊记录类别,例如log4j.flush.now,然后您调用:

LoggerFactory.getLogger("log4j.flush.now").info("Flush")

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/WriterAppender.html#shouldFlush%28org.apache.log4j.spi.LoggingEvent%29

答案 4 :(得分:1)

分享我使用“ Andrey Kurilov”的代码示例的经验,或者至少是相似的。

我真正想要实现的是使用手动刷新AsyncAppender实现一个异步日志条目,以确保在达到bufferSize之前刷新空闲缓冲区的内容。

最初的性能结果实际上可以与AsyncAppender所获得的结果相比较-因此,我认为这是一个很好的选择。

disruptor使用一个单独的线程(以及对ConfigurationSet jar的附加依赖),这使其性能更高,但是却要花费更多的CPU和甚至更多的磁盘刷新(无论高批量刷新)。

因此,如果您想节省磁盘IO操作和CPU负载,但仍要确保在某些时候异步刷新缓冲区,那是必须的方法。

答案 5 :(得分:0)

尝试:

LogFactory.releaseAll();

答案 6 :(得分:0)

我编写了一个修复此问题的appender,请参阅GitHub或使用name.wramner.log4j:Maven中的FlushAppender。它可以配置为刷新具有高严重性的事件,并且当收到特定消息时,它可以使appender无缓冲,例如“Shutting down”。检查单元测试以获取配置示例。当然是免费的。