In log4j2, how to configure renameEmptyFiles to be false for the RollingFile appender?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-06 08:16:47
Hein Blöd

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!