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

added by portage for gitosis-gentoo git-noreply at pixie.qos.ch
Tue Mar 16 18:55:24 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  36d3641c8af6d0174aec0bb4ce2d2ff446a85342 (commit)
      from  49e948fd49e0c62c325320b700c28db219be8314 (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=36d3641c8af6d0174aec0bb4ce2d2ff446a85342
http://github.com/ceki/logback/commit/36d3641c8af6d0174aec0bb4ce2d2ff446a85342

commit 36d3641c8af6d0174aec0bb4ce2d2ff446a85342
Author: Ceki Gulcu <ceki at qos.ch>
Date:   Tue Mar 16 18:54:26 2010 +0100

    - fixing LBCLASSIC-193

diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java
index 7c066da..67845db 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java
@@ -14,6 +14,7 @@
 package ch.qos.logback.classic.net;
 
 import java.io.IOException;
+import java.io.OutputStream;
 
 import ch.qos.logback.classic.PatternLayout;
 import ch.qos.logback.classic.pattern.SyslogStartConverter;
@@ -24,7 +25,6 @@ import ch.qos.logback.classic.util.LevelToSyslogSeverity;
 import ch.qos.logback.core.CoreConstants;
 import ch.qos.logback.core.Layout;
 import ch.qos.logback.core.net.SyslogAppenderBase;
-import ch.qos.logback.core.net.SyslogWriter;
 
 /**
  * This appender can be used to send messages to a remote syslog daemon. <p> For
@@ -75,7 +75,7 @@ public class SyslogAppender extends SyslogAppenderBase<ILoggingEvent> {
   }
 
   @Override
-  protected void postProcess(Object eventObject, SyslogWriter sw) {
+  protected void postProcess(Object eventObject, OutputStream sw) {
     ILoggingEvent event = (ILoggingEvent) eventObject;
 
     String prefix = prefixLayout.doLayout(event);
@@ -85,9 +85,9 @@ public class SyslogAppender extends SyslogAppenderBase<ILoggingEvent> {
       StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
       try {
         for (StackTraceElementProxy step : stepArray) {
-          sw.write(prefix);
-          sw.write(CoreConstants.TAB);
-          sw.write(step.toString());
+          StringBuilder sb = new StringBuilder();
+          sb.append(prefix).append(CoreConstants.TAB).append(step);
+          sw.write(sb.toString().getBytes());
           sw.flush();
         }
       } catch (IOException e) {
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java
index d2a0567..83056a6 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java
@@ -21,38 +21,45 @@ import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.LoggerFactory;
 
+import ch.qos.logback.classic.ClassicTestConstants;
 import ch.qos.logback.classic.Logger;
 import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.ClassicTestConstants;
 import ch.qos.logback.classic.joran.JoranConfigurator;
 import ch.qos.logback.classic.net.mock.MockSyslogServer;
 import ch.qos.logback.core.joran.spi.JoranException;
 import ch.qos.logback.core.net.SyslogConstants;
+import ch.qos.logback.core.recovery.RecoveryCoordinator;
 import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.StatusPrinter;
 
 public class SyslogAppenderTest {
 
+  LoggerContext lc = new LoggerContext();
+  SyslogAppender sa = new SyslogAppender();
+  MockSyslogServer mockServer;
+  String loggerName = this.getClass().getName();
+  Logger logger = lc.getLogger(loggerName);
+
   @Before
   public void setUp() throws Exception {
+    lc.setName("test");
+    sa.setContext(lc);
   }
 
   @After
   public void tearDown() throws Exception {
   }
 
-  @Test
-  public void basic() throws InterruptedException {
+  public void setMockServerAndConfigure(int expectedCount)
+      throws InterruptedException {
     int port = RandomUtil.getRandomServerPort();
 
-    MockSyslogServer mockServer = new MockSyslogServer(1, port);
+    mockServer = new MockSyslogServer(expectedCount, port);
     mockServer.start();
     // give MockSyslogServer head start
+
     Thread.sleep(100);
 
-    LoggerContext lc = new LoggerContext();
-    lc.setName("test");
-    SyslogAppender sa = new SyslogAppender();
-    sa.setContext(lc);
     sa.setSyslogHost("localhost");
     sa.setFacility("MAIL");
     sa.setPort(port);
@@ -63,12 +70,20 @@ public class SyslogAppenderTest {
     String loggerName = this.getClass().getName();
     Logger logger = lc.getLogger(loggerName);
     logger.addAppender(sa);
+
+  }
+
+  @Test
+  public void basic() throws InterruptedException {
+
+    setMockServerAndConfigure(1);
     String logMsg = "hello";
     logger.debug(logMsg);
 
     // wait max 2 seconds for mock server to finish. However, it should
     // much sooner than that.
     mockServer.join(8000);
+
     assertTrue(mockServer.isFinished());
     assertEquals(1, mockServer.getMessageList().size());
     String msg = mockServer.getMessageList().get(0);
@@ -80,39 +95,20 @@ public class SyslogAppenderTest {
     assertTrue(msg.startsWith(expected));
 
     String first = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} [\\w.-]* ";
-    checkRegexMatch(msg, first + "\\[" + threadName + "\\] " + loggerName
-        + " " + logMsg);
+    checkRegexMatch(msg, first + "\\[" + threadName + "\\] " + loggerName + " "
+        + logMsg);
 
   }
 
   @Test
   public void tException() throws InterruptedException {
-    int port = RandomUtil.getRandomServerPort();
-
-    MockSyslogServer mockServer = new MockSyslogServer(21, port);
-    mockServer.start();
-    // give MockSyslogServer head start
-    Thread.sleep(100);
-
-    LoggerContext lc = new LoggerContext();
-    lc.setName("test");
-    SyslogAppender sa = new SyslogAppender();
-    sa.setContext(lc);
-    sa.setSyslogHost("localhost");
-    sa.setFacility("MAIL");
-    sa.setPort(port);
-    sa.setSuffixPattern("[%thread] %logger %msg");
-    sa.start();
-    assertTrue(sa.isStarted());
+    setMockServerAndConfigure(21);
 
-    String loggerName = this.getClass().getName();
-    Logger logger = lc.getLogger(loggerName);
-    logger.addAppender(sa);
     String logMsg = "hello";
     String exMsg = "just testing";
     Exception ex = new Exception(exMsg);
     logger.debug(logMsg, ex);
-    // StatusPrinter.print(lc.getStatusManager());
+    StatusPrinter.print(lc);
 
     // wait max 2 seconds for mock server to finish. However, it should
     // much sooner than that.
@@ -133,13 +129,44 @@ public class SyslogAppenderTest {
 
     String expectedPrefix = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} [\\w.-]* ";
     String threadName = Thread.currentThread().getName();
-    String regex = expectedPrefix + "\\[" + threadName + "\\] "
-        + loggerName + " " + logMsg;
+    String regex = expectedPrefix + "\\[" + threadName + "\\] " + loggerName
+        + " " + logMsg;
     checkRegexMatch(msg, regex);
   }
-  
+
   private void checkRegexMatch(String s, String regex) {
-    assertTrue("The string ["+s+"] did not match regex ["+regex+"]", s.matches(regex));
+    assertTrue("The string [" + s + "] did not match regex [" + regex + "]", s
+        .matches(regex));
+  }
+
+  @Test
+  public void large() throws InterruptedException {
+    setMockServerAndConfigure(1);
+    StringBuilder largeBuf = new StringBuilder();
+    for (int i = 0; i < 2 * 1024 * 1024; i++) {
+      largeBuf.append('a');
+    }
+    logger.debug(largeBuf.toString());
+
+    String logMsg = "hello";
+    logger.debug(logMsg);
+    Thread.sleep(RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN+10);
+    logger.debug(logMsg);
+    
+    mockServer.join(8000);
+    assertTrue(mockServer.isFinished());
+    
+    // the first message is wasted
+    assertEquals(1, mockServer.getMessageList().size());
+    String msg = mockServer.getMessageList().get(0);
+    String expected = "<"
+        + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
+    assertTrue(msg.startsWith(expected));
+    String expectedPrefix = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} [\\w.-]* ";
+    String threadName = Thread.currentThread().getName();
+    String regex = expectedPrefix + "\\[" + threadName + "\\] " + loggerName
+        + " " + logMsg;
+    checkRegexMatch(msg, regex);
   }
 
   @Test
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java b/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java
index 9bea188..b85344b 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/net/mock/MockSyslogServer.java
@@ -48,7 +48,6 @@ public class MockSyslogServer extends Thread {
         DatagramPacket packet = new DatagramPacket(buf, buf.length);
         //System.out.println("Waiting for message");
         socket.receive(packet);
-        //System.out.println("Got message");
         String msg = new String(buf, 0, packet.getLength());
         msgList.add(msg);
       }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java b/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java
index 551de9e..d0cf074 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java
@@ -14,6 +14,7 @@
 package ch.qos.logback.core.net;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 
@@ -25,19 +26,20 @@ import ch.qos.logback.core.Layout;
  * Base class for SyslogAppender.
  * 
  * @author Ceki G&uumllc&uuml;
- *
+ * 
  * @param <E>
  */
 public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
 
-  final static String SYSLOG_LAYOUT_URL = CoreConstants.CODES_URL + "#syslog_layout";
-  final static int MSG_SIZE_LIMIT = 256*1024;
-  
+  final static String SYSLOG_LAYOUT_URL = CoreConstants.CODES_URL
+      + "#syslog_layout";
+  final static int MSG_SIZE_LIMIT = 256 * 1024;
+
   Layout<E> layout;
   String facilityStr;
   String syslogHost;
   protected String suffixPattern;
-  SyslogWriter sw;
+  SyslogOutputStream sos;
   int port = SyslogConstants.SYSLOG_PORT;
 
   public void start() {
@@ -48,13 +50,14 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
     }
 
     try {
-      sw = new SyslogWriter(syslogHost, port);
+      sos = new SyslogOutputStream(syslogHost, port);
     } catch (UnknownHostException e) {
       addError("Could not create SyslogWriter", e);
       errorCount++;
     } catch (SocketException e) {
-      errorCount++;
-      addError("Failed to bind to a random datagram socket ", e);
+      addWarn(
+          "Failed to bind to a random datagram socket. Will try to reconnect later.",
+          e);
     }
 
     if (layout == null) {
@@ -65,7 +68,7 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
       super.start();
     }
   }
-  
+
   abstract public Layout<E> buildLayout(String facilityStr);
 
   abstract public int getSeverityForEvent(Object eventObject);
@@ -78,20 +81,19 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
 
     try {
       String msg = layout.doLayout(eventObject);
-      if(msg != null && msg.length() > MSG_SIZE_LIMIT) {
+      if (msg != null && msg.length() > MSG_SIZE_LIMIT) {
         msg = msg.substring(0, MSG_SIZE_LIMIT);
       }
-      sw.write(msg);
-      sw.flush();
-      postProcess(eventObject, sw);
+      sos.write(msg.getBytes());
+      sos.flush();
+      postProcess(eventObject, sos);
     } catch (IOException ioe) {
       addError("Failed to send diagram to " + syslogHost, ioe);
-      stop();
     }
   }
-  
-  protected void postProcess(Object event, SyslogWriter sw) {
-    
+
+  protected void postProcess(Object event, OutputStream sw) {
+
   }
 
   /**
@@ -174,10 +176,10 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
   }
 
   /**
-   * The <b>Facility</b> option must be set one of the strings KERN, USER,
-   * MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP,
-   * AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5,
-   * LOCAL6, LOCAL7. Case is not important.
+   * The <b>Facility</b> option must be set one of the strings KERN, USER, MAIL,
+   * DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT,
+   * ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6,
+   * LOCAL7. Case is not important.
    * 
    * <p>
    * See {@link SyslogConstants} and RFC 3164 for more information about the
@@ -206,22 +208,22 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
     this.port = port;
   }
 
-
   public Layout<E> getLayout() {
     return layout;
   }
 
   public void setLayout(Layout<E> layout) {
-    addWarn("The layout of a SyslogAppender cannot be set directly. See also "+SYSLOG_LAYOUT_URL);
+    addWarn("The layout of a SyslogAppender cannot be set directly. See also "
+        + SYSLOG_LAYOUT_URL);
   }
 
   @Override
   public void stop() {
-    sw.close();
+    sos.close();
     super.stop();
   }
 
-  /**
+/**
    * See {@link #setSuffixPattern(String).
    * 
    * @return
diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java b/logback-core/src/main/java/ch/qos/logback/core/net/SyslogOutputStream.java
similarity index 61%
rename from logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java
rename to logback-core/src/main/java/ch/qos/logback/core/net/SyslogOutputStream.java
index bedecd3..1e20aeb 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/net/SyslogOutputStream.java
@@ -13,8 +13,9 @@
  */
 package ch.qos.logback.core.net;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.Writer;
+import java.io.OutputStream;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
@@ -22,10 +23,10 @@ import java.net.SocketException;
 import java.net.UnknownHostException;
 
 /**
- * SyslogWriter is a wrapper around the {@link DatagramSocket} class so that it
- * behaves like a {@link Writer}.
+ * SyslogOutputStream is a wrapper around the {@link DatagramSocket} class so that it
+ * behaves like an {@link OutputStream}.
  */
-public class SyslogWriter extends Writer {
+public class SyslogOutputStream extends OutputStream {
 
   /**
    * The maximum length after which we discard the existing string buffer and
@@ -35,39 +36,41 @@ public class SyslogWriter extends Writer {
 
   private InetAddress address;
   private DatagramSocket ds;
-  private StringBuffer buf = new StringBuffer();
+  private ByteArrayOutputStream baos = new ByteArrayOutputStream();
   final private int port;
 
-  public SyslogWriter(String syslogHost, int port) throws UnknownHostException,
+  public SyslogOutputStream(String syslogHost, int port) throws UnknownHostException,
       SocketException {
     this.address = InetAddress.getByName(syslogHost);
     this.port = port;
     this.ds = new DatagramSocket();
   }
 
-  public void write(char[] charArray, int offset, int len) throws IOException {
-    buf.append(charArray, offset, len);
-  }
-
-  public void write(String str) throws IOException {
-    buf.append(str);
-
+  public void write(byte[] byteArray, int offset, int len) throws IOException {
+    baos.write(byteArray, offset, len);
   }
 
   public void flush() throws IOException {
-    byte[] bytes = buf.toString().getBytes();
+    byte[] bytes = baos.toByteArray();
     DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address,
         port);
 
-    if (this.ds != null) {
-      ds.send(packet);
-    }
     // clean up for next round
-    if (buf.length() > MAX_LEN) {
-      buf = new StringBuffer();
+    if (baos.size() > MAX_LEN) {
+      baos = new ByteArrayOutputStream();
     } else {
-      buf.setLength(0);
+      baos.reset();
     }
+    
+    // after a failure, it can happen that bytes.length is zero
+    // in that case, there is no point in sending out an empty message/
+    if(bytes.length == 0) {
+      return;
+    }
+    if (this.ds != null) {
+      ds.send(packet);
+    }
+  
   }
 
   public void close() {
@@ -79,4 +82,9 @@ public class SyslogWriter extends Writer {
     return port;
   }
 
+  @Override
+  public void write(int b) throws IOException {
+    baos.write(b);
+  }
+
 }
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 cbe3b90..27331e2 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,35 +20,22 @@ 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 ResilientOutputStreamBase {
 
-public class ResilientFileOutputStream extends OutputStream {
-
-  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;
 
   public ResilientFileOutputStream(File file, boolean append)
       throws FileNotFoundException {
     this.file = file;
-    fos = new FileOutputStream(file, append);
+    this.os = new FileOutputStream(file, append);
+    this.presumedClean = true;
   }
 
   public FileChannel getChannel() {
-    if (fos == null) {
+    if (os == null) {
       return null;
     }
+    final FileOutputStream fos = (FileOutputStream) os;
     return fos.getChannel();
   }
 
@@ -56,124 +43,21 @@ public class ResilientFileOutputStream extends OutputStream {
     return file;
   }
 
-  final private boolean isPresumedInError() {
-    // existence of recoveryCoordinator indicates failed state
-    return (recoveryCoordinator != null && !presumedClean);
-  }
-
-  public void write(byte b[], int off, int len) {
-    if (isPresumedInError()) {
-      if (!recoveryCoordinator.isTooSoon()) {
-        attemptRecovery();
-      }
-      return; // return regardless of the success of the recovery attempt
-    }
-
-    try {
-      fos.write(b, off, len);
-      postSuccessfulWrite();
-    } catch (IOException e) {
-      postIOFailure(e);
-    }
-  }
 
   @Override
-  public void write(int b) {
-    if (isPresumedInError()) {
-      if (!recoveryCoordinator.isTooSoon()) {
-        attemptRecovery();
-      }
-      return; // return regardless of the success of the recovery attempt
-    }
-    try {
-      fos.write(b);
-      postSuccessfulWrite();
-    } catch (IOException e) {
-      postIOFailure(e);
-    }
-  }
-
-  final 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();
-    }
+  String getDescription() {
+    return "file ["+file+"]";
   }
 
   @Override
-  public void close() throws IOException {
-    if (fos != null) {
-      fos.close();
-    }
+  OutputStream openNewOutputStream() throws IOException {
+    return  new FileOutputStream(file, true);
   }
-
-  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
-    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/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java b/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientOutputStreamBase.java
similarity index 70%
copy from logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientFileOutputStream.java
copy to logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientOutputStreamBase.java
index cbe3b90..8cb9b6d 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/ResilientOutputStreamBase.java
@@ -13,12 +13,8 @@
  */
 package ch.qos.logback.core.recovery;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 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;
@@ -26,35 +22,18 @@ 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 {
+abstract public class ResilientOutputStreamBase extends OutputStream {
 
   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;
+  private Context context;
+  private RecoveryCoordinator recoveryCoordinator;
 
-  public ResilientFileOutputStream(File file, boolean append)
-      throws FileNotFoundException {
-    this.file = file;
-    fos = new FileOutputStream(file, append);
-  }
-
-  public FileChannel getChannel() {
-    if (fos == null) {
-      return null;
-    }
-    return fos.getChannel();
-  }
-
-  public File getFile() {
-    return file;
-  }
+  protected OutputStream os;
+  protected boolean presumedClean = true;
 
   final private boolean isPresumedInError() {
     // existence of recoveryCoordinator indicates failed state
@@ -70,7 +49,7 @@ public class ResilientFileOutputStream extends OutputStream {
     }
 
     try {
-      fos.write(b, off, len);
+      os.write(b, off, len);
       postSuccessfulWrite();
     } catch (IOException e) {
       postIOFailure(e);
@@ -86,26 +65,42 @@ public class ResilientFileOutputStream extends OutputStream {
       return; // return regardless of the success of the recovery attempt
     }
     try {
-      fos.write(b);
+      os.write(b);
       postSuccessfulWrite();
     } catch (IOException e) {
       postIOFailure(e);
     }
   }
 
+  @Override
+  public void flush() {
+    if (os != null) {
+      try {
+        os.flush();
+        postSuccessfulWrite();
+      } catch (IOException e) {
+        postIOFailure(e);
+      }
+    }
+  }
+
+  abstract String getDescription();
+
+  abstract OutputStream openNewOutputStream() throws IOException;
+
   final private void postSuccessfulWrite() {
     if (recoveryCoordinator != null) {
       recoveryCoordinator = null;
       statusCount = 0;
-      addStatus(new InfoStatus("Recovered from IO failure on file [" + file
-          + "]", this));
+      addStatus(new InfoStatus("Recovered from IO failure on "
+          + getDescription(), this));
     }
   }
 
   void postIOFailure(IOException e) {
-    addStatusIfCountNotOverLimit(new ErrorStatus(
-        "IO failure while writing to [" + file + "]", this, e));
-    presumedClean = false; 
+    addStatusIfCountNotOverLimit(new ErrorStatus("IO failure while writing to "
+        + getDescription(), this, e));
+    presumedClean = false;
     if (recoveryCoordinator == null) {
       recoveryCoordinator = new RecoveryCoordinator();
     }
@@ -113,8 +108,8 @@ public class ResilientFileOutputStream extends OutputStream {
 
   @Override
   public void close() throws IOException {
-    if (fos != null) {
-      fos.close();
+    if (os != null) {
+      os.close();
     }
   }
 
@@ -125,15 +120,15 @@ public class ResilientFileOutputStream extends OutputStream {
     }
 
     addStatusIfCountNotOverLimit(new InfoStatus(
-        "Attempting to recover from IO failure on file [" + file + "]", this));
+        "Attempting to recover from IO failure on " + getDescription(), this));
 
     // subsequent writes must always be in append mode
     try {
-      fos = new FileOutputStream(file, true);
+      os = openNewOutputStream();
       presumedClean = true;
     } catch (IOException e) {
-      addStatusIfCountNotOverLimit(new ErrorStatus("Failed to open file ["
-          + file + "]", this, e));
+      addStatusIfCountNotOverLimit(new ErrorStatus("Failed to open "
+          + getDescription(), this, e));
     }
   }
 
@@ -145,8 +140,8 @@ public class ResilientFileOutputStream extends OutputStream {
 
     if (statusCount == STATUS_COUNT_LIMIT) {
       addStatus(s);
-      addStatus(new InfoStatus("Will supress future messages regarding ["
-          + file + "]", this));
+      addStatus(new InfoStatus("Will supress future messages regarding "
+          + getDescription(), this));
     }
   }
 
@@ -170,10 +165,4 @@ public class ResilientFileOutputStream extends OutputStream {
   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/main/java/ch/qos/logback/core/recovery/ResilientSyslogOutputStream.java b/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientSyslogOutputStream.java
new file mode 100644
index 0000000..d3c3822
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientSyslogOutputStream.java
@@ -0,0 +1,53 @@
+/**
+ * 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.recovery;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import ch.qos.logback.core.net.SyslogOutputStream;
+
+public class ResilientSyslogOutputStream extends ResilientOutputStreamBase {
+
+
+  String syslogHost;
+  int port;
+  
+  public ResilientSyslogOutputStream(String syslogHost, int port)
+      throws UnknownHostException, SocketException {
+    this.syslogHost = syslogHost;
+    this.port = port;
+    super.os = new SyslogOutputStream(syslogHost, port);
+    this.presumedClean = true;
+  }
+
+  @Override
+  String getDescription() {
+    return "syslog ["+syslogHost+":"+port+"]";
+  }
+
+  @Override
+  OutputStream openNewOutputStream() throws IOException {
+    return  new SyslogOutputStream(syslogHost, port);
+  }
+  
+  @Override
+  public String toString() {
+    return "c.q.l.c.recovery.ResilientSyslogOutputStream@"
+        + System.identityHashCode(this);
+  }
+
+}

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

Summary of changes:
 .../ch/qos/logback/classic/net/SyslogAppender.java |   10 +-
 .../logback/classic/net/SyslogAppenderTest.java    |   97 +++++++++-----
 .../logback/classic/net/mock/MockSyslogServer.java |    1 -
 .../qos/logback/core/net/SyslogAppenderBase.java   |   52 ++++----
 .../{SyslogWriter.java => SyslogOutputStream.java} |   48 ++++---
 .../core/recovery/ResilientFileOutputStream.java   |  138 ++------------------
 ...tStream.java => ResilientOutputStreamBase.java} |   83 +++++-------
 .../core/recovery/ResilientSyslogOutputStream.java |   53 ++++++++
 8 files changed, 222 insertions(+), 260 deletions(-)
 rename logback-core/src/main/java/ch/qos/logback/core/net/{SyslogWriter.java => SyslogOutputStream.java} (61%)
 copy logback-core/src/main/java/ch/qos/logback/core/recovery/{ResilientFileOutputStream.java => ResilientOutputStreamBase.java} (70%)
 create mode 100644 logback-core/src/main/java/ch/qos/logback/core/recovery/ResilientSyslogOutputStream.java


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


More information about the logback-dev mailing list