logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rpo...@apache.org
Subject svn commit: r1498044 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/appender/ core/src/main/java/org/apache/logging/log4j/core/appender/rolling/ core/src/test/java/org/apache/logging/log4j/core/appender/ core/src/tes...
Date Sun, 30 Jun 2013 00:40:33 GMT
Author: rpopma
Date: Sun Jun 30 00:40:33 2013
New Revision: 1498044

URL: http://svn.apache.org/r1498044
Log:
Fixes for LOG4J2-295, LOG4J2-292 and LOG4J2-267 Fast(Rolling)FileAppender bugs; added JUnit
tests.

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java
  (with props)
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java
  (with props)
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FastFileManager.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManager.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FastFileManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FastFileManager.java?rev=1498044&r1=1498043&r2=1498044&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FastFileManager.java
(original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FastFileManager.java
Sun Jun 30 00:40:33 2013
@@ -32,7 +32,7 @@ import java.util.Map;
  * I/O.
  */
 public class FastFileManager extends OutputStreamManager {
-    private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
+    static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
 
     private static final FastFileManagerFactory FACTORY = new FastFileManagerFactory();
 
@@ -42,8 +42,9 @@ public class FastFileManager extends Out
     private final ByteBuffer buffer;
     private ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
 
-    protected FastFileManager(final RandomAccessFile file, final String fileName,
-            final OutputStream os, final boolean immediateFlush, final String advertiseURI,
+    protected FastFileManager(final RandomAccessFile file,
+            final String fileName, final OutputStream os,
+            final boolean immediateFlush, final String advertiseURI,
             final Layout layout) {
         super(os, fileName, layout);
         this.isImmediateFlush = immediateFlush;
@@ -57,18 +58,21 @@ public class FastFileManager extends Out
 
     /**
      * Returns the FastFileManager.
-     *
+     * 
      * @param fileName The name of the file to manage.
-     * @param append true if the file should be appended to, false if it should be overwritten.
-     * @param isFlush true if the contents should be flushed to disk on every write
+     * @param append true if the file should be appended to, false if it should
+     *            be overwritten.
+     * @param isFlush true if the contents should be flushed to disk on every
+     *            write
      * @param advertiseURI the URI to use when advertising the file
      * @param layout The layout.
      * @return A FastFileManager for the File.
      */
-    public static FastFileManager getFileManager(final String fileName, final boolean append,
-                                                 final boolean isFlush, final String advertiseURI,
-                                                 final Layout layout) {
-        return (FastFileManager) getManager(fileName, new FactoryData(append, isFlush, advertiseURI,
layout), FACTORY);
+    public static FastFileManager getFileManager(final String fileName,
+            final boolean append, final boolean isFlush,
+            final String advertiseURI, final Layout layout) {
+        return (FastFileManager) getManager(fileName, new FactoryData(append,
+                isFlush, advertiseURI, layout), FACTORY);
     }
 
     public Boolean isEndOfBatch() {
@@ -83,10 +87,17 @@ public class FastFileManager extends Out
     protected synchronized void write(byte[] bytes, int offset, int length) {
         super.write(bytes, offset, length); // writes to dummy output stream
 
-        if (length > buffer.remaining()) {
-            flush();
-        }
-        buffer.put(bytes, offset, length);
+        int chunk = 0;
+        do {
+            if (length > buffer.remaining()) {
+                flush();
+            }
+            chunk = Math.min(length, buffer.remaining());
+            buffer.put(bytes, offset, chunk);
+            offset += chunk;
+            length -= chunk;
+        } while (length > 0);
+
         if (isImmediateFlush || isEndOfBatch.get() == Boolean.TRUE) {
             flush();
         }
@@ -117,7 +128,7 @@ public class FastFileManager extends Out
 
     /**
      * Returns the name of the File being managed.
-     *
+     * 
      * @return The name of the File being managed.
      */
     public String getFileName() {
@@ -125,7 +136,7 @@ public class FastFileManager extends Out
     }
 
     /** {@code OutputStream} subclass that does not write anything. */
-    private static class DummyOutputStream extends OutputStream {
+    static class DummyOutputStream extends OutputStream {
         @Override
         public void write(int b) throws IOException {
         }
@@ -139,7 +150,7 @@ public class FastFileManager extends Out
      * FileManager's content format is specified by:
      * <p/>
      * Key: "fileURI" Value: provided "advertiseURI" param.
-     *
+     * 
      * @return Map of content format keys supporting FileManager
      */
     @Override
@@ -161,11 +172,11 @@ public class FastFileManager extends Out
 
         /**
          * Constructor.
-         *
+         * 
          * @param append Append status.
          */
-        public FactoryData(final boolean append, final boolean immediateFlush, final String
advertiseURI,
-                           final Layout layout) {
+        public FactoryData(final boolean append, final boolean immediateFlush,
+                final String advertiseURI, final Layout layout) {
             this.append = append;
             this.immediateFlush = immediateFlush;
             this.advertiseURI = advertiseURI;
@@ -176,11 +187,12 @@ public class FastFileManager extends Out
     /**
      * Factory to create a FastFileManager.
      */
-    private static class FastFileManagerFactory implements ManagerFactory<FastFileManager,
FactoryData> {
+    private static class FastFileManagerFactory implements
+            ManagerFactory<FastFileManager, FactoryData> {
 
         /**
          * Create a FastFileManager.
-         *
+         * 
          * @param name The name of the File.
          * @param data The FactoryData
          * @return The FastFileManager for the File.
@@ -200,7 +212,13 @@ public class FastFileManager extends Out
             RandomAccessFile raf;
             try {
                 raf = new RandomAccessFile(name, "rw");
-                return new FastFileManager(raf, name, os, data.immediateFlush, data.advertiseURI,
data.layout);
+                if (data.append) {
+                    raf.seek(raf.length());
+                } else {
+                    raf.setLength(0);
+                }
+                return new FastFileManager(raf, name, os, data.immediateFlush,
+                        data.advertiseURI, data.layout);
             } catch (Exception ex) {
                 LOGGER.error("FastFileManager (" + name + ") " + ex);
             }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManager.java?rev=1498044&r1=1498043&r2=1498044&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManager.java
(original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManager.java
Sun Jun 30 00:40:33 2013
@@ -17,7 +17,6 @@
 package org.apache.logging.log4j.core.appender.rolling;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.RandomAccessFile;
@@ -33,7 +32,7 @@ import org.apache.logging.log4j.core.app
  * I/O.
  */
 public class FastRollingFileManager extends RollingFileManager {
-    private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
+    static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
 
     private static final FastRollingFileManagerFactory FACTORY = new FastRollingFileManagerFactory();
 
@@ -75,10 +74,17 @@ public class FastRollingFileManager exte
     protected synchronized void write(byte[] bytes, int offset, int length) {
         super.write(bytes, offset, length); // writes to dummy output stream
 
-        if (length > buffer.remaining()) {
-            flush();
-        }
-        buffer.put(bytes, offset, length);
+        int chunk = 0;
+        do {
+            if (length > buffer.remaining()) {
+                flush();
+            }
+            chunk = Math.min(length, buffer.remaining());
+            buffer.put(bytes, offset, chunk);
+            offset += chunk;
+            length -= chunk;
+        } while (length > 0);
+
         if (isImmediateFlush || isEndOfBatch.get() == Boolean.TRUE) {
             flush();
         }
@@ -134,18 +140,24 @@ public class FastRollingFileManager exte
             if (null != parent && !parent.exists()) {
                 parent.mkdirs();
             }
+
             if (!data.append) {
                 file.delete();
             }
-            long size = data.append ? file.length() : 0;
-            long time = file.lastModified();
+            final long size = data.append ? file.length() : 0;
+            final long time = file.exists() ? file.lastModified() : System.currentTimeMillis();
 
             RandomAccessFile raf;
             try {
                 raf = new RandomAccessFile(name, "rw");
+                if (data.append) {
+                    raf.seek(raf.length());
+                } else {
+                    raf.setLength(0);
+                }
                 return new FastRollingFileManager(raf, name, data.pattern, new DummyOutputStream(),
data.append,
                         data.immediateFlush, size, time, data.policy, data.strategy, data.advertiseURI,
data.layout);
-            } catch (FileNotFoundException ex) {
+            } catch (IOException ex) {
                 LOGGER.error("FastRollingFileManager (" + name + ") " + ex);
             }
             return null;
@@ -153,7 +165,7 @@ public class FastRollingFileManager exte
     }
 
     /** {@code OutputStream} subclass that does not write anything. */
-    private static class DummyOutputStream extends OutputStream {
+    static class DummyOutputStream extends OutputStream {
         @Override
         public void write(int b) throws IOException {
         }

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java?rev=1498044&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java
(added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java
Sun Jun 30 00:40:33 2013
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import org.junit.Test;
+
+/**
+ * Tests the FastFileManager class.
+ */
+public class FastFileManagerTest {
+
+    /**
+     * Test method for
+     * {@link org.apache.logging.log4j.core.appender.FastFileManager#write(byte[], int, int)}
+     * .
+     */
+    @Test
+    public void testWrite_multiplesOfBufferSize() throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        OutputStream os = new FastFileManager.DummyOutputStream();
+        FastFileManager manager = new FastFileManager(raf, file.getName(), os,
+                false, null, null);
+
+        int size = FastFileManager.DEFAULT_BUFFER_SIZE * 3;
+        byte[] data = new byte[size];
+        manager.write(data); // no buffer overflow exception
+
+        // buffer is full but not flushed yet
+        assertEquals(FastFileManager.DEFAULT_BUFFER_SIZE * 2, raf.length());
+    }
+
+    /**
+     * Test method for
+     * {@link org.apache.logging.log4j.core.appender.FastFileManager#write(byte[], int, int)}
+     * .
+     */
+    @Test
+    public void testWrite_dataExceedingBufferSize() throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        OutputStream os = new FastFileManager.DummyOutputStream();
+        FastFileManager manager = new FastFileManager(raf, file.getName(), os,
+                false, null, null);
+
+        int size = FastFileManager.DEFAULT_BUFFER_SIZE * 3 + 1;
+        byte[] data = new byte[size];
+        manager.write(data); // no exception
+        assertEquals(FastFileManager.DEFAULT_BUFFER_SIZE * 3, raf.length());
+
+        manager.flush();
+        assertEquals(size, raf.length()); // all data written to file now
+    }
+
+    @Test
+    public void testAppendDoesNotOverwriteExistingFile() throws IOException {
+        boolean isAppend = true;
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        assertEquals(0, file.length());
+
+        byte[] bytes = new byte[4 * 1024];
+
+        // create existing file
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(file);
+            fos.write(bytes, 0, bytes.length);
+            fos.flush();
+        } finally {
+            fos.close();
+        }
+        assertEquals("all flushed to disk", bytes.length, file.length());
+
+        FastFileManager manager = FastFileManager.getFileManager(
+                file.getAbsolutePath(), isAppend, true, null, null);
+        manager.write(bytes, 0, bytes.length);
+        int expected = bytes.length * 2;
+        assertEquals("appended, not overwritten", expected, file.length());
+    }
+}

Propchange: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FastFileManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java?rev=1498044&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java
(added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java
Sun Jun 30 00:40:33 2013
@@ -0,0 +1,172 @@
+/*
+ * 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.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.util.concurrent.locks.LockSupport;
+
+import org.junit.Test;
+
+/**
+ * Tests the FastRollingFileManager class.
+ */
+public class FastRollingFileManagerTest {
+
+    /**
+     * Test method for
+     * {@link org.apache.logging.log4j.core.appender.rolling.FastRollingFileManager#write(byte[],
int, int)}
+     * .
+     */
+    @Test
+    public void testWrite_multiplesOfBufferSize() throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        OutputStream os = new FastRollingFileManager.DummyOutputStream();
+        boolean append = false;
+        boolean flushNow = false;
+        long triggerSize = Long.MAX_VALUE;
+        long time = System.currentTimeMillis();
+        TriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy(
+                triggerSize);
+        RolloverStrategy rolloverStrategy = null;
+        FastRollingFileManager manager = new FastRollingFileManager(raf,
+                file.getName(), "", os, append, flushNow, triggerSize, time,
+                triggerPolicy, rolloverStrategy, null, null);
+
+        int size = FastRollingFileManager.DEFAULT_BUFFER_SIZE * 3;
+        byte[] data = new byte[size];
+        manager.write(data, 0, data.length); // no buffer overflow exception
+
+        // buffer is full but not flushed yet
+        assertEquals(FastRollingFileManager.DEFAULT_BUFFER_SIZE * 2,
+                raf.length());
+    }
+
+    /**
+     * Test method for
+     * {@link org.apache.logging.log4j.core.appender.rolling.FastRollingFileManager#write(byte[],
int, int)}
+     * .
+     */
+    @Test
+    public void testWrite_dataExceedingBufferSize() throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        OutputStream os = new FastRollingFileManager.DummyOutputStream();
+        boolean append = false;
+        boolean flushNow = false;
+        long triggerSize = 0;
+        long time = System.currentTimeMillis();
+        TriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy(
+                triggerSize);
+        RolloverStrategy rolloverStrategy = null;
+        FastRollingFileManager manager = new FastRollingFileManager(raf,
+                file.getName(), "", os, append, flushNow, triggerSize, time,
+                triggerPolicy, rolloverStrategy, null, null);
+
+        int size = FastRollingFileManager.DEFAULT_BUFFER_SIZE * 3 + 1;
+        byte[] data = new byte[size];
+        manager.write(data, 0, data.length); // no exception
+        assertEquals(FastRollingFileManager.DEFAULT_BUFFER_SIZE * 3,
+                raf.length());
+
+        manager.flush();
+        assertEquals(size, raf.length()); // all data written to file now
+    }
+
+    @Test
+    public void testAppendDoesNotOverwriteExistingFile() throws IOException {
+        boolean isAppend = true;
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        assertEquals(0, file.length());
+
+        byte[] bytes = new byte[4 * 1024];
+
+        // create existing file
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(file);
+            fos.write(bytes, 0, bytes.length);
+            fos.flush();
+        } finally {
+            fos.close();
+        }
+        assertEquals("all flushed to disk", bytes.length, file.length());
+
+        FastRollingFileManager manager = FastRollingFileManager
+                .getFastRollingFileManager(
+                        //
+                        file.getAbsolutePath(), "", isAppend, true,
+                        new SizeBasedTriggeringPolicy(Long.MAX_VALUE), //
+                        null, null, null);
+        manager.write(bytes, 0, bytes.length);
+        int expected = bytes.length * 2;
+        assertEquals("appended, not overwritten", expected, file.length());
+    }
+
+    @Test
+    public void testFileTimeBasedOnSystemClockWhenAppendIsFalse()
+            throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        LockSupport.parkNanos(1000000); // 1 millisec
+
+        // append is false deletes the file if it exists
+        boolean isAppend = false;
+        long expectedMin = System.currentTimeMillis();
+        long expectedMax = expectedMin + 50;
+        assertTrue(file.lastModified() < expectedMin);
+        
+        FastRollingFileManager manager = FastRollingFileManager
+                .getFastRollingFileManager(
+                        //
+                        file.getAbsolutePath(), "", isAppend, true,
+                        new SizeBasedTriggeringPolicy(Long.MAX_VALUE), //
+                        null, null, null);
+        assertTrue(manager.getFileTime() < expectedMax);
+        assertTrue(manager.getFileTime() >= expectedMin);
+    }
+
+    @Test
+    public void testFileTimeBasedOnFileModifiedTimeWhenAppendIsTrue()
+            throws IOException {
+        File file = File.createTempFile("log4j2", "test");
+        file.deleteOnExit();
+        LockSupport.parkNanos(1000000); // 1 millisec
+
+        boolean isAppend = true;
+        assertTrue(file.lastModified() < System.currentTimeMillis());
+        
+        FastRollingFileManager manager = FastRollingFileManager
+                .getFastRollingFileManager(
+                        //
+                        file.getAbsolutePath(), "", isAppend, true,
+                        new SizeBasedTriggeringPolicy(Long.MAX_VALUE), //
+                        null, null, null);
+        assertEquals(file.lastModified(), manager.getFileTime());
+    }
+
+}

Propchange: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/rolling/FastRollingFileManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1498044&r1=1498043&r2=1498044&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sun Jun 30 00:40:33 2013
@@ -21,6 +21,18 @@
   </properties>
   <body>
     <release version="2.0-beta8" date="2013-??-??" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-295" dev="rpopma" type="fix">
+        Fast(Rolling)FileAppender now correctly handles messages exceeding the buffer size.
+      </action>
+      <action issue="LOG4J2-271" dev="rpopma" type="fix">
+        FastRollingFileAppender with TimeBasedTriggeringPolicy now works correctly if append=false.
+      </action>
+      <action issue="LOG4J2-267" dev="rpopma" type="fix">
+        FastRollingFileAppender with TimeBasedTriggeringPolicy now works correctly if append=false.
+      </action>
+      <action issue="LOG4J2-292" dev="rpopma" type="fix">
+        Fast(Rolling)FileAppender now correctly appends to (does not overwrite) existing
file.
+      </action>
       <action issue="LOG4J2-294" dev="rgoers" type="update">
         LogManager.getLogger can now be called without a logger name or with a null logger
name.
       </action>



Mime
View raw message