[logback-dev] [GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v0.9.18-57-gfc91f41

added by portage for gitosis-gentoo git-noreply at pixie.qos.ch
Wed Mar 3 23:24:50 CET 2010


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".

The branch, master has been updated
       via  fc91f4117cfaacbd6deac9fb319a6abe07b45115 (commit)
      from  63475d86b35850ed5ed1ea735bf2bf38521ebbaf (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=fc91f4117cfaacbd6deac9fb319a6abe07b45115
http://github.com/ceki/logback/commit/fc91f4117cfaacbd6deac9fb319a6abe07b45115

commit fc91f4117cfaacbd6deac9fb319a6abe07b45115
Author: Ceki Gulcu <ceki at qos.ch>
Date:   Wed Mar 3 23:24:02 2010 +0100

    - more tests and improvements to ResilientFileOutputStream

diff --git a/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java b/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
index 46eae83..1dfbb39 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
@@ -162,7 +162,7 @@ public class FileAppender<E> extends OutputStreamAppender<E> {
 
       ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(
           file, append);
-
+      resilientFos.setContext(context);
       setOutputStream(resilientFos);
     }
   }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/TelnetAppender.java b/logback-core/src/main/java/ch/qos/logback/core/net/TelnetAppender.java
deleted file mode 100644
index a97e000..0000000
--- a/logback-core/src/main/java/ch/qos/logback/core/net/TelnetAppender.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- *   or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package ch.qos.logback.core.net;
-
-import ch.qos.logback.core.AppenderBase;
-
-public class TelnetAppender extends AppenderBase {
-
-  int port; 
-  
-  @Override
-  public void start() {
-    int errorCount = 0;
-    if (port == 0) {
-      errorCount++;
-      addError("No port was configured for appender"
-          + name
-          + " For more information, please visit http://logback.qos.ch/codes.html#socket_no_port");
-    }
-
-    //ServerSocket serverSocket = new ServerSocket(port);
-    
-//    connect(address, port);
-
-    if (errorCount == 0) {
-      this.started = true;
-    }
-  }
-
-  @Override
-  protected void append(Object eventObject) {
-    // TODO Auto-generated method stub
-
-  }
-  
-  
-
-}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java b/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java
index 59839c7..95ad0d2 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java
@@ -20,12 +20,21 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.channels.FileChannel;
 
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.status.ErrorStatus;
+import ch.qos.logback.core.status.InfoStatus;
+import ch.qos.logback.core.status.Status;
+import ch.qos.logback.core.status.StatusManager;
+
 public class ResilientFileOutputStream extends OutputStream {
 
-  RecoveryCoordinator recoveryCoordinator;
-  boolean bufferedIO;
-  int bufferSize;
+  final static int STATUS_COUNT_LIMIT = 2 * 4;
 
+  private int noContextWarning = 0;
+  private int statusCount = 0;
+
+  Context context;
+  RecoveryCoordinator recoveryCoordinator;
   FileOutputStream fos;
   File file;
   boolean presumedClean = true;
@@ -43,67 +52,128 @@ public class ResilientFileOutputStream extends OutputStream {
     return fos.getChannel();
   }
 
-  
   public File getFile() {
     return file;
   }
 
-  public void write(byte b[], int off, int len) throws IOException {
+  boolean isPresumedInError() {
     // existence of recoveryCoordinator indicates failed state
-    if (recoveryCoordinator != null && !presumedClean) {
+    return (recoveryCoordinator != null && !presumedClean);
+  }
+
+  public void write(byte b[], int off, int len) {
+    if (isPresumedInError()) {
       if (!recoveryCoordinator.isTooSoon()) {
-        performRecoveryAttempt();
+        attemptRecovery();
       }
-      // we return regardless of the success of the recovery attempt
-      return;
+      return; // return regardless of the success of the recovery attempt
     }
 
     try {
       fos.write(b, off, len);
       postSuccessfulWrite();
     } catch (IOException e) {
-      presumedClean = false;
-      recoveryCoordinator = new RecoveryCoordinator();
+      postIOFailure(e);
     }
   }
 
-  private void postSuccessfulWrite() {
-    recoveryCoordinator = null;
-  }
-
   @Override
-  public void close() throws IOException {
-    if (fos != null) {
-      fos.close();
-    }
-  }
-
-  @Override
-  public void write(int b) throws IOException {
-    // existence of recoveryCoordinator indicates failed state
-    if (recoveryCoordinator != null) {
+  public void write(int b) {
+    if (isPresumedInError()) {
       if (!recoveryCoordinator.isTooSoon()) {
-        performRecoveryAttempt();
+        attemptRecovery();
       }
-      // we return regardless of the success of the recovery attempt
-      return;
+      return; // return regardless of the success of the recovery attempt
     }
     try {
       fos.write(b);
       postSuccessfulWrite();
     } catch (IOException e) {
+      postIOFailure(e);
+    }
+  }
+
+  private void postSuccessfulWrite() {
+    if (recoveryCoordinator != null) {
+      recoveryCoordinator = null;
+      statusCount = 0;
+      addStatus(new InfoStatus("Recovered from IO failure on file [" + file
+          + "]", this));
+    }
+  }
+
+  void postIOFailure(IOException e) {
+    addStatusIfCountNotOverLimit(new ErrorStatus(
+        "IO failure while writing to [" + file + "]", this, e));
+    presumedClean = false; 
+    if (recoveryCoordinator == null) {
       recoveryCoordinator = new RecoveryCoordinator();
     }
   }
 
-  void performRecoveryAttempt() throws FileNotFoundException {
+  @Override
+  public void close() throws IOException {
+    if (fos != null) {
+      fos.close();
+    }
+  }
+
+  void attemptRecovery() {
     try {
       close();
     } catch (IOException e) {
     }
 
+    addStatusIfCountNotOverLimit(new InfoStatus(
+        "Attempting to recover from IO failure on file [" + file + "]", this));
+
     // subsequent writes must always be in append mode
-    fos = new FileOutputStream(file, true);
-    presumedClean = true;
+    try {
+      fos = new FileOutputStream(file, true);
+      presumedClean = true;
+    } catch (IOException e) {
+      addStatusIfCountNotOverLimit(new ErrorStatus("Failed to open file ["
+          + file + "]", this, e));
+    }
+  }
+
+  void addStatusIfCountNotOverLimit(Status s) {
+    ++statusCount;
+    if (statusCount < STATUS_COUNT_LIMIT) {
+      addStatus(s);
+    }
+
+    if (statusCount == STATUS_COUNT_LIMIT) {
+      addStatus(s);
+      addStatus(new InfoStatus("Will supress future messages regarding ["
+          + file + "]", this));
+    }
+  }
+
+  public void addStatus(Status status) {
+    if (context == null) {
+      if (noContextWarning++ == 0) {
+        System.out.println("LOGBACK: No context given for " + this);
+      }
+      return;
+    }
+    StatusManager sm = context.getStatusManager();
+    if (sm != null) {
+      sm.add(status);
+    }
+  }
+
+  public Context getContext() {
+    return context;
+  }
+
+  public void setContext(Context context) {
+    this.context = context;
+  }
+
+  @Override
+  public String toString() {
+    return "c.q.l.c.recovery.ResilientFileOutputStream@"
+        + System.identityHashCode(this);
   }
 }
diff --git a/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java b/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java
index e4216c2..5df81f3 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java
@@ -1,165 +1,100 @@
 package ch.qos.logback.core;
 
-import static org.junit.Assert.assertTrue;
-
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.nio.channels.FileChannel;
 
-import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
+import ch.qos.logback.core.contention.RunnableWithCounterAndDone;
 import ch.qos.logback.core.encoder.EchoEncoder;
-import ch.qos.logback.core.testUtil.Env;
+import ch.qos.logback.core.recovery.ResilientFileOutputStream;
+import ch.qos.logback.core.status.OnConsoleStatusListener;
 import ch.qos.logback.core.testUtil.RandomUtil;
-import ch.qos.logback.core.util.StatusPrinter;
+import ch.qos.logback.core.util.CoreTestConstants;
+import ch.qos.logback.core.util.ResilienceUtil;
 
 public class FileAppenderResilienceTest {
 
-  static String MOUNT_POINT = "/mnt/loop/";
-
-  static String LONG_STR = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-
-  static String PATH_LOOPFS_SCRIPT = "/home/ceki/java/logback/logback-core/src/test/loopfs.sh";
-
-  
-  enum LoopFSCommand {
-    setup, shake, teardown;
-  }
-
+  FileAppender<Object> fa = new FileAppender<Object>();
   Context context = new ContextBase();
   int diff = RandomUtil.getPositiveInt();
-  String outputDirStr = MOUNT_POINT + "resilience-" + diff + "/";
+  String outputDirStr = CoreTestConstants.OUTPUT_DIR_PREFIX + "resilience-"
+      + diff + "/";
+
+  //String outputDirStr = "\\\\192.168.1.3\\lbtest\\" + "resilience-"+ diff + "/";; 
   String logfileStr = outputDirStr + "output.log";
-  
-  FileAppender<Object> fa = new FileAppender<Object>();
 
-  static boolean isConformingHost() {
-    return Env.isLocalHostNameInList(new String[] {"gimmel"});
-  }
-  
   @Before
-  public void setUp() throws IOException, InterruptedException {
-    if(!isConformingHost()) {
-      return;
-    }
-    Process p = runLoopFSScript(LoopFSCommand.setup);
-    p.waitFor();
-
-    dump("/tmp/loopfs.log");
+  public void setUp() throws InterruptedException {
 
-    fa.setContext(context);
+    context.getStatusManager().add(new OnConsoleStatusListener());
+    
     File outputDir = new File(outputDirStr);
     outputDir.mkdirs();
-    System.out.println("FileAppenderResilienceTest output dir [" + outputDirStr
-        + "]");
 
+    fa.setContext(context);
     fa.setName("FILE");
     fa.setEncoder(new EchoEncoder<Object>());
     fa.setFile(logfileStr);
     fa.start();
-  }
 
-  void dump(String file) throws IOException {
-    FileInputStream fis = null;
-    try {
-      fis = new FileInputStream(file);
-      int r;
-      while ((r = fis.read()) != -1) {
-        char c = (char) r;
-        System.out.print(c);
-      }
-    } finally {
-      if (fis != null) {
-        fis.close();
-      }
-    }
   }
 
-  
-  @After
-  public void tearDown() throws IOException, InterruptedException {
-    if(!isConformingHost()) {
-      return;
+  @Test
+  @Ignore
+  public void manual() throws InterruptedException, IOException {
+    Runner runner = new Runner(fa);
+    Thread t = new Thread(runner);
+    t.start();
+
+    while (true) {
+      Thread.sleep(110);
     }
-    StatusPrinter.print(context);
-    fa.stop();
-    Process p = runLoopFSScript(LoopFSCommand.teardown);
-    p.waitFor();
-    System.out.println("Tearing down");
   }
 
-  static int TOTAL_DURATION = 5000;
-  static int NUM_STEPS = 500;
-  static int DELAY = TOTAL_DURATION / NUM_STEPS;
 
   @Test
-  public void go() throws IOException, InterruptedException {
-    if(!isConformingHost()) {
-      return;
-    }
-    Process p = runLoopFSScript(LoopFSCommand.shake);
-    for (int i = 0; i < NUM_STEPS; i++) {
-      fa.append(String.valueOf(i) + LONG_STR);
-      Thread.sleep(DELAY);
+  public void smoke() throws InterruptedException, IOException {
+    Runner runner = new Runner(fa);
+    Thread t = new Thread(runner);
+    t.start();
+
+    for (int i = 0; i < 10; i++) {
+      Thread.sleep(100);
+      ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) fa
+          .getOutputStream();
+      FileChannel fileChannel = resilientFOS.getChannel();
+      fileChannel.close();
     }
-    p.waitFor();
-    verify(logfileStr);
-    System.out.println("Done go");
+    runner.setDone(true);
+    t.join();
+
+    ResilienceUtil
+        .verify(logfileStr, "^hello (\\d{1,5})$", runner.getCounter());
   }
+}
 
-  // the loopfs script is tightly coupled with the host machine
-  // it needs to be Unix, with sudo privileges granted to the script
-  Process runLoopFSScript(LoopFSCommand cmd) throws IOException,
-      InterruptedException {
-    // causing a NullPointerException is better than locking the whole
-    // machine which the next operation can and will do.
-    if(!isConformingHost()) {
-      return null;
-    }
-    ProcessBuilder pb = new ProcessBuilder();
-    pb.command("/usr/bin/sudo", PATH_LOOPFS_SCRIPT, cmd.toString());
-    Process process = pb.start();
-    return process;
+class Runner extends RunnableWithCounterAndDone {
+  FileAppender<Object> fa;
+
+  Runner(FileAppender<Object> fa) {
+    this.fa = fa;
   }
 
-  void verify(String logfile) throws NumberFormatException, IOException {
-    FileReader fr = new FileReader(logfile);
-    BufferedReader br = new BufferedReader(fr);
-    String regExp = "^(\\d{1,3}) x*$";
-    Pattern p = Pattern.compile(regExp);
-    String line;
-    
-    int totalLines = 0;
-    int oldNum = -1;
-    int gaps = 0;
-    while ((line = br.readLine()) != null) {
-      Matcher m = p.matcher(line);
-      if (m.matches()) {
-        totalLines++;
-        String g = m.group(1);
-        int num = Integer.parseInt(g);
-        if(num != oldNum+1) {
-          gaps++;
+  public void run() {
+    while (!isDone()) {
+      counter++;
+      fa.doAppend("hello " + counter);
+      if (counter % 1024 == 0) {
+        try {
+          Thread.sleep(10);
+        } catch (InterruptedException e) {
         }
-        oldNum = num;
       }
     }
-    fr.close();
-    br.close();
-
-    // at least 40% of the logs should have been written
-    int lowerLimit = (int) (NUM_STEPS*0.4);
-    assertTrue("totalLines="+totalLines+" less than "+lowerLimit, totalLines > lowerLimit);
-    
-    // we want some gaps which indicate recuperation
-    assertTrue("gaps="+gaps+" less than 3", gaps > 3);
-    
   }
 
-}
+}
\ No newline at end of file
diff --git a/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java b/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilience_AS_ROOT_Test.java
similarity index 73%
copy from logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java
copy to logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilience_AS_ROOT_Test.java
index e4216c2..0ed804b 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilienceTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/FileAppenderResilience_AS_ROOT_Test.java
@@ -1,14 +1,21 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ * 
+ * This program and the accompanying materials are dual-licensed under either
+ * the terms of the Eclipse Public License v1.0 as published by the Eclipse
+ * Foundation
+ * 
+ * or (per the licensee's choosing)
+ * 
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ */
 package ch.qos.logback.core;
 
-import static org.junit.Assert.assertTrue;
-
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.junit.After;
 import org.junit.Before;
@@ -17,9 +24,10 @@ import org.junit.Test;
 import ch.qos.logback.core.encoder.EchoEncoder;
 import ch.qos.logback.core.testUtil.Env;
 import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.ResilienceUtil;
 import ch.qos.logback.core.util.StatusPrinter;
 
-public class FileAppenderResilienceTest {
+public class FileAppenderResilience_AS_ROOT_Test {
 
   static String MOUNT_POINT = "/mnt/loop/";
 
@@ -109,7 +117,7 @@ public class FileAppenderResilienceTest {
       Thread.sleep(DELAY);
     }
     p.waitFor();
-    verify(logfileStr);
+    ResilienceUtil.verify(logfileStr, "^(\\d{1,3}) x*$", NUM_STEPS);
     System.out.println("Done go");
   }
 
@@ -127,39 +135,4 @@ public class FileAppenderResilienceTest {
     Process process = pb.start();
     return process;
   }
-
-  void verify(String logfile) throws NumberFormatException, IOException {
-    FileReader fr = new FileReader(logfile);
-    BufferedReader br = new BufferedReader(fr);
-    String regExp = "^(\\d{1,3}) x*$";
-    Pattern p = Pattern.compile(regExp);
-    String line;
-    
-    int totalLines = 0;
-    int oldNum = -1;
-    int gaps = 0;
-    while ((line = br.readLine()) != null) {
-      Matcher m = p.matcher(line);
-      if (m.matches()) {
-        totalLines++;
-        String g = m.group(1);
-        int num = Integer.parseInt(g);
-        if(num != oldNum+1) {
-          gaps++;
-        }
-        oldNum = num;
-      }
-    }
-    fr.close();
-    br.close();
-
-    // at least 40% of the logs should have been written
-    int lowerLimit = (int) (NUM_STEPS*0.4);
-    assertTrue("totalLines="+totalLines+" less than "+lowerLimit, totalLines > lowerLimit);
-    
-    // we want some gaps which indicate recuperation
-    assertTrue("gaps="+gaps+" less than 3", gaps > 3);
-    
-  }
-
 }
diff --git a/logback-core/src/test/java/ch/qos/logback/core/WriterAppenderTest.java b/logback-core/src/test/java/ch/qos/logback/core/OutputStreamAppenderTest.java
similarity index 98%
rename from logback-core/src/test/java/ch/qos/logback/core/WriterAppenderTest.java
rename to logback-core/src/test/java/ch/qos/logback/core/OutputStreamAppenderTest.java
index e5988a7..0d475c8 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/WriterAppenderTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/OutputStreamAppenderTest.java
@@ -25,7 +25,7 @@ import org.junit.Test;
 import ch.qos.logback.core.html.LayoutWrappingEncoder;
 import ch.qos.logback.core.pattern.parser.SamplePatternLayout;
 
-public class WriterAppenderTest {
+public class OutputStreamAppenderTest {
 
   Context context = new ContextBase();
   
diff --git a/logback-core/src/test/java/ch/qos/logback/core/PackageTest.java b/logback-core/src/test/java/ch/qos/logback/core/PackageTest.java
index 190f370..e6e17a5 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/PackageTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/PackageTest.java
@@ -18,6 +18,6 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
- at SuiteClasses( { ContextBaseTest.class, WriterAppenderTest.class })
+ at SuiteClasses( { ContextBaseTest.class, OutputStreamAppenderTest.class, FileAppenderResilienceTest.class, FileAppenderResilience_AS_ROOT_Test.class })
 public class PackageTest {
 }
diff --git a/logback-core/src/test/java/ch/qos/logback/core/util/ResilienceUtil.java b/logback-core/src/test/java/ch/qos/logback/core/util/ResilienceUtil.java
new file mode 100644
index 0000000..2233fbc
--- /dev/null
+++ b/logback-core/src/test/java/ch/qos/logback/core/util/ResilienceUtil.java
@@ -0,0 +1,46 @@
+package ch.qos.logback.core.util;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ResilienceUtil {
+
+  
+  static public void verify(String logfile, String regexp, long totalSteps) throws NumberFormatException, IOException {
+    FileReader fr = new FileReader(logfile);
+    BufferedReader br = new BufferedReader(fr);
+    Pattern p = Pattern.compile(regexp);
+    String line;
+    
+    int totalLines = 0;
+    int oldNum = -1;
+    int gaps = 0;
+    while ((line = br.readLine()) != null) {
+      Matcher m = p.matcher(line);
+      if (m.matches()) {
+        totalLines++;
+        String g = m.group(1);
+        int num = Integer.parseInt(g);
+        if(num != oldNum+1) {
+          gaps++;
+        }
+        oldNum = num;
+      }
+    }
+    fr.close();
+    br.close();
+
+    // at least 40% of the logs should have been written
+    int lowerLimit = (int) (totalSteps*0.4);
+    assertTrue("totalLines="+totalLines+" less than "+lowerLimit, totalLines > lowerLimit);
+    
+    // we want some gaps which indicate recuperation
+    assertTrue("gaps="+gaps+" less than 3", gaps > 3);
+    
+  }
+}
diff --git a/logback-site/src/site/pages/news.html b/logback-site/src/site/pages/news.html
index 964c4dd..2b2c803 100644
--- a/logback-site/src/site/pages/news.html
+++ b/logback-site/src/site/pages/news.html
@@ -58,6 +58,16 @@
 
     </div>
 
+    <p><code>FileAppender</code> and derived classes can now
+    gracefully deal with IO failreus and recover quickly after the
+    original cause of the IO failure is corrected. For example, if the
+    log file is located on a <a
+    href="http://en.wikipedia.org/wiki/Network-attached_storage">network-attached
+    storage (NAS)</a>, and the connection to the NAS server is lost,
+    <code>FileAppender</code> and derived classes will recover quickly
+    after the connection to the server is re-established. 
+    </p>
+
     <p>Added <a
     href="manual/appenders.html#OnMarkerEvaluator">OnMarkerEvaluator</a>
     which evaluates to true in the presence of user-specified

-----------------------------------------------------------------------

Summary of changes:
 .../java/ch/qos/logback/core/FileAppender.java     |    2 +-
 .../ch/qos/logback/core/net/TelnetAppender.java    |   49 ------
 .../core/recovery/ResilientFileOutputStream.java   |  132 +++++++++++----
 .../logback/core/FileAppenderResilienceTest.java   |  177 ++++++-------------
 ...va => FileAppenderResilience_AS_ROOT_Test.java} |   59 ++-----
 ...nderTest.java => OutputStreamAppenderTest.java} |    2 +-
 .../test/java/ch/qos/logback/core/PackageTest.java |    2 +-
 .../ch/qos/logback/core/util/ResilienceUtil.java   |   46 +++++
 logback-site/src/site/pages/news.html              |   10 +
 9 files changed, 232 insertions(+), 247 deletions(-)
 delete mode 100644 logback-core/src/main/java/ch/qos/logback/core/net/TelnetAppender.java
 copy logback-core/src/test/java/ch/qos/logback/core/{FileAppenderResilienceTest.java => FileAppenderResilience_AS_ROOT_Test.java} (73%)
 rename logback-core/src/test/java/ch/qos/logback/core/{WriterAppenderTest.java => OutputStreamAppenderTest.java} (98%)
 create mode 100644 logback-core/src/test/java/ch/qos/logback/core/util/ResilienceUtil.java


hooks/post-receive
-- 
Logback: the generic, reliable, fast and flexible logging framework.


More information about the logback-dev mailing list