You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2013/06/30 02:40:33 UTC
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...
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>