brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [04/18] brooklyn-server git commit: trim redundant messages when showing errors
Date Fri, 04 Mar 2016 16:15:49 GMT
trim redundant messages when showing errors

esp if a task fails (like cloud prov) the error is prominent,
not wrapped in unnecessary context info


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/a74b8d22
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/a74b8d22
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/a74b8d22

Branch: refs/heads/master
Commit: a74b8d229add00dfdbacdd0c1df49b5f490addb9
Parents: 437c9bf
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Wed Feb 24 09:38:25 2016 -0800
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Wed Feb 24 09:38:25 2016 -0800

----------------------------------------------------------------------
 .../core/mgmt/internal/EffectorUtils.java       | 52 ++++++++++++++++----
 .../core/effector/EffectorBasicTest.java        | 52 +++++++++++++++-----
 .../core/effector/EffectorSayHiTest.java        | 16 +++---
 .../rest/transform/TaskTransformer.java         |  2 +-
 .../util/exceptions/CanSkipInContext.java       | 29 +++++++++++
 .../brooklyn/util/exceptions/Exceptions.java    | 48 +++++++++++-------
 6 files changed, 148 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
index f8bb7cb..b933cf4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EffectorUtils.java
@@ -41,12 +41,14 @@ import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.CanSkipInContext;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
@@ -261,17 +263,47 @@ public class EffectorUtils {
         }
     }
 
-    public static void handleEffectorException(Entity entity, Effector<?> effector,
Throwable throwable) {
-        String message = "Error invoking " + effector.getName() + " at " + entity;
-        // Avoid throwing a PropagatedRuntimeException that just repeats the last PropagatedRuntimeException.
-        if (throwable instanceof PropagatedRuntimeException &&
-                throwable.getMessage() != null &&
-                throwable.getMessage().startsWith(message)) {
-            throw PropagatedRuntimeException.class.cast(throwable);
-        } else {
-            log.warn(message + ": " + Exceptions.collapseText(throwable));
-            throw new PropagatedRuntimeException(message, throwable);
+    static class EffectorCallPropagatedRuntimeException extends PropagatedRuntimeException
implements CanSkipInContext {
+        private static final long serialVersionUID = 6146890711493851848L;
+        private String entityId;
+        private String effectorName;
+        public EffectorCallPropagatedRuntimeException(Entity entity, Effector<?> effector,
Throwable throwable) {
+            super(makeMessage(entity, effector), throwable);
+            this.entityId = entity.getId();
+            this.effectorName = effector.getName();
+        }
+        @Override
+        public boolean canSkipInContext(Object context) {
+            if (context instanceof Task) {
+                Entity entity = BrooklynTaskTags.getContextEntity((Task<?>)context);
+                if (entity==null || !Objects.equal(entityId, entity.getId())) return false;
+                if (!Objects.equal(effectorName, BrooklynTaskTags.getEffectorName((Task<?>)context)))
return false;
+                // matching entity and effector name is enough to skip the prefix;
+                // means a self-referential effector message might match others but that's
probably desired
+                // so we can see the underlying error quickly.
+                // (the trace includes the near-self calls)
+                return true;
+            }
+            return false;
+        }
+        private static String makeMessage(Entity entity, Effector<?> effector) {
+            return "Error invoking " + effector.getName() + " at " + entity;
         }
+        private static RuntimeException propagate(Entity entity, Effector<?> effector,
Throwable throwable) {
+            if (throwable instanceof EffectorCallPropagatedRuntimeException &&
+                    Objects.equal(makeMessage(entity, effector), throwable.getMessage()))
{
+                // Avoid throwing a PropagatedRuntimeException that just repeats the last
PropagatedRuntimeException.
+                throw (EffectorCallPropagatedRuntimeException)throwable;
+            }
+                
+            EffectorCallPropagatedRuntimeException result = new EffectorCallPropagatedRuntimeException(entity,
effector, throwable);
+            log.warn(Exceptions.collapseText(result));
+            throw result;
+        }
+    }
+    
+    public static void handleEffectorException(Entity entity, Effector<?> effector,
Throwable throwable) {
+        throw EffectorCallPropagatedRuntimeException.propagate(entity, effector, throwable);
     }
 
     public static <T> Task<T> invokeEffectorAsync(Entity entity, Effector<T>
eff, Map<String,?> parameters) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
index a8dfda5..05b3a10 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.core.effector;
 import java.util.List;
 import java.util.concurrent.Callable;
 
-import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
@@ -36,8 +35,7 @@ import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.util.text.Strings;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -46,8 +44,6 @@ import com.google.common.collect.ImmutableList;
 
 public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
 
-    private static final Logger log = LoggerFactory.getLogger(EffectorBasicTest.class);
-    
     // NB: more tests of effectors in EffectorSayHiTest and EffectorConcatenateTest
     // as well as EntityConfigMapUsageTest and others
 
@@ -75,7 +71,7 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
 
     @Test
     public void testInvokeEffectorStartWithArgs() {
-        Entities.invokeEffectorWithArgs((EntityLocal)app, app, Startable.START, locs).getUnchecked();
+        Entities.invokeEffectorWithArgs(app, app, Startable.START, locs).getUnchecked();
         Asserts.assertEqualsIgnoringOrder(locs, app.getLocations());
     }
 
@@ -121,7 +117,6 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
     @Test
     public void testInvokeEffectorStartFailing_EntitiesInvoke() {
         FailingEntity entity = createFailingEntity();
-        
         assertTaskFails( Entities.invokeEffectorWithArgs(entity, entity, Startable.START,
locs) );
     }
 
@@ -152,6 +147,34 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
         assertTaskSucceeds(task);
     }
 
+    @Test
+    public void testInvokeEffectorErrorCollapsedNicely() {
+        FailingEntity entity = createFailingEntity();
+        Task<Void> task = entity.invoke(Startable.START, MutableMap.of("locations",
locs));
+        Exception e = assertTaskFails( task );
+        // normal collapse should report where we started
+        String collapsed = Exceptions.collapseText(e);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, "Propagated"), "Error too verbose:
"+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, "invoking"), "Error not verbose
enough: "+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, "start"), "Error not verbose
enough: "+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, "FailingEntity"), "Error not
verbose enough: "+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, entity.getId()), "Error not
verbose enough: "+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, "Simulating"), "Error not verbose
enough: "+collapsed);
+        // in the context of the task we should not report where we started;
+        // it instead of
+        //    Error invoking start at FailingEntityImpl{id=wv6KwsPh}: Simulating entity stop
failure for test
+        // show
+        //   Simulating entity stop failure for test
+        collapsed = Exceptions.collapseTextInContext(e, task);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, "Propagated"), "Error too verbose:
"+collapsed);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, "invoking"), "Error too verbose:
"+collapsed);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, "start"), "Error too verbose:
"+collapsed);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, "FailingEntity"), "Error too
verbose: "+collapsed);
+        Assert.assertFalse(Strings.containsLiteral(collapsed, entity.getId()), "Error too
verbose: "+collapsed);
+        Assert.assertTrue(Strings.containsLiteral(collapsed, "Simulating"), "Error not verbose
enough: "+collapsed);
+    }
+     
+
     private void assertTaskSucceeds(Task<Void> task) {
         task.getUnchecked();
         Assert.assertFalse(task.isError());
@@ -161,23 +184,26 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
         Assert.assertTrue(Tasks.failed( ((HasTaskChildren)task).getChildren() ).iterator().hasNext());
     }
         
-    private void assertStartMethodFails(FailingEntity entity) {
+    private Exception assertStartMethodFails(FailingEntity entity) {
         try {
             entity.start(locs);
-            Assert.fail("Should have failed");
+            Asserts.shouldHaveFailedPreviously();
         } catch (Exception e) {
-            // expected
+            Asserts.expectedFailure(e);
+            return e;
         }
+        return null;
     }
      
-    protected void assertTaskFails(Task<?> t) {
+    protected Exception assertTaskFails(Task<?> t) {
         try {
             t.get();
             Assert.fail("Should have failed");
         } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            // expected
+            Asserts.expectedFailure(e);
+            return e;
         }
+        return null;
     }
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
index 76dcdba..7f37245 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
@@ -74,11 +74,11 @@ public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
 
     @Test
     public void testFindEffectorMetaData() {
-        assertEquals("sayHi1", e.SAY_HI_1.getName());
-        assertEquals("says hello", e.SAY_HI_1.getDescription());
+        assertEquals("sayHi1", MyEntity.SAY_HI_1.getName());
+        assertEquals("says hello", MyEntity.SAY_HI_1.getDescription());
         
-        assertEquals(ImmutableList.of("name", "greeting"), getParameterNames(e.SAY_HI_1));
-        assertEquals(MutableMap.of("name", null, "greeting", "what to say"), getParameterDescriptions(e.SAY_HI_1));
+        assertEquals(ImmutableList.of("name", "greeting"), getParameterNames(MyEntity.SAY_HI_1));
+        assertEquals(MutableMap.of("name", null, "greeting", "what to say"), getParameterDescriptions(MyEntity.SAY_HI_1));
     }
 
     @Test
@@ -90,12 +90,12 @@ public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
     public void testInvokeEffectors1() throws Exception {
         assertEquals("hi Bob", e.sayHi1("Bob", "hi"));
 
-        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting",
"hi")) );
-        assertEquals("hi Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting",
"hi")).get() );
+        assertEquals("hi Bob", MyEntity.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting",
"hi")) );
+        assertEquals("hi Bob", e.invoke(MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob",
"greeting", "hi")).get() );
         
         // and with default greeting param value
-        assertEquals("hi Bob", e.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting",
"hi")) );
-        assertEquals("hello Bob", e.invoke(e.SAY_HI_1, ImmutableMap.of("name", "Bob")).get()
);
+        assertEquals("hi Bob", MyEntity.SAY_HI_1.call(e, ImmutableMap.of("name", "Bob", "greeting",
"hi")) );
+        assertEquals("hello Bob", e.invoke(MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob")).get()
);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
index cb74164..7abb71a 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
@@ -114,7 +114,7 @@ public class TaskTransformer {
                 result = null;
             }
         } catch (Throwable t) {
-            result = Exceptions.collapseText(t);
+            result = Exceptions.collapseTextInContext(t, task);
         }
         
         return new TaskSummary(task.getId(), task.getDisplayName(), task.getDescription(),
entityId, entityDisplayName, 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CanSkipInContext.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CanSkipInContext.java
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CanSkipInContext.java
new file mode 100644
index 0000000..9a447fb
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/CanSkipInContext.java
@@ -0,0 +1,29 @@
+/*
+ * 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.brooklyn.util.exceptions;
+
+public interface CanSkipInContext {
+
+    /** Whether this should be skipped in the given context. In particular for exceptions,
+     * indicates whether it can be omitted when collapsing text for the given caller
+     * (such as a task reporting an exception should not report a redundant description of
a task.)
+     */
+    boolean canSkipInContext(Object context);
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a74b8d22/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
index 7653370..44d66ca 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
@@ -95,7 +95,8 @@ public class Exceptions {
         return false;
     }
 
-    private static String stripBoringPrefixes(String s) {
+    // not used, but kept in case we might want it
+    static String stripBoringPrefixes(String s) {
         ArrayList<String> prefixes = Lists.newArrayListWithCapacity(2 + BORING_PREFIX_THROWABLE_EXACT_TYPES.size()
* 3);
         for (Class<? extends Throwable> type : BORING_PREFIX_THROWABLE_EXACT_TYPES)
{
             prefixes.add(type.getCanonicalName());
@@ -218,24 +219,24 @@ public class Exceptions {
     /** as {@link #collapse(Throwable)} but includes causal messages in the message as per
{@link #collapseTextIncludingAllCausalMessages(Throwable)};
      * use with care (limit once) as repeated usage can result in multiple copies of the
same message */ 
     public static Throwable collapseIncludingAllCausalMessages(Throwable source) {
-        return collapse(source, true, true, ImmutableSet.<Throwable>of());
+        return collapse(source, true, true, ImmutableSet.<Throwable>of(), new Object[0]);
     }
     
     /** creates (but does not throw) a new {@link PropagatedRuntimeException} whose 
      * message is taken from the first _interesting_ element in the source,
      * and optionally also the causal chain */
     public static Throwable collapse(Throwable source, boolean collapseCausalChain) {
-        return collapse(source, collapseCausalChain, false, ImmutableSet.<Throwable>of());
+        return collapse(source, collapseCausalChain, false, ImmutableSet.<Throwable>of(),
new Object[0]);
     }
     
-    private static Throwable collapse(Throwable source, boolean collapseCausalChain, boolean
includeAllCausalMessages, Set<Throwable> visited) {
+    private static Throwable collapse(Throwable source, boolean collapseCausalChain, boolean
includeAllCausalMessages, Set<Throwable> visited, Object contexts[]) {
         visited = MutableSet.copyOf(visited);
         String message = "";
         Throwable collapsed = source;
         int collapseCount = 0;
         boolean messageIsFinal = false;
-        // remove boring stack traces at the head
-        while (isBoringForMessage(collapsed)  && !messageIsFinal) {
+        // remove boring exceptions at the head; if message is interesting append it
+        while ((isBoringForMessage(collapsed) || isSkippableInContext(collapsed, contexts))
&& !messageIsFinal) {
             collapseCount++;
             Throwable cause = collapsed.getCause();
             if (cause==null) {
@@ -248,14 +249,8 @@ public class Exceptions {
             }
             String collapsedS = collapsed.getMessage();
             if (collapsed instanceof PropagatedRuntimeException && ((PropagatedRuntimeException)collapsed).isCauseEmbeddedInMessage())
{
-                message = collapsed.getMessage();
+                message = collapsedS;
                 messageIsFinal = true;
-            } else if (Strings.isNonBlank(collapsedS)) {
-                String causeToString = getMessageWithAppropriatePrefix(cause);
-                collapsedS = Strings.removeAllFromEnd(collapsedS, cause.toString(), causeToString,
stripBoringPrefixes(causeToString), cause.getMessage());
-                collapsedS = stripBoringPrefixes(collapsedS);
-                if (Strings.isNonBlank(collapsedS))
-                    message = appendSeparator(message, collapsedS);
             }
             collapsed = cause;
         }
@@ -280,13 +275,24 @@ public class Exceptions {
         }
         
         if (messagesCause!=null && !messageIsFinal) {
-            String extraMessage = collapseText(messagesCause, includeAllCausalMessages, ImmutableSet.copyOf(visited));
+            String extraMessage = collapseText(messagesCause, includeAllCausalMessages, ImmutableSet.copyOf(visited),
contexts);
             message = appendSeparator(message, extraMessage);
         }
         if (message==null) message = "";
         return new PropagatedRuntimeException(message, collapseCausalChain ? collapsed :
source, Strings.isNonBlank(message));
     }
     
+    /** True if the given exception is skippable in any of the supplied contexts. */
+    public static boolean isSkippableInContext(Throwable e, Object... contexts) {
+        if (!(e instanceof CanSkipInContext)) return false;
+        for (Object c: contexts) { 
+            if (((CanSkipInContext)e).canSkipInContext(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     static String appendSeparator(String message, String next) {
         if (Strings.isBlank(message))
             return next;
@@ -309,6 +315,10 @@ public class Exceptions {
     public static String collapseText(Throwable t) {
         return collapseText(t, false);
     }
+    
+    public static String collapseTextInContext(Throwable t, Object ...contexts) {
+        return collapseText(t, false, ImmutableSet.<Throwable>of(), contexts);
+    }
 
     /** normally {@link #collapseText(Throwable)} will stop following causal chains when
encountering an interesting exception
      * with a message; this variant will continue to follow such causal chains, showing all
messages. 
@@ -318,9 +328,9 @@ public class Exceptions {
     }
     
     private static String collapseText(Throwable t, boolean includeAllCausalMessages) {
-        return collapseText(t, includeAllCausalMessages, ImmutableSet.<Throwable>of());
+        return collapseText(t, includeAllCausalMessages, ImmutableSet.<Throwable>of(),
new Object[0]);
     }
-    private static String collapseText(Throwable t, boolean includeAllCausalMessages, Set<Throwable>
visited) {
+    private static String collapseText(Throwable t, boolean includeAllCausalMessages, Set<Throwable>
visited, Object contexts[]) {
         if (t == null) return null;
         if (visited.contains(t)) {
             // If a boring-prefix class has no message it will render as multiply-visited.
@@ -330,7 +340,7 @@ public class Exceptions {
             if (t.getCause()!=null) return t.getCause().getClass().getName();
             return t.getClass().getName();
         }
-        Throwable t2 = collapse(t, true, includeAllCausalMessages, visited);
+        Throwable t2 = collapse(t, true, includeAllCausalMessages, visited, contexts);
         visited = MutableSet.copyOf(visited);
         visited.add(t);
         visited.add(t2);
@@ -339,7 +349,7 @@ public class Exceptions {
                 // normally
                 return t2.getMessage();
             else if (t2.getCause()!=null)
-                return collapseText(t2.getCause(), includeAllCausalMessages, ImmutableSet.copyOf(visited));
+                return collapseText(t2.getCause(), includeAllCausalMessages, ImmutableSet.copyOf(visited),
contexts);
             return ""+t2.getClass();
         }
         String result = getMessageWithAppropriatePrefix(t2);
@@ -348,7 +358,7 @@ public class Exceptions {
         }
         Throwable cause = t2.getCause();
         if (cause != null) {
-            String causeResult = collapseText(new PropagatedRuntimeException(cause));
+            String causeResult = collapseTextInContext(new PropagatedRuntimeException(cause),
contexts);
             if (result.indexOf(causeResult)>=0)
                 return result;
             return result + "; caused by "+causeResult;


Mime
View raw message