This is an automated email from the ASF dual-hosted git repository.
dakirily pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
The following commit(s) were added to refs/heads/main by this push:
new 30a6e6357b QPID-8768: [Broker-J] Remove obsolete Logback
circular-exception workaround (#449)
30a6e6357b is described below
commit 30a6e6357bbe1f9e5b57452de0134cbc0cea1272
Author: usugumo <[email protected]>
AuthorDate: Mon Oct 19 11:19:02 2026 +0200
QPID-8768: [Broker-J] Remove obsolete Logback circular-exception workaround
(#449)
---
.../logback/Logback1027WorkaroundTurboFilter.java | 119 --------
.../LogbackLoggingSystemLauncherListener.java | 5 -
.../Logback1027WorkaroundTurboFilterTest.java | 280 -----------------
.../logback/LogbackExceptionHandlingTest.java | 332 +++++++++++++++++++++
4 files changed, 332 insertions(+), 404 deletions(-)
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
deleted file mode 100644
index 5180f31a2e..0000000000
---
a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilter.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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)
- {
- if (t != null && hasRecursiveThrowableReference(t, null))
- {
- 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 == null)
- {
- seen = Collections.newSetFromMap(new IdentityHashMap<>());
- }
-
- 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<>(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);
- }
- }
- }
-
-}
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 a56e2702e1..90b781c784 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
@@ -32,7 +32,6 @@ public class LogbackLoggingSystemLauncherListener implements
SystemLauncherListe
{
private StartupAppender _startupAppender;
private ch.qos.logback.classic.Logger _logger;
- private Logback1027WorkaroundTurboFilter _logback1027WorkaroundTurboFilter;
@Override
public void beforeStartup()
@@ -45,9 +44,6 @@ public class LogbackLoggingSystemLauncherListener implements
SystemLauncherListe
}
final LoggerContext loggerContext = _logger.getLoggerContext();
- _logback1027WorkaroundTurboFilter = new
Logback1027WorkaroundTurboFilter();
- loggerContext.addTurboFilter(_logback1027WorkaroundTurboFilter);
-
_startupAppender = new StartupAppender();
_startupAppender.setContext(loggerContext);
_startupAppender.start();
@@ -85,7 +81,6 @@ public class LogbackLoggingSystemLauncherListener implements
SystemLauncherListe
public void onContainerClose(final SystemConfig<?> systemConfig)
{
QpidLoggerTurboFilter.uninstallFromRootContext();
-
_logger.getLoggerContext().getTurboFilterList().remove(_logback1027WorkaroundTurboFilter);
}
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
deleted file mode 100644
index 5d42f26141..0000000000
---
a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/Logback1027WorkaroundTurboFilterTest.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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 static org.apache.qpid.test.utils.JvmVendor.IBM;
-import static org.apache.qpid.test.utils.JvmVendor.OPENJDK;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assumptions.assumeFalse;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-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.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.apache.qpid.test.utils.UnitTestBase;
-
-public class Logback1027WorkaroundTurboFilterTest extends UnitTestBase
-{
- private static final String TEST_LOG_MESSAGE = "hello";
- private final Logback1027WorkaroundTurboFilter _filter = new
Logback1027WorkaroundTurboFilter();
- private Logger _logger;
- private SnoopingAppender _snoopingAppender;
-
- @BeforeEach
- public void setUp() throws Exception
- {
- final LoggerContext context = new LoggerContext();
- _logger =
context.getLogger(Logback1027WorkaroundTurboFilterTest.class);
- _snoopingAppender = new SnoopingAppender();
- _logger.addAppender(_snoopingAppender);
- }
-
- @Test
- public void testOneException()
- {
- final Exception e = new Exception();
- final FilterReply reply = doDecide(e);
- assertEquals(FilterReply.NEUTRAL, reply);
-
- assertEquals(0, (long) _snoopingAppender.getEvents().size());
- }
-
- @Test
- public void testSuppressedExceptionRecursion()
- {
- //
https://www.ibm.com/developerworks/community/forums/html/topic?id=8482d948-665c-47a2-862e-457e49ac71a4&ps=25
- assumeFalse(Objects.equals(getJvmVendor(), OPENJDK) ||
Objects.equals(getJvmVendor(), IBM),
- "(QPID-7955) Behavioural difference between the IBM JDK and
the Open JDK");
-
- final Exception e1 = new Exception();
- final 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, (long) 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());
- final IThrowableProxy thing = loggingEvent.getThrowableProxy();
-
assertEquals(Logback1027WorkaroundTurboFilter.StringifiedException.class.getName(),
thing.getClassName());
- }
-
- @Test
- public void testInitCauseRecursion()
- {
- //
https://www.ibm.com/developerworks/community/forums/html/topic?id=8482d948-665c-47a2-862e-457e49ac71a4&ps=25
- assumeFalse(Objects.equals(getJvmVendor(), OPENJDK) ||
Objects.equals(getJvmVendor(), IBM),
- "(QPID-7955) Behavioural difference between the IBM JDK and
the Open JDK");
-
- final Exception e1 = new Exception();
- final Exception e2 = new Exception();
- e2.initCause(e1);
- e1.initCause(e2);
-
- final FilterReply reply = doDecide(e1);
- assertEquals(FilterReply.DENY, reply);
- assertEquals(1, (long) _snoopingAppender.getEvents().size());
- }
-
- @Test
- public void testNoRecursion()
- {
- final Exception e1 = new Exception();
- final Exception e2 = new Exception();
- final Exception e3 = new Exception();
-
- e2.addSuppressed(e3);
- e1.addSuppressed(e2);
- e1.initCause(e3);
-
- final FilterReply reply = doDecide(e1);
- assertEquals(FilterReply.NEUTRAL, reply);
- assertEquals(0, (long) _snoopingAppender.getEvents().size());
- }
-
- @Test
- public void testNoRecursion2()
- {
- final Exception e1 = new Exception();
- final Exception e2 = new Exception();
- final Exception e3 = new Exception();
-
- e2.initCause(e3);
- e1.initCause(e2);
- e1.addSuppressed(e3);
-
- final FilterReply reply = doDecide(e1);
- assertEquals(FilterReply.NEUTRAL, reply);
- assertEquals(0, (long) _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 final 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
diff --git
a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/LogbackExceptionHandlingTest.java
b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/LogbackExceptionHandlingTest.java
new file mode 100644
index 0000000000..618b2e59f1
--- /dev/null
+++
b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/LogbackExceptionHandlingTest.java
@@ -0,0 +1,332 @@
+/*
+ *
+ * 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 static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import java.util.Arrays;
+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.PatternLayout;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.spi.IThrowableProxy;
+import ch.qos.logback.classic.spi.StackTraceElementProxy;
+import ch.qos.logback.classic.spi.ThrowableProxy;
+import ch.qos.logback.classic.util.LogbackMDCAdapter;
+import ch.qos.logback.core.read.ListAppender;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.MockedStatic;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class LogbackExceptionHandlingTest extends UnitTestBase
+{
+ private static final String TEST_LOG_MESSAGE = "hello";
+ private static final Marker TEST_MARKER =
MarkerFactory.getMarker("exception-handling-test");
+
+ private LoggerContext _loggerContext;
+ private Logger _logger;
+ private ListAppender<ILoggingEvent> _appender;
+ private PatternLayout _layout;
+
+ @BeforeEach
+ public void setUp()
+ {
+ _loggerContext = new LoggerContext();
+ _loggerContext.setMDCAdapter(new LogbackMDCAdapter());
+ _loggerContext.start();
+ _logger = _loggerContext.getLogger(getTestClassName());
+ _logger.setLevel(Level.INFO);
+ _logger.setAdditive(false);
+
+ _appender = new ListAppender<>();
+ _appender.setContext(_loggerContext);
+ _appender.start();
+ _logger.addAppender(_appender);
+
+ _layout = new PatternLayout();
+ _layout.setContext(_loggerContext);
+ _layout.setPattern("%msg%n%ex");
+ _layout.start();
+ }
+
+ @AfterEach
+ public void tearDown()
+ {
+ _layout.stop();
+ _loggerContext.stop();
+ }
+
+ @Test
+ public void testSingleException()
+ {
+ final Exception exception = new IllegalStateException("outer");
+ final ILoggingEvent event = logException(exception, false);
+
+ assertNull(event.getThrowableProxy().getCause());
+ assertEquals(0, event.getThrowableProxy().getSuppressed().length);
+ assertFalse(_layout.doLayout(event).contains("CIRCULAR REFERENCE"));
+ }
+
+ @Test
+ public void testCauseAndSuppressedException()
+ {
+ final Exception cause = new IllegalArgumentException("cause");
+ final Exception suppressed = new
UnsupportedOperationException("suppressed");
+ final Exception exception = new IllegalStateException("outer", cause);
+ exception.addSuppressed(suppressed);
+
+ final ILoggingEvent event = logException(exception, false);
+ assertThrowable(cause, event.getThrowableProxy().getCause());
+ assertEquals(1, event.getThrowableProxy().getSuppressed().length);
+ assertThrowable(suppressed,
event.getThrowableProxy().getSuppressed()[0]);
+ assertRendered(event, "Caused by: " + cause);
+ assertRendered(event, "Suppressed: " + suppressed);
+ assertFalse(_layout.doLayout(event).contains("CIRCULAR REFERENCE"));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ public void testCircularCauses(final boolean parameterized)
+ {
+ final Exception exception = new IllegalStateException("outer");
+ final Exception cause = new IllegalArgumentException("cause",
exception);
+ exception.initCause(cause);
+
+ final ILoggingEvent event = logException(exception, parameterized);
+ final IThrowableProxy causeProxy =
event.getThrowableProxy().getCause();
+ assertThrowable(cause, causeProxy);
+ assertCyclicReference(exception, causeProxy.getCause());
+ assertRendered(event, "Caused by: " + cause);
+ assertRendered(event, "CIRCULAR REFERENCE");
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ public void testCircularSuppressedExceptions(final boolean parameterized)
+ {
+ final Exception exception = new IllegalStateException("outer");
+ final Exception suppressed = new
IllegalArgumentException("suppressed");
+ exception.addSuppressed(suppressed);
+ suppressed.addSuppressed(exception);
+
+ final ILoggingEvent event = logException(exception, parameterized);
+ assertEquals(1, event.getThrowableProxy().getSuppressed().length);
+ final IThrowableProxy suppressedProxy =
event.getThrowableProxy().getSuppressed()[0];
+ assertThrowable(suppressed, suppressedProxy);
+ assertEquals(1, suppressedProxy.getSuppressed().length);
+ assertCyclicReference(exception, suppressedProxy.getSuppressed()[0]);
+ assertRendered(event, "Suppressed: " + suppressed);
+ assertRendered(event, "CIRCULAR REFERENCE");
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ public void testMixedCauseAndSuppressedCycle(final boolean parameterized)
+ {
+ final Exception cause = new IllegalArgumentException("cause");
+ final Exception exception = new IllegalStateException("outer", cause);
+ cause.addSuppressed(exception);
+
+ final ILoggingEvent event = logException(exception, parameterized);
+ final IThrowableProxy causeProxy =
event.getThrowableProxy().getCause();
+ assertThrowable(cause, causeProxy);
+ assertEquals(1, causeProxy.getSuppressed().length);
+ assertCyclicReference(exception, causeProxy.getSuppressed()[0]);
+ assertRendered(event, "Caused by: " + cause);
+ assertRendered(event, "CIRCULAR REFERENCE");
+ }
+
+ @Test
+ public void testCauseSharedWithNestedSuppressedException()
+ {
+ final Exception shared = new IllegalArgumentException("shared");
+ final Exception suppressed = new
UnsupportedOperationException("suppressed");
+ final Exception exception = new IllegalStateException("outer", shared);
+ exception.addSuppressed(suppressed);
+ suppressed.addSuppressed(shared);
+
+ final ILoggingEvent event = logException(exception, false);
+ assertThrowable(shared, event.getThrowableProxy().getCause());
+ assertEquals(1, event.getThrowableProxy().getSuppressed().length);
+ final IThrowableProxy suppressedProxy =
event.getThrowableProxy().getSuppressed()[0];
+ assertThrowable(suppressed, suppressedProxy);
+ assertEquals(1, suppressedProxy.getSuppressed().length);
+ // Logback also uses a cyclic reference for a shared throwable in an
otherwise acyclic graph.
+ assertCyclicReference(shared, suppressedProxy.getSuppressed()[0]);
+ assertRendered(event, "CIRCULAR REFERENCE");
+ }
+
+ @Test
+ public void testSuppressedExceptionSharedWithNestedCause()
+ {
+ final Exception shared = new UnsupportedOperationException("shared");
+ final Exception cause = new IllegalArgumentException("cause", shared);
+ final Exception exception = new IllegalStateException("outer", cause);
+ exception.addSuppressed(shared);
+
+ final ILoggingEvent event = logException(exception, false);
+ assertThrowable(cause, event.getThrowableProxy().getCause());
+ assertThrowable(shared,
event.getThrowableProxy().getCause().getCause());
+ assertEquals(1, event.getThrowableProxy().getSuppressed().length);
+ assertCyclicReference(shared,
event.getThrowableProxy().getSuppressed()[0]);
+ assertRendered(event, "CIRCULAR REFERENCE");
+ }
+
+ @Test
+ public void testCircularExceptionAfterBrokerStartup()
+ {
+ final Logger rootLogger =
_loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
+ _logger.setAdditive(true);
+ final LogbackLoggingSystemLauncherListener listener = beforeStartup();
+ try
+ {
+ final Exception exception = new IllegalStateException("outer");
+ exception.initCause(new IllegalArgumentException("cause",
exception));
+
+ final ILoggingEvent event = logException(exception, false);
+ assertCyclicReference(exception,
event.getThrowableProxy().getCause().getCause());
+ assertRendered(event, "CIRCULAR REFERENCE");
+
+ final StartupAppender startupAppender =
+ assertInstanceOf(StartupAppender.class,
rootLogger.getAppender(StartupAppender.class.getName()));
+ startupAppender.replayAccumulatedEvents(_appender);
+ assertEquals(2, _appender.list.size());
+ assertSame(event, _appender.list.get(1));
+ }
+ finally
+ {
+ listener.afterStartup();
+ }
+ }
+
+ @Test
+ public void testDisabledLevelDoesNotInspectExceptionAfterBrokerStartup()
+ {
+ final LogbackLoggingSystemLauncherListener listener = beforeStartup();
+ try
+ {
+ _logger.setLevel(Level.WARN);
+ final Throwable exception = mock(Throwable.class);
+
+ _logger.info(TEST_LOG_MESSAGE, exception);
+
+ assertTrue(_appender.list.isEmpty());
+ verifyNoInteractions(exception);
+ }
+ finally
+ {
+ listener.afterStartup();
+ }
+ }
+
+ private LogbackLoggingSystemLauncherListener beforeStartup()
+ {
+ final Logger rootLogger =
_loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
+ final LogbackLoggingSystemLauncherListener listener = new
LogbackLoggingSystemLauncherListener();
+ try (final MockedStatic<LoggerFactory> loggerFactory =
mockStatic(LoggerFactory.class))
+ {
+ loggerFactory.when(() ->
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).thenReturn(rootLogger);
+ listener.beforeStartup();
+ }
+ return listener;
+ }
+
+ private ILoggingEvent logException(final Throwable exception, final
boolean parameterized)
+ {
+ if (parameterized)
+ {
+ _logger.info(TEST_MARKER, TEST_LOG_MESSAGE + " {}", "world",
exception);
+ }
+ else
+ {
+ _logger.info(TEST_MARKER, TEST_LOG_MESSAGE, exception);
+ }
+
+ assertEquals(1, _appender.list.size(), "Exactly one logging event
should be emitted");
+ final ILoggingEvent event = _appender.list.get(0);
+ assertEquals(Level.INFO, event.getLevel());
+ assertEquals(_logger.getName(), event.getLoggerName());
+ assertEquals(List.of(TEST_MARKER), event.getMarkerList());
+ assertEquals(parameterized ? TEST_LOG_MESSAGE + " {}" :
TEST_LOG_MESSAGE, event.getMessage());
+ assertEquals(parameterized ? TEST_LOG_MESSAGE + " world" :
TEST_LOG_MESSAGE, event.getFormattedMessage());
+ if (parameterized)
+ {
+ assertArrayEquals(new Object[] {"world"},
event.getArgumentArray());
+ }
+ else
+ {
+ assertNull(event.getArgumentArray());
+ }
+ assertThrowable(exception, event.getThrowableProxy());
+ assertRendered(event, exception.toString());
+ return event;
+ }
+
+ private void assertThrowable(final Throwable expected, final
IThrowableProxy actual)
+ {
+ final ThrowableProxy proxy = assertInstanceOf(ThrowableProxy.class,
actual);
+ assertSame(expected, proxy.getThrowable());
+ assertEquals(expected.getClass().getName(), actual.getClassName());
+ assertEquals(expected.getMessage(), actual.getMessage());
+ assertFalse(actual.isCyclic());
+ assertArrayEquals(expected.getStackTrace(),
Arrays.stream(actual.getStackTraceElementProxyArray())
+
.map(StackTraceElementProxy::getStackTraceElement).toArray(StackTraceElement[]::new));
+ }
+
+ private void assertCyclicReference(final Throwable expected, final
IThrowableProxy actual)
+ {
+ final ThrowableProxy proxy = assertInstanceOf(ThrowableProxy.class,
actual);
+ assertSame(expected, proxy.getThrowable());
+ assertEquals(expected.getClass().getName(), actual.getClassName());
+ assertEquals(expected.getMessage(), actual.getMessage());
+ assertTrue(actual.isCyclic());
+ assertNull(actual.getCause());
+ assertEquals(0, actual.getSuppressed().length);
+ assertEquals(0, actual.getStackTraceElementProxyArray().length);
+ }
+
+ private void assertRendered(final ILoggingEvent event, final String
expected)
+ {
+ final String rendered = _layout.doLayout(event);
+ assertTrue(rendered.contains(expected), rendered);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]