-
Notifications
You must be signed in to change notification settings - Fork 69
Support nested C# exceptions #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support nested C# exceptions #58
Conversation
* Inner exceptions * Aggregate exceptions (from wait operations on failed tasks) * Exceptions thrown from asynchronous code
ef8ce9d to
1df893b
Compare
|
@eadred Thank you for the contribution! This plugin is designed to work with Stackdriver Error Reporting, which should recognize the resulting multiline message as a stack trace. I'm verifying this with the team right now whether the backend would recognize a nested C# exception if the stack trace were joined into a single log entry. If the backend won't recognize these, there's no point in handling them in the plugin, and we should file an Error Reporting feature request. |
|
I've confirmed with the Error Reporting team that all 3 new exceptions were picked up by Error Reporting, but maybe not in the form you'd expect. For example, for the For the record, a self-service test can be done by running: echo "System.AggregateException: One or more errors occurred. (This is an exception) ---> System.InvalidOperationException: This is an exception
at ExampleApp.AsyncExceptionExample.LowestLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 28
at ExampleApp.AsyncExceptionExample.ThirdLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 23
at ExampleApp.AsyncExceptionExample.SecondLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 17
at ExampleApp.AsyncExceptionExample.TopLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 12
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at ExampleApp.Program.Main(String[] args) in c:/ExampleApp/ExampleApp/Program.cs:line 12
---> (Inner Exception #0) System.InvalidOperationException: This is an exception
at ExampleApp.AsyncExceptionExample.LowestLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 28
at ExampleApp.AsyncExceptionExample.ThirdLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 23
at ExampleApp.AsyncExceptionExample.SecondLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 17
at ExampleApp.AsyncExceptionExample.TopLevelMethod() in c:/ExampleApp/ExampleApp/AsyncExceptionExample.cs:line 12<---
" | \
gcloud beta error-reporting events report \
--service manual \
--service-version test-version \
--project=$(gcloud config get-value project) \
--message-file=/dev/stdin(see the gcloud docs). If the ingestion results don't look ok, let's open a feature request against Error Reporting before proceeding with this PR. For the values that work correctly, we can start reviewing those portions of the PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some preliminary comments.
|
|
||
| # C# aggregate exception | ||
| rule([:java_after_exception, :java], | ||
| /^---> \(Inner Exception #[0-9]+\)/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These look sufficiently different from Java that they merit a separate set of rules for C# (possibly sharing some of the Java rules programmatically, e.g., by copying the rules and doing symbol substitution). @qingling128, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. At least we should separate the names (not having java_after_exception in a C# exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem I'm having implementing this is there's not a good way of distinguishing between what is a C# exception and what is a Java exception when first transitioning to a *_start_exception state. Essentially both have to look for Exception in the text.
Because of this, if the JAVA_RULES are added first to ALL_RULES before CSHARP_RULES, then C# exceptions go off down the Java state machine path, and therefore never encounter C# specific rules like the ones I'm trying to implement. Likewise, if CSHARP_RULES were to appear before JAVA_RULES then Java exceptions get picked up by the C# state machine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the problem here. The Java state machine could use a lot of improvement, but that's way beyond the scope of this PR, so what you have is fine.
| at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0 | ||
| END | ||
|
|
||
| CSHARP_NESTED_EXC = <<END.freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be time to define an array of exceptions per language. This is a much larger refactoring than we should reasonably expect you to do in this PR, but if you're game, that's great. If not, we could try to do it ourselves, and then rebase your PR on top of the result. @qingling128, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with merging this PR once it's approved and refactoring them into arrays per language later. This way we unblock the use case earlier.
|
|
||
| # C# aggregate exception | ||
| rule([:java_after_exception, :java], | ||
| /^---> \(Inner Exception #[0-9]+\)/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. At least we should separate the names (not having java_after_exception in a C# exception.
| at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0 | ||
| END | ||
|
|
||
| CSHARP_NESTED_EXC = <<END.freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with merging this PR once it's approved and refactoring them into arrays per language later. This way we unblock the use case earlier.
1df893b to
800b860
Compare
| # C# exception from async code | ||
| rule([:java_after_exception, :java], | ||
| %r{^---\sEnd\sof\sstack\strace\sfrom\sprevious\s | ||
| location\swhere\sexception\swas\sthrown\s---}x, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linter doesn't like this ('Use // around regular expression.'), but without it I end up with a line that is too long for the linter. Have you got any suggestions about how to split the regex across multiple lines (Ruby isn't my language)?
I could perhaps define a '+' operator for Regexp, as suggested here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try the /x modifier, as suggested here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't force-push changes once the PR is being reviewed. Force-pushes make it impossible to retain conversation threads. It's ok to have multiple commits in a PR — we'll squash-and-merge them anyway.
Can you restore the previous commit chain (git reflog is your friend), add the latest changes in top of that, and re-push?
| # C# exception from async code | ||
| rule([:java_after_exception, :java], | ||
| %r{^---\sEnd\sof\sstack\strace\sfrom\sprevious\s | ||
| location\swhere\sexception\swas\sthrown\s---}x, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try the /x modifier, as suggested here.
* Aligning method params properly * Attempting to put long regex on multi-lines
* Don't use %r{} around regex
Updated the state machine to allow multiple current states, to cope with the case where it is ambiguous if the start of an exception is Java or C#
800b860 to
a991faa
Compare
|
Sorry about the force push. I've now restored the original commit as it was at the time of the first review (1df893b). I've now managed to get the C# rules into a separate set of rules (in the most recent commit a991faa). As I mentioned in an earlier comment, I've now had to cope with the fact that it is ambiguous as far as the rules are concerned whether you are seeing a C# or a Java exception. To implement this I've had to support the state machine having more than one possible current state. For example, it might be in either the Unfortunately these changes have made the bench tests around 3 to 4 times slower because the ExceptionDetector.transition method can't exit early once it has found a match. I'm not sure there's much I can do about this - is it preferable to have the cleaner separation of rules with worse performance, or to go back to the mixing of C# and Java-like rules? |
|
I checked how the new C# exceptions looked in error reporting, and it seems it is only the aggregate exception that doesn't get picked up properly. It is actually the other two types of exception I am more interested in getting handled properly, so if it meant this PR could get merged faster I could drop the logic for handling the aggregate exception. What do you think? |
|
@eadred - Thanks for refactoring the code. Now I see why it was challenging to separate As to the |
This was causing too much of a slowdown
Handles multiple inner exceptions
|
Thanks for that. I've now reverted a991faa (as 7fa27c0) and also removed the handling for aggregate exceptions (58889d3). I've raised an issue with the Error Reporting team for handling AggregateExceptions - https://issuetracker.google.com/issues/139292720. PS. I realised that my handling of aggregate exceptions wasn't dealing with the case where there are multiple inner exceptions, so I did put in a fix for that (6ea0cb7). Although this has all been reverted anyway, I may want to re-add these changes in a future PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
Thanks @eadred! This looks good to me. Seems like there are still pending comments from @igorpeshansky. He is on vacation and will be back on Monday (Aug 19). Is this something that can wait or is it urgent? |
|
Thanks @qingling128. No problem if this is delayed - it isn't urgent. |
|
Cool, thanks. Will wait for @igorpeshansky to take a second look once he's back. |
| rule(:java_after_exception, /^[\r\n]*$/, :java_after_exception), | ||
| rule([:java_after_exception, :java], /^[\t ]+(?:eval )?at /, :java), | ||
|
|
||
| # C# nested exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this comment to the line right before the regexp, and add the trailing ".".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| /^[\t ]+--- End of inner exception stack trace ---/, | ||
| :java), | ||
|
|
||
| # C# exception from async code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this comment to the line right before the regexp, and add the trailing ".".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
|
||
| # C# exception from async code | ||
| rule([:java_after_exception, :java], | ||
| /^---\sEnd\sof\sstack\strace\sfrom\sprevious\s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These \s all over the place are hard to read. They seem to be imposed by the use of /x. If so, we may be better off turning the x option on locally, e.g.:
rule([:java_after_exception, :java],
/^--- End of stack trace from previous (?x:
)location where exception was thrown ---/,
:java),Alternatively, you could use \ instead of \s, as we do in the first PHP rule below, though I find that less readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done as per the former suggestion.
|
|
||
| # C# nested exception | ||
| rule([:java_after_exception, :java], | ||
| /^[\t ]+--- End of inner exception stack trace ---/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need a trailing $?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
| # C# exception from async code | ||
| rule([:java_after_exception, :java], | ||
| /^---\sEnd\sof\sstack\strace\sfrom\sprevious\s | ||
| location\swhere\sexception\swas\sthrown\s---/x, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need a trailing $?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
|
|
||
| # C# aggregate exception | ||
| rule([:java_after_exception, :java], | ||
| /^---> \(Inner Exception #[0-9]+\)/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the problem here. The Java state machine could use a lot of improvement, but that's way beyond the scope of this PR, so what you have is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM ![]()
|
@igorpeshansky Could you release a new version for this issue? |
|
I'll work with our oncall @davidbtucker to do a release. |
|
Sent #65. |
Uh oh!
There was an error while loading. Please reload this page.