如何刷新缓冲的log4j FileAppender?

myss37ts  于 2022-11-06  发布在  其他
关注(0)|答案(8)|浏览(155)

在log4j中,当使用一个FileAppender,并且BufferedIO=true和BufferSize=xxx属性(即启用了缓冲)时,我希望能够在正常的关机过程中刷新日志。

cgh8pdjw

cgh8pdjw1#

关闭日志管理器时:

LogManager.shutdown();

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

zzlelutf

zzlelutf2#

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);
    }
}
n1bvdmb6

n1bvdmb63#

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();
            }
        }
    }
}
0sgqnhkj

0sgqnhkj4#

也许你可以重写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

3pvhb19x

3pvhb19x5#

分享我的经验与使用“安德烈库里洛夫”的代码示例,或至少相似。
我实际上想要实现的是实现一个带有手动刷新(immediateFlush = false)的异步日志条目,以确保在达到bufferSize之前刷新空闲缓冲区的内容。
最初的性能结果实际上与AsyncAppender相当,因此我认为它是一个很好的替代品。
AsyncAppender使用单独的线程(以及对disruptor jar的额外依赖),这使其性能更高,但代价是更多的CPU和甚至更多的磁盘刷新(无论高负载刷新是在批处理上进行的)。
因此,如果您希望保存磁盘IO操作和CPU负载,但仍希望确保缓冲区在某个时间点异步刷新,这是一种可行的方法。

5lhxktic

5lhxktic6#

请尝试:

LogFactory.releaseAll();
qacovj5a

qacovj5a7#

我已经写了一个附加器来修复这个问题,请参见GitHub或使用Maven中的name.wramner.log4j:FlushAppender。它可以被配置为对严重性高的事件进行刷新,并且当它接收到特定的消息时,可以使附加器不缓冲,例如“正在关闭”。请查看单元测试中的配置示例。当然,它是免费的。

643ylb08

643ylb088#

对我有效的唯一解决办法是等待一段时间:

private void flushAppender(Appender appender) {
    // this flush seems to be useless
    ((AbstractOutputStreamAppender<?>) appender).getManager().flush(); 
    try {
        Thread.sleep(500); // wait for log4j to flush logs
    } catch (InterruptedException ignore) {
    }
}

相关问题