Author: carnold
Date: Sat Feb 13 18:24:46 2010
New Revision: 909868

URL: http://svn.apache.org/viewvc?rev=909868&view=rev
Log:
Bug 48704: Add purient mode to FileAppender

Added:
    
logging/log4j/trunk/src/main/java/org/apache/log4j/helpers/PrudentWriter.java
    logging/log4j/trunk/tests/witness/prudent
      - copied, changed from r909853, logging/log4j/trunk/tests/witness/simple
Modified:
    logging/log4j/trunk/src/changes/changes.xml
    logging/log4j/trunk/src/main/java/org/apache/log4j/FileAppender.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/FileAppenderTest.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/MinimumTestCase.java

Modified: logging/log4j/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/src/changes/changes.xml?rev=909868&r1=909867&r2=909868&view=diff
==============================================================================
--- logging/log4j/trunk/src/changes/changes.xml (original)
+++ logging/log4j/trunk/src/changes/changes.xml Sat Feb 13 18:24:46 2010
@@ -94,6 +94,7 @@
        <action action="add" issue="48187">Typo ("two three goals") in log4j 
FAQ</action>
        <action action="fix" issue="48531">Unit tests fail for system dates 
after 2009-12-31</action>
        <action action="fix" issue="48604">Download page does not have link to 
KEYS file</action>
+       <action action="add" issue="48704">Add purient mode to 
FileAppender.</action>
     </release>
 
   

Modified: logging/log4j/trunk/src/main/java/org/apache/log4j/FileAppender.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/src/main/java/org/apache/log4j/FileAppender.java?rev=909868&r1=909867&r2=909868&view=diff
==============================================================================
--- logging/log4j/trunk/src/main/java/org/apache/log4j/FileAppender.java 
(original)
+++ logging/log4j/trunk/src/main/java/org/apache/log4j/FileAppender.java Sat 
Feb 13 18:24:46 2010
@@ -65,6 +65,12 @@
    * Determines the size of IO buffer be. Default is 8K. 
    */
   protected int bufferSize = 8*1024;
+  
+  /**
+   * Determines whether "prudent" mode used.
+   * @since 1.2.16
+   */
+  private boolean prudent = false;
 
 
   /**
@@ -259,6 +265,44 @@
   void setBufferSize(int bufferSize) {
     this.bufferSize = bufferSize;
   }
+  
+  /**
+   * Determines if the FileAppender should attempt to use
+   * java.nio.FileChannel.lock to gain exclusive access
+   * to the file during write operations.  The effectiveness
+   * and performance impact is JVM and operating system dependent.
+   * Avoiding concurrent writes to the same file by appenders
+   * and streams either within or outside a single JVM 
+   * is recommended.
+   * 
+   * Prudent mode requires JDK 1.4 or later.
+   * 
+   * @return true if prudent mode is enabled.
+   * @since 1.2.16
+   */
+  public final boolean isPrudent() {
+         return prudent;
+  }
+  
+  /**
+   * Sets if the FileAppender should attempt to use
+   * java.nio.FileChannel.lock to gain exclusive access
+   * to the file during write operations.  The effectiveness
+   * and performance impact is JVM and operating system dependent.
+   * Avoiding concurrent writes to the same file by appenders
+   * and streams either within or outside a single JVM 
+   * is recommended.
+   * 
+   * Prudent mode requires JDK 1.4 or later.
+   * 
+   * @param valve true to enable prudent mode on next call to
+   * activateOptions or setFile.
+   *
+   * @since 1.2.16
+   */
+  public void setPrudent(final boolean value) {
+         prudent = value;
+  }
 
   /**
     <p>Sets and <i>opens</i> the file where the log output will
@@ -311,7 +355,9 @@
           }
     }
     Writer fw = createWriter(ostream);
-    if(bufferedIO) {
+    if (prudent) {
+      fw = new org.apache.log4j.helpers.PrudentWriter(fw, ostream);
+    } else if(bufferedIO) {
       fw = new BufferedWriter(fw, bufferSize);
     }
     this.setQWForFiles(fw);

Added: 
logging/log4j/trunk/src/main/java/org/apache/log4j/helpers/PrudentWriter.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/src/main/java/org/apache/log4j/helpers/PrudentWriter.java?rev=909868&view=auto
==============================================================================
--- 
logging/log4j/trunk/src/main/java/org/apache/log4j/helpers/PrudentWriter.java 
(added)
+++ 
logging/log4j/trunk/src/main/java/org/apache/log4j/helpers/PrudentWriter.java 
Sat Feb 13 18:24:46 2010
@@ -0,0 +1,74 @@
+/*
+ * 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.log4j.helpers;
+
+import java.io.FileOutputStream;
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+
+/**
+ * An implementation of the "prudent" mode where file locking and
+ * repositioning are used to minimize the consequences of 
+ * concurrent writes to a log file multiple appenders or
+ * programs.  The effectiveness is operating system and
+ * Java platform dependent.  Avoiding concurrent writing
+ * of log files is recommended.
+ * 
+ * @since 1.2.16
+ */
+public final class PrudentWriter extends FilterWriter {
+       /**
+        * File channel associated with encapsulated writer.
+        */
+       private final FileChannel channel;
+
+       /**
+        * Constructs a new instance.
+        * @param out writer to encapsulate, may not be null.
+        * @param ostream file stream corresponding to writer, may not be null.
+        */
+       public PrudentWriter(final Writer out, final FileOutputStream ostream) {
+               super(out);
+               channel = ostream.getChannel();
+       }
+       
+       /**
+        * Write string to encapsulated writer within a lock
+        * on the associated FileChannel.  Channel will be 
+        * repositioned to the end of the file if necessary. 
+        */
+       public void write(final String str) throws IOException {
+               FileLock lock = null;
+               try {
+                       lock = channel.lock();
+                       long size = channel.size();
+                       if (size != channel.position()) {
+                               channel.position(size);
+                       }
+                       super.write(str);
+                       super.flush();
+               } finally {
+                       if (lock != null) {
+                               lock.release();
+                       }
+               }
+       }
+       
+}

Modified: 
logging/log4j/trunk/tests/src/java/org/apache/log4j/FileAppenderTest.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/tests/src/java/org/apache/log4j/FileAppenderTest.java?rev=909868&r1=909867&r2=909868&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/FileAppenderTest.java 
(original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/FileAppenderTest.java 
Sat Feb 13 18:24:46 2010
@@ -84,4 +84,17 @@
     Priority debug = Level.DEBUG;
     assertTrue(appender.isAsSevereAsThreshold(debug));
   }
+  
+  /**
+   * Tests prudent mutator and accessor.
+   * See bug 48704.
+   */
+  public void testIsPrudent() {
+         FileAppender appender = new FileAppender();
+         assertFalse(appender.isPrudent());
+         appender.setPrudent(true);
+         assertTrue(appender.isPrudent());
+         appender.setPrudent(false);
+         assertFalse(appender.isPrudent());
+  }
 }

Modified: 
logging/log4j/trunk/tests/src/java/org/apache/log4j/MinimumTestCase.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/tests/src/java/org/apache/log4j/MinimumTestCase.java?rev=909868&r1=909867&r2=909868&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/MinimumTestCase.java 
(original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/MinimumTestCase.java 
Sat Feb 13 18:24:46 2010
@@ -79,6 +79,32 @@
     assertTrue(Compare.compare(FILTERED, "witness/simple"));
   }
 
+  public void prudent() throws Exception {
+           try {
+               java.io.FileOutputStream.class.getMethod("getChannel", 
(Class[]) null);
+           } catch(NoSuchMethodException ex) {
+               //  earlier than JDK 1.4
+               return;
+           }
+           Layout layout = new SimpleLayout();
+           FileAppender appender = new FileAppender();
+           
+           appender.setPrudent(true);
+           appender.setFile("output/prudent");
+           appender.setLayout(layout);
+           appender.activateOptions();
+           root.addAppender(appender);    
+           common();
+
+           Transformer.transform(
+             "output/prudent", FILTERED,
+             new Filter[] { new LineNumberFilter(), 
+                            new SunReflectFilter(), 
+                            new JunitTestRunnerFilter() });
+           assertTrue(Compare.compare(FILTERED, "witness/prudent"));
+         }
+  
+  
   public void ttcc() throws Exception {
     
     Layout layout = new 
TTCCLayout(AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT);
@@ -200,6 +226,7 @@
     TestSuite suite = new TestSuite();
     suite.addTest(new MinimumTestCase("simple"));
     suite.addTest(new MinimumTestCase("ttcc"));
+    suite.addTest(new MinimumTestCase("prudent"));
     return suite;
   }
 

Copied: logging/log4j/trunk/tests/witness/prudent (from r909853, 
logging/log4j/trunk/tests/witness/simple)
URL: 
http://svn.apache.org/viewvc/logging/log4j/trunk/tests/witness/prudent?p2=logging/log4j/trunk/tests/witness/prudent&p1=logging/log4j/trunk/tests/witness/simple&r1=909853&r2=909868&rev=909868&view=diff
==============================================================================
--- logging/log4j/trunk/tests/witness/simple (original)
+++ logging/log4j/trunk/tests/witness/prudent Sat Feb 13 18:24:46 2010
@@ -30,7 +30,7 @@
 DEBUG - Message 29
 java.lang.Exception: Just testing.
        at org.apache.log4j.MinimumTestCase.common(MinimumTestCase.java:XXX)
-       at org.apache.log4j.MinimumTestCase.simple(MinimumTestCase.java:XXX)
+       at org.apache.log4j.MinimumTestCase.prudent(MinimumTestCase.java:XXX)
        at junit.framework.TestCase.runTest(TestCase.java:XXX)
        at junit.framework.TestCase.runBare(TestCase.java:XXX)
        at junit.framework.TestResult$1.protect(TestResult.java:XXX)



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to