You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2013/01/01 20:27:48 UTC
svn commit: r1427540 - in /logging/log4j/log4j2/trunk:
core/src/main/java/org/apache/logging/log4j/core/appender/
core/src/main/java/org/apache/logging/log4j/core/helpers/
core/src/main/java/org/apache/logging/log4j/core/net/
core/src/main/java/org/apa...
Author: rgoers
Date: Tue Jan 1 19:27:47 2013
New Revision: 1427540
URL: http://svn.apache.org/viewvc?rev=1427540&view=rev
Log:
Have FailoverAppender retry after user specified interval. JMS appenders now retry after connection failure at initialization.
Added:
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java
- copied, changed from r1426987, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java
Modified:
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/helpers/Constants.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FailoverAppenderTest.java
logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml
logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java Tue Jan 1 19:27:47 2013
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.core.con
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.Constants;
import java.util.ArrayList;
import java.util.List;
@@ -50,12 +51,21 @@ public final class FailoverAppender exte
private final List<AppenderControl> failoverAppenders = new ArrayList<AppenderControl>();
+ private final long interval;
+
+ private long nextCheck = 0;
+
+ private volatile boolean failure = false;
+
+ private static final int DEFAULT_INTERVAL = 60 * Constants.MILLIS_IN_SECONDS;
+
private FailoverAppender(final String name, final Filter filter, final String primary, final String[] failovers,
- final Configuration config, final boolean handleExceptions) {
+ final int interval, final Configuration config, final boolean handleExceptions) {
super(name, filter, null, handleExceptions);
this.primaryRef = primary;
this.failovers = failovers;
this.config = config;
+ this.interval = interval;
}
@@ -95,22 +105,48 @@ public final class FailoverAppender exte
error("FailoverAppender " + getName() + " did not start successfully");
return;
}
+ if (!failure) {
+ callAppender(event);
+ } else {
+ long current = System.currentTimeMillis();
+ if (current >= nextCheck) {
+ callAppender(event);
+ } else {
+ failover(event, null);
+ }
+ }
+ }
+
+ private void callAppender(final LogEvent event) {
try {
primary.callAppender(event);
} catch (final Exception ex) {
- re = new LoggingException(ex);
- boolean written = false;
- for (final AppenderControl control : failoverAppenders) {
- try {
- control.callAppender(event);
- written = true;
- break;
- } catch (final Exception fex) {
- continue;
+ nextCheck = System.currentTimeMillis() + interval;
+ failure = true;
+ failover(event, ex);
+ }
+ }
+
+ private void failover(final LogEvent event, Exception ex) {
+ RuntimeException re = ex != null ? new LoggingException(ex) : null;
+ boolean written = false;
+ Exception failoverException = null;
+ for (final AppenderControl control : failoverAppenders) {
+ try {
+ control.callAppender(event);
+ written = true;
+ break;
+ } catch (final Exception fex) {
+ if (failoverException == null) {
+ failoverException = fex;
}
}
- if (!written && !isExceptionSuppressed()) {
+ }
+ if (!written && !isExceptionSuppressed()) {
+ if (re != null) {
throw re;
+ } else {
+ throw new LoggingException("Unable to write to failover appenders", failoverException);
}
}
}
@@ -136,6 +172,7 @@ public final class FailoverAppender exte
* @param name The name of the Appender (required).
* @param primary The name of the primary Appender (required).
* @param failovers The name of one or more Appenders to fail over to (at least one is required).
+ * @param interval The retry interval.
* @param config The current Configuration (passed by the Configuration when the appender is created).
* @param filter A Filter (optional).
* @param suppress "true" if exceptions should be hidden from the application, "false" otherwise.
@@ -146,6 +183,7 @@ public final class FailoverAppender exte
public static FailoverAppender createAppender(@PluginAttr("name") final String name,
@PluginAttr("primary") final String primary,
@PluginElement("failovers") final String[] failovers,
+ @PluginAttr("retryInterval") final String interval,
@PluginConfiguration final Configuration config,
@PluginElement("filters") final Filter filter,
@PluginAttr("suppressExceptions") final String suppress) {
@@ -162,8 +200,26 @@ public final class FailoverAppender exte
return null;
}
+ int retryInterval;
+ if (interval == null) {
+ retryInterval = DEFAULT_INTERVAL;
+ } else {
+ try {
+ int value = Integer.parseInt(interval);
+ if (value >= 0) {
+ retryInterval = value * Constants.MILLIS_IN_SECONDS;
+ } else {
+ LOGGER.warn("Interval " + interval + " is less than zero. Using default");
+ retryInterval = DEFAULT_INTERVAL;
+ }
+ } catch (NumberFormatException nfe) {
+ LOGGER.error("Interval " + interval + " is non-numeric. Using default");
+ retryInterval = DEFAULT_INTERVAL;
+ }
+ }
+
final boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress);
- return new FailoverAppender(name, filter, primary, failovers, config, handleExceptions);
+ return new FailoverAppender(name, filter, primary, failovers, retryInterval, config, handleExceptions);
}
}
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/helpers/Constants.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/helpers/Constants.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/helpers/Constants.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/helpers/Constants.java Tue Jan 1 19:27:47 2013
@@ -37,6 +37,11 @@ public final class Constants {
public static final String LINE_SEP = PropertiesUtil.getSystemProperty("line.separator", "\n");
/**
+ * Number of milliseconds in a second.
+ */
+ public static final int MILLIS_IN_SECONDS = 1000;
+
+ /**
* Prevent class instantiation.
*/
private Constants() {
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSQueueManager.java Tue Jan 1 19:27:47 2013
@@ -102,21 +102,37 @@ public class JMSQueueManager extends Abs
if (info == null) {
info = connect(context, factoryBindingName, queueBindingName, userName, password, false);
}
- super.send(object, info.session, info.sender);
+ try {
+ super.send(object, info.session, info.sender);
+ } catch (Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
}
@Override
public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(boolean quiet) {
try {
- if (info != null) {
- info.session.close();
- info.conn.close();
+ info.session.close();
+ } catch (Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
}
- } catch (final JMSException ex) {
- LOGGER.error("Error closing " + getName(), ex);
- } finally {
- info = null;
}
+ info = null;
}
/**
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/JMSTopicManager.java Tue Jan 1 19:27:47 2013
@@ -103,18 +103,37 @@ public class JMSTopicManager extends Abs
info = connect(context, factoryBindingName, topicBindingName, userName, password, false);
}
super.send(object, info.session, info.publisher);
+ try {
+ super.send(object, info.session, info.publisher);
+ } catch (Exception ex) {
+ cleanup(true);
+ throw ex;
+ }
}
@Override
public void releaseSub() {
+ if (info != null) {
+ cleanup(false);
+ }
+ }
+
+ private void cleanup(boolean quiet) {
try {
- if (info != null) {
- info.session.close();
- info.conn.close();
+ info.session.close();
+ } catch (Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing session for " + getName(), e);
+ }
+ }
+ try {
+ info.conn.close();
+ } catch (Exception e) {
+ if (!quiet) {
+ LOGGER.error("Error closing connection for " + getName(), e);
}
- } catch (final JMSException ex) {
- LOGGER.error("Error closing " + getName(), ex);
}
+ info = null;
}
/**
Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/CachedDateFormat.java Tue Jan 1 19:27:47 2013
@@ -16,6 +16,8 @@
*/
package org.apache.logging.log4j.core.pattern;
+import org.apache.logging.log4j.core.helpers.Constants;
+
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
@@ -82,8 +84,6 @@ final class CachedDateFormat extends Dat
private static final int BUF_SIZE = 50;
- private static final int MILLIS_IN_SECONDS = 1000;
-
private static final int DEFAULT_VALIDITY = 1000;
private static final int THREE_DIGITS = 100;
@@ -170,10 +170,10 @@ final class CachedDateFormat extends Dat
* field (likely RelativeTimeDateFormat)
*/
public static int findMillisecondStart(final long time, final String formatted, final DateFormat formatter) {
- long slotBegin = (time / MILLIS_IN_SECONDS) * MILLIS_IN_SECONDS;
+ long slotBegin = (time / Constants.MILLIS_IN_SECONDS) * Constants.MILLIS_IN_SECONDS;
if (slotBegin > time) {
- slotBegin -= MILLIS_IN_SECONDS;
+ slotBegin -= Constants.MILLIS_IN_SECONDS;
}
final int millis = (int) (time - slotBegin);
@@ -292,10 +292,10 @@ final class CachedDateFormat extends Dat
cache.append(formatter.format(tmpDate));
buf.append(cache);
previousTime = now;
- slotBegin = (previousTime / MILLIS_IN_SECONDS) * MILLIS_IN_SECONDS;
+ slotBegin = (previousTime / Constants.MILLIS_IN_SECONDS) * Constants.MILLIS_IN_SECONDS;
if (slotBegin > previousTime) {
- slotBegin -= MILLIS_IN_SECONDS;
+ slotBegin -= Constants.MILLIS_IN_SECONDS;
}
//
Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FailoverAppenderTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FailoverAppenderTest.java?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FailoverAppenderTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/FailoverAppenderTest.java Tue Jan 1 19:27:47 2013
@@ -23,6 +23,7 @@ import org.apache.logging.log4j.core.Log
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.FailOnceAppender;
import org.apache.logging.log4j.test.appender.ListAppender;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -41,6 +42,7 @@ public class FailoverAppenderTest {
private static final String CONFIG = "log4j-failover.xml";
private static Configuration config;
private static ListAppender app;
+ private static FailOnceAppender foApp;
private static LoggerContext ctx;
@BeforeClass
@@ -51,7 +53,8 @@ public class FailoverAppenderTest {
for (final Map.Entry<String, Appender> entry : config.getAppenders().entrySet()) {
if (entry.getKey().equals("List")) {
app = (ListAppender) entry.getValue();
- break;
+ } else if (entry.getKey().equals("Once")) {
+ foApp = (FailOnceAppender) entry.getValue();
}
}
}
@@ -64,9 +67,11 @@ public class FailoverAppenderTest {
}
org.apache.logging.log4j.Logger logger = LogManager.getLogger("LoggerTest");
+ org.apache.logging.log4j.Logger onceLogger = LogManager.getLogger("Once");
@Test
public void testFailover() {
+ app.clear();
logger.error("This is a test");
List<LogEvent> events = app.getEvents();
assertNotNull(events);
@@ -77,4 +82,21 @@ public class FailoverAppenderTest {
assertNotNull(events);
assertTrue("Incorrect number of events. Should be 1 is " + events.size(), events.size() == 1);
}
+
+ @Test
+ public void testRecovery() throws Exception {
+ app.clear();
+ onceLogger.error("Fail once");
+ onceLogger.error("Fail again");
+ List<LogEvent> events = app.getEvents();
+ assertNotNull(events);
+ assertTrue("Incorrect number of events. Should be 2 is " + events.size(), events.size() == 2);
+ app.clear();
+ Thread.sleep(1100);
+ onceLogger.error("Fail after recovery interval");
+ events = app.getEvents();
+ assertTrue("Did not recoever", events.size() == 0);
+ events = foApp.getEvents();
+ assertTrue("No events in primary appender", events.size() == 1);
+ }
}
Copied: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java (from r1426987, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java?p2=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java&r1=1426987&r2=1427540&rev=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java Tue Jan 1 19:27:47 2013
@@ -23,28 +23,46 @@ import org.apache.logging.log4j.core.con
import org.apache.logging.log4j.core.config.plugins.PluginAttr;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import java.util.ArrayList;
+import java.util.List;
+
/**
*
*/
-@Plugin(name="AlwaysFail",type="Core",elementType="appender",printObject=true)
-public class AlwaysFailAppender extends AbstractAppender {
+@Plugin(name="FailOnce",type="Core",elementType="appender",printObject=true)
+public class FailOnceAppender extends AbstractAppender {
+
+ boolean fail = true;
+
+ private List<LogEvent> events = new ArrayList<LogEvent>();
- private AlwaysFailAppender(final String name) {
+ private FailOnceAppender(final String name) {
super(name, null, null, false);
}
public void append(final LogEvent event) {
- throw new LoggingException("Always fail");
+ if (fail) {
+ fail = false;
+ throw new LoggingException("Always fail");
+ } else {
+ events.add(event);
+ }
+ }
+
+ public List<LogEvent> getEvents() {
+ List<LogEvent> list = new ArrayList<LogEvent>(events);
+ events.clear();
+ return list;
}
@PluginFactory
- public static AlwaysFailAppender createAppender(@PluginAttr("name") final String name) {
+ public static FailOnceAppender createAppender(@PluginAttr("name") final String name) {
if (name == null) {
LOGGER.error("A name for the Appender must be specified");
return null;
}
- return new AlwaysFailAppender(name);
+ return new FailOnceAppender(name);
}
}
Modified: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-failover.xml Tue Jan 1 19:27:47 2013
@@ -19,15 +19,24 @@
<configuration status="error" name="FailoverTest" packages="org.apache.logging.log4j.test">
<Appenders>
<AlwaysFail name="Fail" />
+ <FailOnce name="Once"/>
<List name="List" />
<Failover name="Failover" primary="Fail" suppressExceptions="false">
<Failovers>
<appender-ref ref="List"/>
</Failovers>
</Failover>
+ <Failover name="FailoverOnce" primary="Once" suppressExceptions="false" retryInterval="1">
+ <Failovers>
+ <appender-ref ref="List"/>
+ </Failovers>
+ </Failover>
</Appenders>
<loggers>
+ <logger name="Once" level="error" additvity="false">
+ <appender-ref ref="FailoverOnce"/>
+ </logger>
<root level="error">
<appender-ref ref="Failover"/>
</root>
Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml?rev=1427540&r1=1427539&r2=1427540&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/appenders.xml Tue Jan 1 19:27:47 2013
@@ -222,6 +222,11 @@
<td>The name of the Appender.</td>
</tr>
<tr>
+ <td>retryInterval</td>
+ <td>integer</td>
+ <td>The number of seconds that should pass before retrying the primary Appender. The default is 60.</td>
+ </tr>
+ <tr>
<td>suppressExceptions</td>
<td>boolean</td>
<td>The default is true, causing exceptions to be internally logged and then ignored. When set to