You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by lq...@apache.org on 2017/10/10 12:34:07 UTC
qpid-broker-j git commit: QPID-7955: [Java Broker] Workaround
LOGBACK-1027: Stack overflow on recursive exceptions
Repository: qpid-broker-j
Updated Branches:
refs/heads/master 28c3dc2bc -> 4889eac08
QPID-7955: [Java Broker] Workaround LOGBACK-1027: Stack overflow on recursive exceptions
Project: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/commit/4889eac0
Tree: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/tree/4889eac0
Diff: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/diff/4889eac0
Branch: refs/heads/master
Commit: 4889eac089acd05f6725cbeca23d30eff2f84d63
Parents: 28c3dc2
Author: Lorenz Quack <lq...@apache.org>
Authored: Tue Oct 10 13:25:09 2017 +0100
Committer: Lorenz Quack <lq...@apache.org>
Committed: Tue Oct 10 13:33:59 2017 +0100
----------------------------------------------------------------------
.../Logback1027WorkaroundTurboFilter.java | 117 +++++++++
.../LogbackLoggingSystemLauncherListener.java | 10 +-
.../Logback1027WorkaroundTurboFilterTest.java | 257 +++++++++++++++++++
3 files changed, 382 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/4889eac0/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilter.java
----------------------------------------------------------------------
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilter.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilter.java
new file mode 100644
index 0000000..9787fbb
--- /dev/null
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.qpid.server.logging.logback;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.turbo.TurboFilter;
+import ch.qos.logback.core.spi.FilterReply;
+import org.slf4j.Marker;
+
+public class Logback1027WorkaroundTurboFilter extends TurboFilter
+{
+ @Override
+ public FilterReply decide(final Marker marker,
+ final Logger logger,
+ final Level level,
+ final String format,
+ final Object[] params,
+ final Throwable t)
+ {
+
+ Set<Throwable> seen = Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
+
+
+ if (t != null && hasRecursiveThrowableReference(t, seen))
+ {
+ final int locationAwareLoggerInteger = Level.toLocationAwareLoggerInteger(level);
+ logger.log(marker, logger.getName(), locationAwareLoggerInteger, format, params, new StringifiedException(t));
+ return FilterReply.DENY;
+ }
+
+ return FilterReply.NEUTRAL;
+ }
+
+ private boolean hasRecursiveThrowableReference(Throwable t, Set<Throwable> seen)
+ {
+ if (t == null)
+ {
+ return false;
+ }
+ if (!seen.add(t))
+ {
+ return true;
+ }
+ else
+ {
+ final Throwable[] allSuppressed = t.getSuppressed();
+ int allSuppressedLength = allSuppressed.length;
+ if (allSuppressedLength > 0)
+ {
+ Set<Throwable> seenCopy = Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>(seen.size()));
+ seenCopy.addAll(seen);
+ for (int i = 0; i < allSuppressedLength; ++i)
+ {
+ if (hasRecursiveThrowableReference(allSuppressed[i], seenCopy))
+ {
+ return true;
+ }
+ }
+ }
+ if (hasRecursiveThrowableReference(t.getCause(), seen))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static class StringifiedException extends RuntimeException
+ {
+ public StringifiedException(final Throwable t)
+ {
+ super(stringifyStacktrace(t));
+ }
+
+ private static String stringifyStacktrace(final Throwable e)
+ {
+ try (StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw))
+ {
+ e.printStackTrace(pw);
+ pw.println("End of stringified Stacktrace");
+ return sw.toString();
+ }
+ catch (IOException e1)
+ {
+ throw new RuntimeException("Unexpected exception stringifying stacktrace", e1);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/4889eac0/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/LogbackLoggingSystemLauncherListener.java
----------------------------------------------------------------------
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/LogbackLoggingSystemLauncherListener.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/LogbackLoggingSystemLauncherListener.java
index fc676ff..fbbf3e5 100644
--- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/LogbackLoggingSystemLauncherListener.java
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/LogbackLoggingSystemLauncherListener.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.logging.logback;
import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,6 +32,7 @@ public class LogbackLoggingSystemLauncherListener implements SystemLauncherListe
{
private StartupAppender _startupAppender;
private ch.qos.logback.classic.Logger _logger;
+ private Logback1027WorkaroundTurboFilter _logback1027WorkaroundTurboFilter;
@Override
public void beforeStartup()
@@ -42,11 +44,14 @@ public class LogbackLoggingSystemLauncherListener implements SystemLauncherListe
_logger.setAdditive(true);
}
+ final LoggerContext loggerContext = _logger.getLoggerContext();
+ _logback1027WorkaroundTurboFilter = new Logback1027WorkaroundTurboFilter();
+ loggerContext.addTurboFilter(_logback1027WorkaroundTurboFilter);
+
_startupAppender = new StartupAppender();
- _startupAppender.setContext(_logger.getLoggerContext());
+ _startupAppender.setContext(loggerContext);
_startupAppender.start();
_logger.addAppender(_startupAppender);
-
}
@Override
@@ -80,6 +85,7 @@ public class LogbackLoggingSystemLauncherListener implements SystemLauncherListe
public void onContainerClose(final SystemConfig<?> systemConfig)
{
QpidLoggerTurboFilter.uninstallFromRootContext();
+ _logger.getLoggerContext().getTurboFilterList().remove(_logback1027WorkaroundTurboFilter);
}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/4889eac0/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilterTest.java
----------------------------------------------------------------------
diff --git a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilterTest.java b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilterTest.java
new file mode 100644
index 0000000..84ab2f3
--- /dev/null
+++ b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilterTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.qpid.server.logging.logback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.spi.IThrowableProxy;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.LogbackException;
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import ch.qos.logback.core.status.Status;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class Logback1027WorkaroundTurboFilterTest extends QpidTestCase
+{
+ private static final String TEST_LOG_MESSAGE = "hello";
+ private Logback1027WorkaroundTurboFilter _filter = new Logback1027WorkaroundTurboFilter();
+ private Logger _logger;
+ private SnoopingAppender _snoopingAppender;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ LoggerContext context = new LoggerContext();
+ _logger = context.getLogger(Logback1027WorkaroundTurboFilterTest.class);
+ _snoopingAppender = new SnoopingAppender();
+ _logger.addAppender(_snoopingAppender);
+ }
+
+ public void testOneException()
+ {
+ Exception e = new Exception();
+ final FilterReply reply = doDecide(e);
+ assertEquals(FilterReply.NEUTRAL, reply);
+
+ assertEquals(0, _snoopingAppender.getEvents().size());
+ }
+
+ public void testSuppressedExceptionRecursion()
+ {
+ Exception e1 = new Exception();
+ Exception e2 = new Exception();
+ e2.addSuppressed(e1);
+ e1.addSuppressed(e2);
+
+ final FilterReply reply = doDecide(e1);
+ assertEquals(FilterReply.DENY, reply);
+
+ final List<ILoggingEvent> events = _snoopingAppender.getEvents();
+ assertEquals(1, events.size());
+
+ assertLoggingEvent(events.get(0));
+ }
+
+ private void assertLoggingEvent(final ILoggingEvent loggingEvent)
+ {
+ assertEquals(Level.INFO, loggingEvent.getLevel());
+ assertEquals(TEST_LOG_MESSAGE, loggingEvent.getMessage());
+ assertNull(loggingEvent.getArgumentArray());
+ IThrowableProxy thing = loggingEvent.getThrowableProxy();
+ assertEquals(Logback1027WorkaroundTurboFilter.StringifiedException.class.getName(), thing.getClassName());
+ }
+
+ public void testInitCauseRecursion() throws Exception
+ {
+ Exception e1 = new Exception();
+ Exception e2 = new Exception();
+ e2.initCause(e1);
+ e1.initCause(e2);
+
+ final FilterReply reply = doDecide(e1);
+ assertEquals(FilterReply.DENY, reply);
+ assertEquals(1, _snoopingAppender.getEvents().size());
+ }
+
+ public void testNoRecursion()
+ {
+ Exception e1 = new Exception();
+ Exception e2 = new Exception();
+ Exception e3 = new Exception();
+
+ e2.addSuppressed(e3);
+ e1.addSuppressed(e2);
+ e1.initCause(e3);
+
+ final FilterReply reply = doDecide(e1);
+ assertEquals(FilterReply.NEUTRAL, reply);
+ assertEquals(0, _snoopingAppender.getEvents().size());
+ }
+
+ public void testNoRecursion2()
+ {
+ Exception e1 = new Exception();
+ Exception e2 = new Exception();
+ Exception e3 = new Exception();
+
+ e2.initCause(e3);
+ e1.initCause(e2);
+ e1.addSuppressed(e3);
+
+ final FilterReply reply = doDecide(e1);
+ assertEquals(FilterReply.NEUTRAL, reply);
+ assertEquals(0, _snoopingAppender.getEvents().size());
+ }
+
+ private FilterReply doDecide(final Exception e1)
+ {
+ return _filter.decide(null, _logger, Level.INFO, "hello", null, e1);
+ }
+
+ private static class SnoopingAppender implements Appender<ILoggingEvent>
+ {
+
+ private List<ILoggingEvent> _events = new ArrayList<>();
+
+ List<ILoggingEvent> getEvents()
+ {
+ return _events;
+ }
+
+ @Override
+ public void doAppend(final ILoggingEvent event) throws LogbackException
+ {
+ _events.add(event);
+ }
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public void setName(final String name)
+ {
+ }
+
+ @Override
+ public void setContext(final Context context)
+ {
+ }
+
+ @Override
+ public Context getContext()
+ {
+ return null;
+ }
+
+ @Override
+ public void addStatus(final Status status)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addInfo(final String msg)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addInfo(final String msg, final Throwable ex)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addWarn(final String msg)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addWarn(final String msg, final Throwable ex)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addError(final String msg)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addError(final String msg, final Throwable ex)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addFilter(final Filter<ILoggingEvent> newFilter)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clearAllFilters()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Filter<ILoggingEvent>> getCopyOfAttachedFiltersList()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FilterReply getFilterChainDecision(final ILoggingEvent event)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void start()
+ {
+ }
+
+ @Override
+ public void stop()
+ {
+ }
+
+ @Override
+ public boolean isStarted()
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org