You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2017/06/27 06:48:41 UTC

logging-log4j2 git commit: [LOG4J2-1766] Temporary compress directory during rollover (#88).

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 3f4536859 -> e7b638929


[LOG4J2-1766] Temporary compress directory during rollover (#88).

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e7b63892
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e7b63892
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e7b63892

Branch: refs/heads/master
Commit: e7b638929cc71ed626b52263ac6a04388b1e7dbd
Parents: 3f45368
Author: Pierrick HYMBERT <pi...@gmail.com>
Authored: Mon Jun 26 23:48:37 2017 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Mon Jun 26 23:48:37 2017 -0700

----------------------------------------------------------------------
 .../core/appender/RollingFileAppender.java      |  12 +-
 .../RollingRandomAccessFileAppender.java        |   6 +-
 .../rolling/DefaultRolloverStrategy.java        | 279 ++++++++++++++++---
 .../rolling/DirectWriteRolloverStrategy.java    | 210 ++++++++++++--
 ...irectWriteTempCompressedFilePatternTest.java |  98 +++++++
 ...ngAppenderTempCompressedFilePatternTest.java | 151 ++++++++++
 ...log4j-rolling-direct-tmp-compress-folder.xml |  52 ++++
 .../resources/log4j-rolling-gz-tmp-compress.xml |  62 +++++
 src/changes/changes.xml                         |   3 +
 src/site/xdoc/manual/appenders.xml              |  10 +
 10 files changed, 827 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
index 1072259..bcba88f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
@@ -125,11 +125,15 @@ public final class RollingFileAppender extends AbstractOutputStreamAppender<Roll
 
             if (strategy == null) {
                 if (fileName != null) {
-                    strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
-                            String.valueOf(Deflater.DEFAULT_COMPRESSION), null, true, getConfiguration());
+                    strategy = DefaultRolloverStrategy.newBuilder()
+                                        .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION))
+                                        .withConfig(getConfiguration())
+                                        .build();
                 } else {
-                    strategy = DirectWriteRolloverStrategy.createStrategy(null,
-                            String.valueOf(Deflater.DEFAULT_COMPRESSION), null, true, getConfiguration());
+                    strategy = DirectWriteRolloverStrategy.newBuilder()
+                                        .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION))
+                                        .withConfig(getConfiguration())
+                                        .build();
                 }
             } else if (fileName == null && !(strategy instanceof DirectFileRolloverStrategy)) {
                 LOGGER.error("RollingFileAppender '{}': When no file name is provided a DirectFilenameRolloverStrategy must be configured");

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
index 89c2008..6148dec 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
@@ -111,8 +111,10 @@ public final class RollingRandomAccessFileAppender extends AbstractOutputStreamA
             }
 
             if (strategy == null) {
-                strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
-                        String.valueOf(Deflater.DEFAULT_COMPRESSION), null, true, getConfiguration());
+                strategy = DefaultRolloverStrategy.newBuilder()
+                                .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION))
+                                .withConfig(getConfiguration())
+                                .build();
             }
 
             final Layout<? extends Serializable> layout = getOrCreateLayout();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
index 4141195..865eeb4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
@@ -37,6 +37,8 @@ import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeA
 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.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
 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;
@@ -83,6 +85,195 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
     private static final int DEFAULT_WINDOW_SIZE = 7;
 
     /**
+     * Builds DefaultRolloverStrategy instances.
+     */
+    public static class Builder implements org.apache.logging.log4j.core.util.Builder<DefaultRolloverStrategy> {
+        @PluginBuilderAttribute("max")
+        private String max;
+        
+        @PluginBuilderAttribute("min")
+        private String min;
+        
+        @PluginBuilderAttribute("fileIndex")
+        private String fileIndex;
+
+        @PluginBuilderAttribute("compressionLevel")
+        private String compressionLevelStr;
+
+        @PluginElement("Actions")
+        private Action[] customActions;
+
+        @PluginBuilderAttribute(value = "stopCustomActionsOnError")
+        private boolean stopCustomActionsOnError = true;
+
+        @PluginBuilderAttribute(value = "tempCompressedFilePattern")
+        private String tempCompressedFilePattern;
+
+        @PluginConfiguration
+        private Configuration config;
+
+        @Override
+        public DefaultRolloverStrategy build() {
+            int minIndex;
+            int maxIndex;
+            boolean useMax;
+
+            if (fileIndex != null && fileIndex.equalsIgnoreCase("nomax")) {
+                minIndex = Integer.MIN_VALUE;
+                maxIndex = Integer.MAX_VALUE;
+                useMax = false;
+            } else {
+                useMax = fileIndex == null ? true : fileIndex.equalsIgnoreCase("max");
+                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;
+                    }
+                }
+                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 DefaultRolloverStrategy(minIndex, maxIndex, useMax, compressionLevel, config.getStrSubstitutor(),
+                    customActions, stopCustomActionsOnError, tempCompressedFilePattern);
+        }
+
+        public String getMax() {
+            return max;
+        }
+
+        /**
+         * Defines the maximum number of files to keep.
+         *
+         * @param max The maximum number of files to keep.
+         * @return This builder for chaining convenience
+         */
+        public Builder withMax(String max) {
+            this.max = max;
+            return this;
+        }
+
+        public String getMin() {
+            return min;
+        }
+
+        /**
+         * Defines the minimum number of files to keep.
+         *
+         * @param min The minimum number of files to keep.
+         * @return This builder for chaining convenience
+         */
+        public Builder withMin(String min) {
+            this.min = min;
+            return this;
+        }
+
+        public String getFileIndex() {
+            return fileIndex;
+        }
+
+        /**
+         * Defines the file index for rolling strategy.
+         *
+         * @param fileIndex If set to "max" (the default), files with a higher index will be newer than files with a smaller
+         *            index. If set to "min", file renaming and the counter will follow the Fixed Window strategy.
+         * @return This builder for chaining convenience
+         */
+        public Builder withFileIndex(String fileIndex) {
+            this.fileIndex = fileIndex;
+            return this;
+        }
+
+        public String getCompressionLevelStr() {
+            return compressionLevelStr;
+        }
+
+        /**
+         * Defines compression level.
+         *
+         * @param compressionLevelStr The compression level, 0 (less) through 9 (more); applies only to ZIP files.
+         * @return This builder for chaining convenience
+         */
+        public Builder withCompressionLevelStr(String compressionLevelStr) {
+            this.compressionLevelStr = compressionLevelStr;
+            return this;
+        }
+
+        public Action[] getCustomActions() {
+            return customActions;
+        }
+
+        /**
+         * Defines custom actions.
+         *
+         * @param customActions custom actions to perform asynchronously after rollover
+         * @return This builder for chaining convenience
+         */
+        public Builder withCustomActions(Action[] customActions) {
+            this.customActions = customActions;
+            return this;
+        }
+
+        public boolean isStopCustomActionsOnError() {
+            return stopCustomActionsOnError;
+        }
+
+        /**
+         * Defines whether to stop executing asynchronous actions if an error occurs.
+         *
+         * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+         * @return This builder for chaining convenience
+         */
+        public Builder withStopCustomActionsOnError(boolean stopCustomActionsOnError) {
+            this.stopCustomActionsOnError = stopCustomActionsOnError;
+            return this;
+        }
+
+        public String getTempCompressedFilePattern() {
+            return tempCompressedFilePattern;
+        }
+
+        /**
+         * Defines temporary compression file pattern.
+         *
+         * @param tempCompressedFilePattern File pattern of the working file pattern used during compression, if null no temporary file are used
+         * @return This builder for chaining convenience
+         */
+        public Builder withTempCompressedFilePattern(String tempCompressedFilePattern) {
+            this.tempCompressedFilePattern = tempCompressedFilePattern;
+            return this;
+        }
+
+        public Configuration getConfig() {
+            return config;
+        }
+
+        /**
+         * Defines configuration.
+         * 
+         * @param config The Configuration.
+         * @return This builder for chaining convenience
+         */
+        public Builder withConfig(Configuration config) {
+            this.config = config;
+            return this;
+        }
+    }
+
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
      * Creates the DefaultRolloverStrategy.
      *
      * @param max The maximum number of files to keep.
@@ -94,8 +285,10 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
      * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
      * @param config The Configuration.
      * @return A DefaultRolloverStrategy.
+     * @deprecated Since 2.9 Usage of Builder API is preferable
      */
     @PluginFactory
+    @Deprecated
     public static DefaultRolloverStrategy createStrategy(
             // @formatter:off
             @PluginAttribute("max") final String max,
@@ -106,37 +299,16 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
             @PluginAttribute(value = "stopCustomActionsOnError", defaultBoolean = true)
                     final boolean stopCustomActionsOnError,
             @PluginConfiguration final Configuration config) {
+        return DefaultRolloverStrategy.newBuilder()
+                    .withMin(min)
+                    .withMax(max)
+                    .withFileIndex(fileIndex)
+                    .withCompressionLevelStr(compressionLevelStr)
+                    .withCustomActions(customActions)
+                    .withStopCustomActionsOnError(stopCustomActionsOnError)
+                    .withConfig(config)
+                .build();
             // @formatter:on
-        int minIndex;
-        int maxIndex;
-        boolean useMax;
-
-        if (fileIndex != null && fileIndex.equalsIgnoreCase("nomax")) {
-            minIndex = Integer.MIN_VALUE;
-            maxIndex = Integer.MAX_VALUE;
-            useMax = false;
-        } else {
-            useMax = fileIndex == null ? true : fileIndex.equalsIgnoreCase("max");
-            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;
-                }
-            }
-            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 DefaultRolloverStrategy(minIndex, maxIndex, useMax, compressionLevel, config.getStrSubstitutor(),
-                customActions, stopCustomActionsOnError);
     }
 
     /**
@@ -152,6 +324,7 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
     private final int compressionLevel;
     private final List<Action> customActions;
     private final boolean stopCustomActionsOnError;
+    private final PatternProcessor tempCompressedFilePattern;
 
     /**
      * Constructs a new instance.
@@ -160,10 +333,29 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
      * @param maxIndex The maximum index.
      * @param customActions custom actions to perform asynchronously after rollover
      * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+     * @deprecated Since 2.9 Added tempCompressedFilePatternString parameter
      */
+    @Deprecated
     protected DefaultRolloverStrategy(final int minIndex, final int maxIndex, final boolean useMax,
             final int compressionLevel, final StrSubstitutor strSubstitutor, final Action[] customActions,
             final boolean stopCustomActionsOnError) {
+        this(minIndex, maxIndex, useMax, compressionLevel,
+                       strSubstitutor, customActions, stopCustomActionsOnError, null);
+    }
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param minIndex The minimum index.
+     * @param maxIndex The maximum index.
+     * @param customActions custom actions to perform asynchronously after rollover
+     * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+     * @param tempCompressedFilePatternString File pattern of the working file
+     *                                     used during compression, if null no temporary file are used
+     */
+    protected DefaultRolloverStrategy(final int minIndex, final int maxIndex, final boolean useMax,
+            final int compressionLevel, final StrSubstitutor strSubstitutor, final Action[] customActions,
+            final boolean stopCustomActionsOnError, final String tempCompressedFilePatternString) {
         super(strSubstitutor);
         this.minIndex = minIndex;
         this.maxIndex = maxIndex;
@@ -171,6 +363,8 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
         this.compressionLevel = compressionLevel;
         this.stopCustomActionsOnError = stopCustomActionsOnError;
         this.customActions = customActions == null ? Collections.<Action> emptyList() : Arrays.asList(customActions);
+        this.tempCompressedFilePattern =
+                tempCompressedFilePatternString != null ? new PatternProcessor(tempCompressedFilePatternString) : null;
     }
 
     public int getCompressionLevel() {
@@ -197,6 +391,10 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
         return useMax;
     }
 
+    public PatternProcessor getTempCompressedFilePattern() {
+        return tempCompressedFilePattern;
+    }
+
     private int purge(final int lowIndex, final int highIndex, final RollingFileManager manager) {
         return useMax ? purgeAscending(lowIndex, highIndex, manager) : purgeDescending(lowIndex, highIndex, manager);
     }
@@ -344,9 +542,26 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
 
         FileExtension fileExtension = manager.getFileExtension();
         if (fileExtension != null) {
+            final File renameToFile = new File(renameTo);
             renameTo = renameTo.substring(0, renameTo.length() - fileExtension.length());
-            compressAction = fileExtension.createCompressAction(renameTo, compressedName,
-                    true, compressionLevel);
+            if (tempCompressedFilePattern != null) {
+                buf.delete(0, buf.length());
+                tempCompressedFilePattern.formatFileName(strSubstitutor, buf, fileIndex);
+                String tmpCompressedName = buf.toString();
+                final File tmpCompressedNameFile = new File(tmpCompressedName);
+                if (tmpCompressedNameFile.getParentFile() != null) {
+                    tmpCompressedNameFile.getParentFile().mkdirs();
+                }
+                compressAction = new CompositeAction(
+                        Arrays.asList(fileExtension.createCompressAction(renameTo, tmpCompressedName,
+                                true, compressionLevel),
+                                new FileRenameAction(tmpCompressedNameFile,
+                                        renameToFile, true)),
+                        true);
+            } else {
+                compressAction = fileExtension.createCompressAction(renameTo, compressedName,
+                        true, compressionLevel);
+            }
         }
 
         if (currentFileName.equals(renameTo)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
index 6ce58d8..06dd5d3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
+import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -29,11 +30,14 @@ import java.util.zip.Deflater;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.appender.rolling.action.Action;
 import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
+import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
 import org.apache.logging.log4j.core.appender.rolling.action.PathCondition;
 import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeAction;
 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.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
 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;
@@ -56,6 +60,141 @@ import org.apache.logging.log4j.core.util.Integers;
 public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implements DirectFileRolloverStrategy {
 
     private static final int DEFAULT_MAX_FILES = 7;
+    
+    /**
+     * Builds DirectWriteRolloverStrategy instances.
+     */
+    public static class Builder implements org.apache.logging.log4j.core.util.Builder<DirectWriteRolloverStrategy> {
+        @PluginBuilderAttribute("maxFiles")
+        private String maxFiles;
+
+        @PluginBuilderAttribute("compressionLevel")
+        private String compressionLevelStr;
+
+        @PluginElement("Actions")
+        private Action[] customActions;
+
+        @PluginBuilderAttribute(value = "stopCustomActionsOnError")
+        private boolean stopCustomActionsOnError = true;
+
+        @PluginBuilderAttribute(value = "tempCompressedFilePattern")
+        private String tempCompressedFilePattern;
+
+        @PluginConfiguration
+        private Configuration config;
+
+        @Override
+        public DirectWriteRolloverStrategy build() {
+            int maxIndex = Integer.MAX_VALUE;
+            if (maxFiles != null) {
+                maxIndex = Integer.parseInt(maxFiles);
+                if (maxIndex < 0) {
+                    maxIndex = Integer.MAX_VALUE;
+                } else if (maxIndex < 2) {
+                    LOGGER.error("Maximum files too small. Limited to " + DEFAULT_MAX_FILES);
+                    maxIndex = DEFAULT_MAX_FILES;
+                }
+            }
+            final int compressionLevel = Integers.parseInt(compressionLevelStr, Deflater.DEFAULT_COMPRESSION);
+            return new DirectWriteRolloverStrategy(maxIndex, compressionLevel, config.getStrSubstitutor(),
+                    customActions, stopCustomActionsOnError, tempCompressedFilePattern);
+        }
+
+        public String getMaxFiles() {
+            return maxFiles;
+        }
+
+        /**
+         * Defines the maximum number of files to keep.
+         *
+         * @param maxFiles The maximum number of files that match the date portion of the pattern to keep.
+         * @return This builder for chaining convenience
+         */
+        public Builder withMaxFiles(String maxFiles) {
+            this.maxFiles = maxFiles;
+            return this;
+        }
+
+        public String getCompressionLevelStr() {
+            return compressionLevelStr;
+        }
+
+        /**
+         * Defines compression level.
+         *
+         * @param compressionLevelStr The compression level, 0 (less) through 9 (more); applies only to ZIP files.
+         * @return This builder for chaining convenience
+         */
+        public Builder withCompressionLevelStr(String compressionLevelStr) {
+            this.compressionLevelStr = compressionLevelStr;
+            return this;
+        }
+
+        public Action[] getCustomActions() {
+            return customActions;
+        }
+
+        /**
+         * Defines custom actions.
+         *
+         * @param customActions custom actions to perform asynchronously after rollover
+         * @return This builder for chaining convenience
+         */
+        public Builder withCustomActions(Action[] customActions) {
+            this.customActions = customActions;
+            return this;
+        }
+
+        public boolean isStopCustomActionsOnError() {
+            return stopCustomActionsOnError;
+        }
+
+        /**
+         * Defines whether to stop executing asynchronous actions if an error occurs.
+         *
+         * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+         * @return This builder for chaining convenience
+         */
+        public Builder withStopCustomActionsOnError(boolean stopCustomActionsOnError) {
+            this.stopCustomActionsOnError = stopCustomActionsOnError;
+            return this;
+        }
+
+        public String getTempCompressedFilePattern() {
+            return tempCompressedFilePattern;
+        }
+
+        /**
+         * Defines temporary compression file pattern.
+         *
+         * @param tempCompressedFilePattern File pattern of the working file pattern used during compression, if null no temporary file are used
+         * @return This builder for chaining convenience
+         */
+        public Builder withTempCompressedFilePattern(String tempCompressedFilePattern) {
+            this.tempCompressedFilePattern = tempCompressedFilePattern;
+            return this;
+        }
+
+        public Configuration getConfig() {
+            return config;
+        }
+
+        /**
+         * Defines configuration.
+         * 
+         * @param config The Configuration.
+         * @return This builder for chaining convenience
+         */
+        public Builder withConfig(Configuration config) {
+            this.config = config;
+            return this;
+        }
+    }
+
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
 
     /**
      * Creates the DirectWriteRolloverStrategy.
@@ -65,8 +204,10 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
      * @param customActions custom actions to perform asynchronously after rollover
      * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
      * @param config The Configuration.
-     * @return A DefaultRolloverStrategy.
+     * @return A DirectWriteRolloverStrategy.
+     * @deprecated Since 2.9 Usage of Builder API is preferable
      */
+    @Deprecated
     @PluginFactory
     public static DirectWriteRolloverStrategy createStrategy(
             // @formatter:off
@@ -76,20 +217,13 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
             @PluginAttribute(value = "stopCustomActionsOnError", defaultBoolean = true)
                     final boolean stopCustomActionsOnError,
             @PluginConfiguration final Configuration config) {
+            return newBuilder().withMaxFiles(maxFiles)
+                    .withCompressionLevelStr(compressionLevelStr)
+                    .withCustomActions(customActions)
+                    .withStopCustomActionsOnError(stopCustomActionsOnError)
+                    .withConfig(config)
+                    .build();
             // @formatter:on
-        int maxIndex = Integer.MAX_VALUE;
-        if (maxFiles != null) {
-            maxIndex = Integer.parseInt(maxFiles);
-            if (maxIndex < 0) {
-                maxIndex = Integer.MAX_VALUE;
-            } else if (maxIndex < 2) {
-                LOGGER.error("Maximum files too small. Limited to " + DEFAULT_MAX_FILES);
-                maxIndex = DEFAULT_MAX_FILES;
-            }
-        }
-        final int compressionLevel = Integers.parseInt(compressionLevelStr, Deflater.DEFAULT_COMPRESSION);
-        return new DirectWriteRolloverStrategy(maxIndex, compressionLevel, config.getStrSubstitutor(),
-                customActions, stopCustomActionsOnError);
     }
 
     /**
@@ -101,22 +235,42 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
     private final boolean stopCustomActionsOnError;
     private volatile String currentFileName;
     private int nextIndex = -1;
+    private final PatternProcessor tempCompressedFilePattern;
 
     /**
      * Constructs a new instance.
      *
-     * @param maxFiles The minimum index.
+     * @param maxFiles The maximum number of files that match the date portion of the pattern to keep.
      * @param customActions custom actions to perform asynchronously after rollover
      * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+     * @deprecated Since 2.9 Added tempCompressedFilePatternString parameter
      */
+    @Deprecated
     protected DirectWriteRolloverStrategy(final int maxFiles, final int compressionLevel,
                                           final StrSubstitutor strSubstitutor, final Action[] customActions,
                                           final boolean stopCustomActionsOnError) {
+        this(maxFiles, compressionLevel, strSubstitutor, customActions, stopCustomActionsOnError, null);
+    }
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param maxFiles The maximum number of files that match the date portion of the pattern to keep.
+     * @param customActions custom actions to perform asynchronously after rollover
+     * @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
+     * @param tempCompressedFilePatternString File pattern of the working file
+     *                                     used during compression, if null no temporary file are used
+     */
+    protected DirectWriteRolloverStrategy(final int maxFiles, final int compressionLevel,
+                                          final StrSubstitutor strSubstitutor, final Action[] customActions,
+                                          final boolean stopCustomActionsOnError, final String tempCompressedFilePatternString) {
         super(strSubstitutor);
         this.maxFiles = maxFiles;
         this.compressionLevel = compressionLevel;
         this.stopCustomActionsOnError = stopCustomActionsOnError;
         this.customActions = customActions == null ? Collections.<Action> emptyList() : Arrays.asList(customActions);
+        this.tempCompressedFilePattern =
+                tempCompressedFilePatternString != null ? new PatternProcessor(tempCompressedFilePatternString) : null;
     }
 
     public int getCompressionLevel() {
@@ -135,6 +289,10 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
         return stopCustomActionsOnError;
     }
 
+    public PatternProcessor getTempCompressedFilePattern() {
+        return tempCompressedFilePattern;
+    }
+
     private int purge(final RollingFileManager manager) {
         SortedMap<Integer, Path> eligibleFiles = getEligibleFiles(manager);
         LOGGER.debug("Found {} eligible files, max is  {}", eligibleFiles.size(), maxFiles);
@@ -190,9 +348,25 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
         nextIndex = fileIndex + 1;
         FileExtension fileExtension = manager.getFileExtension();
         if (fileExtension != null) {
-            compressedName += fileExtension.getExtension();
-            compressAction = fileExtension.createCompressAction(sourceName, compressedName,
-                    true, compressionLevel);
+            compressedName += fileExtension.getExtension();            
+            if (tempCompressedFilePattern != null) {
+                StringBuilder buf = new StringBuilder();
+                tempCompressedFilePattern.formatFileName(strSubstitutor, buf, fileIndex);
+                String tmpCompressedName = buf.toString();
+                final File tmpCompressedNameFile = new File(tmpCompressedName);
+                if (tmpCompressedNameFile.getParentFile() != null) {
+                    tmpCompressedNameFile.getParentFile().mkdirs();
+                }
+                compressAction = new CompositeAction(
+                        Arrays.asList(fileExtension.createCompressAction(sourceName, tmpCompressedName,
+                                true, compressionLevel),
+                                new FileRenameAction(tmpCompressedNameFile,
+                                        new File(compressedName), true)),
+                        true);
+            } else {
+                compressAction = fileExtension.createCompressAction(sourceName, compressedName,
+                      true, compressionLevel);
+            }
         }
 
         if (manager.isPosixSupported()) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteTempCompressedFilePatternTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteTempCompressedFilePatternTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteTempCompressedFilePatternTest.java
new file mode 100644
index 0000000..8b6430b
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDirectWriteTempCompressedFilePatternTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender.rolling;
+
+import static org.apache.logging.log4j.hamcrest.Descriptors.that;
+import static org.apache.logging.log4j.hamcrest.FileMatchers.hasName;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.hasItemInArray;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+/**
+ * LOG4J2-1766.
+ */
+public class RollingAppenderDirectWriteTempCompressedFilePatternTest {
+
+    private static final String CONFIG = "log4j-rolling-direct-tmp-compress-folder.xml";
+
+    private static final String DIR = "target/rolling-direct";
+
+    public static LoggerContextRule loggerContextRule = LoggerContextRule
+            .createShutdownTimeoutLoggerContextRule(CONFIG);
+
+    @Rule
+    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+
+    private Logger logger;
+
+    @Before
+    public void setUp() throws Exception {
+        this.logger = loggerContextRule.getLogger(RollingAppenderDirectWriteTest.class.getName());
+    }
+
+    @Test
+    public void testAppender() throws Exception {
+        final File dir = new File(DIR);
+        dir.mkdirs();
+        final WatchService watcher = FileSystems.getDefault().newWatchService();
+        WatchKey key = dir.toPath().register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
+
+        for (int i = 0; i < 100; ++i) {
+            logger.debug("This is test message number " + i);
+        }
+        Thread.sleep(50);
+        assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0);
+        final File[] files = dir.listFiles();
+        assertNotNull(files);
+        assertThat(files, hasItemInArray(that(hasName(that(endsWith(".gz"))))));
+
+        int temporaryFilesCreated = 0;
+        int compressedFiles = 0;
+        key = watcher.take();
+
+        for (final WatchEvent<?> event : key.pollEvents()) {
+            final WatchEvent.Kind<?> kind = event.kind();
+            final WatchEvent<Path> ev = (WatchEvent<Path>) event;
+            final Path filename = ev.context();
+            if (filename.toString().endsWith(".tmp")) {
+                temporaryFilesCreated++;
+            }
+            if (filename.toString().endsWith(".gz")) {
+                compressedFiles++;
+            }
+        }
+        assertTrue("No temporary file created during compression", temporaryFilesCreated > 0);
+        assertTrue("Temporarys file created not equals to compressed files", compressedFiles == temporaryFilesCreated);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTempCompressedFilePatternTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTempCompressedFilePatternTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTempCompressedFilePatternTest.java
new file mode 100644
index 0000000..a62d494
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderTempCompressedFilePatternTest.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender.rolling;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.compress.compressors.CompressorException;
+import org.apache.commons.compress.compressors.CompressorStreamFactory;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+/**
+ * LOG4J2-1766.
+ */
+public class RollingAppenderTempCompressedFilePatternTest {
+
+    private static final String CONFIG = "log4j-rolling-gz-tmp-compress.xml";
+
+    private static final String DIR = "target/rolling2";
+    private static final String DIR_TMP = "target/rolling-tmp";
+
+    public static LoggerContextRule loggerContextRule = LoggerContextRule
+            .createShutdownTimeoutLoggerContextRule(CONFIG);
+
+    @Rule
+    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR, DIR_TMP);
+
+    private Logger logger;
+
+    @Before
+    public void setUp() throws Exception {
+        this.logger = loggerContextRule.getLogger(RollingAppenderTempCompressedFilePatternTest.class.getName());
+    }
+
+    @Test
+    public void testAppender() throws Exception {
+        final File dirTmp = new File(DIR_TMP);
+        dirTmp.mkdirs();
+        final WatchService watcher = FileSystems.getDefault().newWatchService();
+        WatchKey key = dirTmp.toPath().register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
+
+        final List<String> messages = new ArrayList<>();
+        for (int i = 0; i < 500; ++i) {
+            final String message = "This is test message number " + i;
+            messages.add(message);
+            logger.debug(message);
+            if (i % 100 == 0) {
+                Thread.sleep(500);
+            }
+        }
+        if (!loggerContextRule.getLoggerContext().stop(30, TimeUnit.SECONDS)) {
+            System.err.println("Could not stop cleanly " + loggerContextRule + " for " + this);
+        }
+        final File dir = new File(DIR);
+        assertTrue("Directory not created", dir.exists());
+        final File[] files = dir.listFiles();
+        assertNotNull(files);
+        int gzippedFiles = 0;
+        for (final File file : files) {
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            InputStream in = null;
+            final FileExtension ext = FileExtension.lookupForFile(file.getName());
+            try {
+                try (FileInputStream fis = new FileInputStream(file)) {
+                    if (ext != null) {
+                        gzippedFiles++;
+                        try {
+                            in = new CompressorStreamFactory().createCompressorInputStream(ext.name().toLowerCase(),
+                                    fis);
+                        } catch (final CompressorException ce) {
+                            ce.printStackTrace();
+                            fail("Error creating intput stream from " + file.toString() + ": " + ce.getMessage());
+                        }
+                    } else {
+                        in = new FileInputStream(file);
+                    }
+                    assertNotNull("No input stream for " + file.getName(), in);
+                    try {
+                        IOUtils.copy(in, baos);
+                    } catch (final Exception ex) {
+                        ex.printStackTrace();
+                        fail("Unable to decompress " + file.getAbsolutePath());
+                    }
+                }
+            } finally {
+                Closer.close(in);
+            }
+            final String text = new String(baos.toByteArray(), Charset.defaultCharset());
+            final String[] lines = text.split("[\\r\\n]+");
+            for (final String line : lines) {
+                messages.remove(line);
+            }
+        }
+        assertTrue("Log messages lost : " + messages.size(), messages.isEmpty());
+        assertTrue("Files not rolled : " + files.length, files.length > 2);
+        assertTrue("Files gzipped not rolled : " + gzippedFiles, gzippedFiles > 0);
+
+        int temporaryFilesCreated = 0;
+        key = watcher.take();
+
+        for (final WatchEvent<?> event : key.pollEvents()) {
+            final WatchEvent.Kind<?> kind = event.kind();
+            final WatchEvent<Path> ev = (WatchEvent<Path>) event;
+            final Path filename = ev.context();
+            if (filename.toString().endsWith(".tmp")) {
+                temporaryFilesCreated++;
+            }
+        }
+        assertTrue("No temporary file created during compression", temporaryFilesCreated > 0);
+        assertTrue(
+                "Temporarys file created not equals to compressed files " + temporaryFilesCreated + "/" + gzippedFiles,
+                gzippedFiles == temporaryFilesCreated);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/test/resources/log4j-rolling-direct-tmp-compress-folder.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-rolling-direct-tmp-compress-folder.xml b/log4j-core/src/test/resources/log4j-rolling-direct-tmp-compress-folder.xml
new file mode 100644
index 0000000..cac266b
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-rolling-direct-tmp-compress-folder.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="WARN" name="XMLConfigTest">
+  <Properties>
+    <Property name="logDir">target/rolling-direct</Property>
+  </Properties>
+  <ThresholdFilter level="debug"/>
+
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <RollingFile name="RollingFile" filePattern="${logDir}/test1-%d{MM-dd-yy-HH-mm}-%i.log.gz">
+      <PatternLayout>
+        <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+      </PatternLayout>
+      <Policies>
+        <TimeBasedTriggeringPolicy />
+        <SizeBasedTriggeringPolicy size="500" />
+      </Policies>
+      <DirectWriteRolloverStrategy 
+      	 tempCompressedFilePattern="${logDir}/test1-%d{MM-dd-yy-HH-mm}-%i.log.gz.tmp"/>
+    </RollingFile>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
+      <AppenderRef ref="RollingFile"/>
+    </Logger>>
+
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/log4j-core/src/test/resources/log4j-rolling-gz-tmp-compress.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-rolling-gz-tmp-compress.xml b/log4j-core/src/test/resources/log4j-rolling-gz-tmp-compress.xml
new file mode 100644
index 0000000..5caf196
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-rolling-gz-tmp-compress.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="WARN" name="XMLConfigTest">
+  <Properties>
+    <Property name="filename">target/rolling2/rollingtest.log</Property>
+  </Properties>
+  <ThresholdFilter level="debug"/>
+
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <RollingFile name="RollingFile" fileName="${filename}"
+                 filePattern="target/rolling2/test1-$${date:MM-dd-yyyy}-%i.log.gz"
+                 createOnDemand="true">
+      <PatternLayout>
+        <Pattern>%m%n</Pattern>
+      </PatternLayout>
+      <SizeBasedTriggeringPolicy size="500" />
+      <DefaultRolloverStrategy
+      	 fileIndex="nomax"
+      	 tempCompressedFilePattern="target/rolling-tmp/test1-$${date:MM-dd-yyyy}-%i.log.gz.tmp"/>
+    </RollingFile>
+    <List name="List">
+      <ThresholdFilter level="error"/>
+    </List>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
+      <ThreadContextMapFilter>
+        <KeyValuePair key="test" value="123"/>
+      </ThreadContextMapFilter>
+      <AppenderRef ref="STDOUT"/>
+    </Logger>>
+
+    <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
+      <AppenderRef ref="RollingFile"/>
+    </Logger>>
+
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 91b1101..d272730 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -31,6 +31,9 @@
          - "remove" - Removed
     -->
     <release version="2.9.0" date="2017-MM-DD" description="GA Release 2.9.0">
+      <action issue="LOG4J2-1766" dev="ggregory" type="add" due-to="Pierrick HYMBERT">
+        Temporary compress directory during rollover (#88).
+      </action>
       <action issue="LOG4J2-1950" dev="ggregory" type="update" due-to="Pierrick HYMBERT">
         Fix docker build with jdk9 requirements (#84).
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e7b63892/src/site/xdoc/manual/appenders.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml
index ba1bf7d..339d35c 100644
--- a/src/site/xdoc/manual/appenders.xml
+++ b/src/site/xdoc/manual/appenders.xml
@@ -2930,6 +2930,11 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity {
                     Only implemented for ZIP files.
                   </td>
                 </tr>
+                <tr>
+                  <td>tempCompressedFilePattern</td>
+                  <td>String</td>
+                  <td>The pattern of the file name of the archived log file during compression.</td>
+                </tr>
               </table>
           <a name="DirectWriteRolloverStrategy"/>
           <h5>DirectWrite Rollover Strategy</h5>
@@ -2968,6 +2973,11 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity {
                   Only implemented for ZIP files.
                 </td>
               </tr>
+              <tr>
+                <td>tempCompressedFilePattern</td>
+                <td>String</td>
+                <td>The pattern of the file name of the archived log file during compression.</td>
+              </tr>
             </table>
           <p>
             Below is a sample configuration that uses a RollingFileAppender with both the time and size based