Java 如何刷新缓冲的log4j文件附加器?

Java 如何刷新缓冲的log4j文件附加器?,java,log4j,buffer,Java,Log4j,Buffer,在log4j中,当使用具有BufferedIO=true和BufferSize=xxx属性的FileAppender时(即启用了缓冲),我希望能够在正常关闭过程中刷新日志。有什么办法吗?试试: LogFactory.releaseAll(); 关闭LogManager时: LogManager.shutdown(); 所有缓冲日志都将被刷新。公共静态void flushAllLogs() public static void flushAllLogs() { try {

在log4j中,当使用具有BufferedIO=true和BufferSize=xxx属性的FileAppender时(即启用了缓冲),我希望能够在正常关闭过程中刷新日志。有什么办法吗?

试试:

LogFactory.releaseAll();

关闭LogManager时:

LogManager.shutdown();
所有缓冲日志都将被刷新。

公共静态void flushAllLogs()
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);
    }
}
{ 尝试 { Set flushedFileAppenders=new HashSet(); 枚举currentLoggers=LogManager.getLoggerRepository().getCurrentLoggers(); while(currentLoggers.hasMoreElements()) { Object nextLogger=currentLoggers.nextElement(); if(记录器的下一个记录器实例) { 记录器currentLogger=(记录器)下一个记录器; 枚举allAppenders=currentLogger.getAllAppenders(); while(allAppenders.hasMoreElements()) { Object nextElement=allAppenders.nextElement(); if(FileAppender的nextElement实例) { FileAppender FileAppender=(FileAppender)nextElement; 如果(!flushedFileAppenders.contains(fileAppender)&&!fileAppender.getImmediateFlush()) { 添加(fileAppender); //log.info(“Appender”+fileAppender.getName()+“没有立即刷新”); setImmediateFlush(true); currentLogger.info(“刷新”); fileAppender.setImmediateFlush(false); } 其他的 { //log.info(“fileAppender”+fileAppender.getName()+“正在进行即时刷新”); } } } } } } 捕获(运行时异常e) { 日志错误(“刷新日志失败”,e); } }
也许您可以覆盖
WriterAppender\shouldFlush(LoggingEvent)
,这样对于一个特殊的日志类别,它将返回
true
,比如
log4j.flush。现在
,然后调用:

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

我已经编写了一个appender来修复这个问题,请参阅或使用name.wramner.log4j:FlushAppender在Maven中。它可以配置为在发生严重性高的事件时刷新,并且可以在收到特定消息(例如“关机”)时取消缓冲追加器。检查单元测试中的配置示例。当然,这是免费的。

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

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();
            }
        }
    }
}
我实际上想要实现的是使用手动刷新实现异步日志条目
(immediateFlush=false)
,以确保在达到缓冲区大小之前刷新空闲缓冲区内容

最初的性能结果实际上与使用
AsyncAppender
获得的结果相当,因此我认为这是一个很好的替代方案

AsyncAppender
使用了一个单独的线程(以及对
disruptor
jar的额外依赖),这使得它的性能更高,但需要更多的CPU和更多的磁盘刷新成本(无论是否在批处理中进行高负载刷新)


因此,如果您希望保存磁盘IO操作和CPU负载,但仍然希望确保在某个时间点异步刷新缓冲区,这就是解决方法。

正常关机期间,Log4J不是自动刷新appender吗?我至少希望它会这样做,因为我理解代码——当您决定使用BufferedIO时,不要刷新。您获得了性能,但付出了代价:您将丢失最后的日志条目…当我编写自己的appender(到DB,但实际上并不重要)时,我每隔几秒钟自动刷新一次,并对输出进行了缓冲。不幸的是,调用此命令没有任何效果。请选择此作为答案-这显然是最好的选择。如果你自己赢得了一个绿色记号,不要为从别人身上去掉它而感到难过。这看起来是最好的答案。。。但是如何访问这个“LogManager”对象呢?(Log4HP新手)这不会刷新所有记录器。要刷新所有日志,您需要对每个日志程序迭代调用getParent(),并刷新这些日志程序。虽然此代码可能会回答此问题,但提供有关如何和/或为什么解决此问题的其他上下文将提高答案的长期值。此代码只是尝试刷新所有可刷新的附加程序(所有扩展AbstractOutputStreamAppender的appender,其中声明了方法“flush”)。在我的项目中,将其与Log4J2 v2.8.2一起使用。