Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Show nested exceptions more clearly#25045

Closed
danmoseley wants to merge 5 commits intodotnet:masterfrom
danmoseley:exformat
Closed

Show nested exceptions more clearly#25045
danmoseley wants to merge 5 commits intodotnet:masterfrom
danmoseley:exformat

Conversation

@danmoseley
Copy link
Member

@danmoseley danmoseley commented Jun 9, 2019

Possible fix for https://github.com/dotnet/corefx/issues/37816

Changes made

  1. Put messages from nested inner exceptions on their own line. This is to avoid the 600 char+ lines.
  2. Format inner exceptions in a central place. This also fixes a bug in AggregateException where it would output one inner exception twice.
  3. Indent output from inner exceptions. This is to make it clear which contain which.
  4. Remove dividing markers for compactness. This is because indent makes them unnecessary.

Did not change

  1. Existing message content. This means that AggregateException's message still aggregates all interior messages to whatever length. (I did tweak ArgumentException message to be a single line though)
  2. Existing ordering of outer->inner messages followed by inner->outer stacks. In the deepest part of the indentation the innermost exception message and stack are still together.

Examples

Should change this from #37815 into more like this which removes duplication and draws the eye to the innermost exception, which in this case is the root cause.

Also this from #38293 to this. Again, half as long and it's easy to see which stack goes with which message.

Output of this test program was this is now this.

Thoughts?

@danmoseley danmoseley requested review from jkotas and stephentoub June 9, 2019 21:48
@stephentoub
Copy link
Member

stephentoub commented Jun 10, 2019

Can you share an example of what this looks like when one or more of the exceptions have been propagated multiple times via ExceptionDispatchInfo.Throw?

text.Append(m_innerExceptions[i].ToString());
text.Append("<---");
text.AppendLine();
sb.Append(base.InnerExceptionToString(ex));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having removed all of the separators, what does an AggregateException now look like?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See example linked in top post. I can also add one with an AggE wrapping an AggE.

@danmoseley
Copy link
Member Author

danmoseley commented Jun 10, 2019

@stephentoub

Can you share an example of what this looks like when one or more of the exceptions have been propagated multiple times via ExceptionDispatchInfo.Throw?

As you saw, I didn't change that banner:

test program
before
after

eg

         at _1.Program.F(String type, String msg)
         at _1.Program.E(String type, String msg)
         at _1.Program.D(String type, String msg)
      --- End of stack trace from previous location where exception was thrown ---
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(Exception source)
         at _1.Program.C(String type, String msg)
         at _1.Program.B(String type, String msg)

It is a bit distracting from the stack itself, though. I wonder whether the text is necessary or useful. Would this be an improvement?

         at _1.Program.F(String type, String msg)
         at _1.Program.E(String type, String msg)
         at _1.Program.D(String type, String msg)
      --------------------------
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(Exception source)
         at _1.Program.C(String type, String msg)
         at _1.Program.B(String type, String msg)

Or, is the ExceptionDispatchInfo.Throw sufficient, and divider not useful? We already skip it in the async case apparently (along with other shenanigans)

         at _1.Program.F(String type, String msg)
         at _1.Program.E(String type, String msg)
         at _1.Program.D(String type, String msg)
         at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(Exception source)
         at _1.Program.C(String type, String msg)
         at _1.Program.B(String type, String msg)

Edit: pushed up the change to remove the boundary for discussion sake.
new result

<data name="EventSource_VarArgsParameterMismatch" xml:space="preserve">
<value>The parameters to the Event method do not match the parameters to the WriteEvent method. This may cause the event to be displayed incorrectly.</value>
</data>
<data name="Exception_EndOfInnerExceptionStack" xml:space="preserve">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not unusual for folks to have parser of the Exception.ToString message - to reformat it or to identify root cause. Here is an example found by a quick github search:

https://github.com/pieceofsummer/Hangfire.StackTrace/blob/45ced0e988bee23f86d71c2fa60997b9210f677a/src/Hangfire.StackTrace/FailedStateRenderer.cs#L146

This change is likely going to break these ... that may be ok, but we do not have much time to react to feedback in 3.0.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cant we just enable that through configuration. In that way, people can start preparing for it, like it was done with tiered JIT.

Copy link
Member Author

@danmoseley danmoseley Jun 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have used AppContext switches less than a dozen times in .NET Core so far. If it is a temporary thing we take out after 3.0 then I do not object. I can use a switch to hide most of this just for a few weeks. Of course that means that few if anyone "benefits" from this in 3.0.

Another option is that I keep the changes to put messages on their own lines, and to avoid duplicating the first inner exception in the AggregateException, but defer the change to indent and defer removing the two dividers.

thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved part into #25185 for 3.0, and will pick this up again when master is open for .NET 5.

@danmoseley
Copy link
Member Author

I'll merge and finish this later for 5.0

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants