在log4j2中,如何为RollingFile Appender配置RenameEmptyFiles为false?[英] In log4j2, how to configure renameEmptyFiles to be false for the RollingFile appender?

本文是小编为大家收集整理的关于在log4j2中,如何为RollingFile Appender配置RenameEmptyFiles为false?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在使用log4j 2和rollingfile appender:

<RollingFile name="mylog"
fileName="mylog.log"
filePattern="mylog.log.%d{yyyy-MM-dd}.log">
  <PatternLayout>
    <pattern>[%d] [%-5p] [%-8t] %F:%L %m%n</pattern>
  </PatternLayout>
  <Policies>
    <TimeBasedTriggeringPolicy interval="1"/>
  </Policies>
</RollingFile>

日志文件每天都会重命名.但是 FileRenameAction类的Javadoc 表示有一个option renameEmptyFiles默认情况下是错误的,因此,如果一天的日志为空,则将其删除它而不是将日期附加到文件名上的日期而重命名.如何将其配置为true,因为我想拥有日志文件,即使它为空?

推荐答案

我制作了一个提供所需功能的小插件.我简单地扩展了DefaultRolloverStrategy并替换(因为它的所有字段都是final)RolloverDescription从rollover()返回的对象.我从DefaultRolloverStrategy中复制了静态@PluginFactory代码,因为log4j 2插件系统需要.

这是代码:

import java.util.zip.Deflater;

import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
import org.apache.logging.log4j.core.appender.rolling.RolloverDescription;
import org.apache.logging.log4j.core.appender.rolling.RolloverDescriptionImpl;
import org.apache.logging.log4j.core.appender.rolling.action.Action;
import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.util.Integers;

@Plugin( name = "KeepEmptyFilesRolloverStrategy", category = "Core", printObject = true )
public class KeepEmptyFilesRolloverStrategy extends DefaultRolloverStrategy
{
   private static final int MIN_WINDOW_SIZE = 1;
   private static final int DEFAULT_WINDOW_SIZE = 7;

   @PluginFactory
   public static KeepEmptyFilesRolloverStrategy createStrategy( @PluginAttribute( "max" ) final String max,
                                                                @PluginAttribute( "min" ) final String min,
                                                                @PluginAttribute( "fileIndex" ) final String fileIndex,
                                                                @PluginAttribute( "compressionLevel" ) final String compressionLevelStr,
                                                                @PluginElement( "Actions" ) final Action[] customActions,
                                                                @PluginAttribute( value = "stopCustomActionsOnError", defaultBoolean = true ) final boolean stopCustomActionsOnError,
                                                                @PluginConfiguration final Configuration config )
   {
      final boolean useMax = fileIndex == null ? true : fileIndex.equalsIgnoreCase( "max" );
      int minIndex = MIN_WINDOW_SIZE;
      if ( min != null )
      {
         minIndex = Integer.parseInt( min );
         if ( minIndex < 1 )
         {
            LOGGER.error( "Minimum window size too small. Limited to " + MIN_WINDOW_SIZE );
            minIndex = MIN_WINDOW_SIZE;
         }
      }
      int maxIndex = DEFAULT_WINDOW_SIZE;
      if ( max != null )
      {
         maxIndex = Integer.parseInt( max );
         if ( maxIndex < minIndex )
         {
            maxIndex = minIndex < DEFAULT_WINDOW_SIZE ? DEFAULT_WINDOW_SIZE : minIndex;
            LOGGER.error( "Maximum window size must be greater than the minimum windows size. Set to "
                          + maxIndex );
         }
      }
      final int compressionLevel = Integers.parseInt( compressionLevelStr, Deflater.DEFAULT_COMPRESSION );
      return new KeepEmptyFilesRolloverStrategy( minIndex,
                                                 maxIndex,
                                                 useMax,
                                                 compressionLevel,
                                                 config.getStrSubstitutor(),
                                                 customActions,
                                                 stopCustomActionsOnError );
   }

   protected KeepEmptyFilesRolloverStrategy( int minIndex,
                                             int maxIndex,
                                             boolean useMax,
                                             int compressionLevel,
                                             StrSubstitutor subst,
                                             Action[] customActions,
                                             boolean stopCustomActionsOnError )
   {
      super( minIndex, maxIndex, useMax, compressionLevel, subst, customActions, stopCustomActionsOnError );
   }

   @Override
   public RolloverDescription rollover( final RollingFileManager manager ) throws SecurityException
   {
      RolloverDescription oldResult = super.rollover( manager );

      // Fail fast (ClassCastException) if implementation of DefaultRolloverStrategy 
      // ever changes and uses a different Action type. 
      FileRenameAction oldRenameAction = (FileRenameAction) oldResult.getSynchronous();
      FileRenameAction newRenameAction = new FileRenameAction( oldRenameAction.getSource(),
                                                               oldRenameAction.getDestination(),
                                                               true );

      RolloverDescription newResult = new RolloverDescriptionImpl( oldResult.getActiveFileName(),
                                                                   oldResult.getAppend(),
                                                                   newRenameAction,
                                                                   oldResult.getAsynchronous() );

      return newResult;
   }
}

要使用此类,只需在log4j 2 XML配置中引用它,例如这样:

<RollingFile name="RollingFile" fileName="/usr/local/glassfish4.1-webprofile/glassfish/domains/domain1/logs/server.log" filePattern="/usr/local/glassfish4.1-webprofile/glassfish/domains/domain1/logs/server.%d{yyyyMMdd-HH:mm}.log">
  <KeepEmptyFilesRolloverStrategy/>
  <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
  <CronTriggeringPolicy schedule="0 * * * * ?"/>
</RollingFile>

该实现的灵感来自 this 相关答案.

在旁注上,可能有必要使用新的CronTriggeringPolicy完全创建空的日志文件,因为它使用单独的线程.从其他一些答案来看,至少其他一些政策只要申请人不写任何东西,就无法对触发器做出反应.

本文地址:https://www.itbaoku.cn/post/1574952.html

问题描述

I'm using log4j 2 and RollingFile appender:

<RollingFile name="mylog"
fileName="mylog.log"
filePattern="mylog.log.%d{yyyy-MM-dd}.log">
  <PatternLayout>
    <pattern>[%d] [%-5p] [%-8t] %F:%L %m%n</pattern>
  </PatternLayout>
  <Policies>
    <TimeBasedTriggeringPolicy interval="1"/>
  </Policies>
</RollingFile>

The log files do get renamed daily. But the Javadoc of FileRenameAction class indicates there is an option renameEmptyFiles which is false by default so if a day's log is empty it deletes it instead of rename it appending the date to the file name. How to configure it to true since I'd like to have the log file even if it's empty?

推荐答案

I made a little plugin that offers the desired functionality. I simply extended the DefaultRolloverStrategy and replaced (as all of its fields are final) the RolloverDescription object that is returned from rollover(). I copied the static @PluginFactory code from DefaultRolloverStrategy as it's required for the Log4j 2 plugin system.

Here's the code:

import java.util.zip.Deflater;

import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
import org.apache.logging.log4j.core.appender.rolling.RolloverDescription;
import org.apache.logging.log4j.core.appender.rolling.RolloverDescriptionImpl;
import org.apache.logging.log4j.core.appender.rolling.action.Action;
import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.util.Integers;

@Plugin( name = "KeepEmptyFilesRolloverStrategy", category = "Core", printObject = true )
public class KeepEmptyFilesRolloverStrategy extends DefaultRolloverStrategy
{
   private static final int MIN_WINDOW_SIZE = 1;
   private static final int DEFAULT_WINDOW_SIZE = 7;

   @PluginFactory
   public static KeepEmptyFilesRolloverStrategy createStrategy( @PluginAttribute( "max" ) final String max,
                                                                @PluginAttribute( "min" ) final String min,
                                                                @PluginAttribute( "fileIndex" ) final String fileIndex,
                                                                @PluginAttribute( "compressionLevel" ) final String compressionLevelStr,
                                                                @PluginElement( "Actions" ) final Action[] customActions,
                                                                @PluginAttribute( value = "stopCustomActionsOnError", defaultBoolean = true ) final boolean stopCustomActionsOnError,
                                                                @PluginConfiguration final Configuration config )
   {
      final boolean useMax = fileIndex == null ? true : fileIndex.equalsIgnoreCase( "max" );
      int minIndex = MIN_WINDOW_SIZE;
      if ( min != null )
      {
         minIndex = Integer.parseInt( min );
         if ( minIndex < 1 )
         {
            LOGGER.error( "Minimum window size too small. Limited to " + MIN_WINDOW_SIZE );
            minIndex = MIN_WINDOW_SIZE;
         }
      }
      int maxIndex = DEFAULT_WINDOW_SIZE;
      if ( max != null )
      {
         maxIndex = Integer.parseInt( max );
         if ( maxIndex < minIndex )
         {
            maxIndex = minIndex < DEFAULT_WINDOW_SIZE ? DEFAULT_WINDOW_SIZE : minIndex;
            LOGGER.error( "Maximum window size must be greater than the minimum windows size. Set to "
                          + maxIndex );
         }
      }
      final int compressionLevel = Integers.parseInt( compressionLevelStr, Deflater.DEFAULT_COMPRESSION );
      return new KeepEmptyFilesRolloverStrategy( minIndex,
                                                 maxIndex,
                                                 useMax,
                                                 compressionLevel,
                                                 config.getStrSubstitutor(),
                                                 customActions,
                                                 stopCustomActionsOnError );
   }

   protected KeepEmptyFilesRolloverStrategy( int minIndex,
                                             int maxIndex,
                                             boolean useMax,
                                             int compressionLevel,
                                             StrSubstitutor subst,
                                             Action[] customActions,
                                             boolean stopCustomActionsOnError )
   {
      super( minIndex, maxIndex, useMax, compressionLevel, subst, customActions, stopCustomActionsOnError );
   }

   @Override
   public RolloverDescription rollover( final RollingFileManager manager ) throws SecurityException
   {
      RolloverDescription oldResult = super.rollover( manager );

      // Fail fast (ClassCastException) if implementation of DefaultRolloverStrategy 
      // ever changes and uses a different Action type. 
      FileRenameAction oldRenameAction = (FileRenameAction) oldResult.getSynchronous();
      FileRenameAction newRenameAction = new FileRenameAction( oldRenameAction.getSource(),
                                                               oldRenameAction.getDestination(),
                                                               true );

      RolloverDescription newResult = new RolloverDescriptionImpl( oldResult.getActiveFileName(),
                                                                   oldResult.getAppend(),
                                                                   newRenameAction,
                                                                   oldResult.getAsynchronous() );

      return newResult;
   }
}

To use this class, simply reference it in the Log4j 2 XML configuration, e.g. like this:

<RollingFile name="RollingFile" fileName="/usr/local/glassfish4.1-webprofile/glassfish/domains/domain1/logs/server.log" filePattern="/usr/local/glassfish4.1-webprofile/glassfish/domains/domain1/logs/server.%d{yyyyMMdd-HH:mm}.log">
  <KeepEmptyFilesRolloverStrategy/>
  <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
  <CronTriggeringPolicy schedule="0 * * * * ?"/>
</RollingFile>

The implementation was inspired by this related answer.

On a sidenote, it might be necessary to use the new CronTriggeringPolicy to have empty log files being created at all, as it uses a separate thread. Judging from some other answers on SO, at least some of the other policies cannot react to the trigger as long as the Appender doesn't write out anything.