mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-10-31 09:09:25 +08:00 
			
		
		
		
	Fix parsing of exceptions on .NET Framework
On .NET Framework, `exception.ToString()` uses a slightly different format than on .NET Core. So in order to properly transform an `Exception` into an `ExceptionInfo` on both .NET Core and .NET Framework we use `exception.StackTrace` + `exception.InnerException`. As an added benefit, it greatly simplifies the implementation of the `ExceptionParser` class.
This commit is contained in:
		 Cédric Luthi
					Cédric Luthi
				
			
				
					committed by
					
						 Patrik Svensson
						Patrik Svensson
					
				
			
			
				
	
			
			
			 Patrik Svensson
						Patrik Svensson
					
				
			
						parent
						
							bf95564ebb
						
					
				
				
					commit
					e081593012
				
			| @@ -14,11 +14,7 @@ namespace Spectre.Console | ||||
|                 throw new ArgumentNullException(nameof(exception)); | ||||
|             } | ||||
|  | ||||
|             var info = ExceptionParser.Parse(exception.ToString()); | ||||
|             if (info == null) | ||||
|             { | ||||
|                 return new Text(exception.ToString()); | ||||
|             } | ||||
|             var info = ExceptionParser.Parse(exception); | ||||
|  | ||||
|             return GetException(info, settings); | ||||
|         } | ||||
|   | ||||
| @@ -1,90 +1,27 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     internal static class ExceptionParser | ||||
|     { | ||||
|         private static readonly Regex _messageRegex = new Regex(@"^(?'type'.*):\s(?'message'.*)$"); | ||||
|         private static readonly Regex _stackFrameRegex = new Regex(@"^\s*\w*\s(?'method'.*)\((?'params'.*)\)"); | ||||
|         private static readonly Regex _fullStackFrameRegex = new Regex(@"^\s*(?'at'\w*)\s(?'method'.*)\((?'params'.*)\)\s(?'in'\w*)\s(?'path'.*)\:(?'line'\w*)\s(?'linenumber'\d*)$"); | ||||
|  | ||||
|         public static ExceptionInfo? Parse(string exception) | ||||
|         public static ExceptionInfo Parse(Exception exception) | ||||
|         { | ||||
|             if (exception is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(exception)); | ||||
|             } | ||||
|  | ||||
|             var lines = exception.SplitLines(); | ||||
|             return Parse(new Queue<string>(lines)); | ||||
|         } | ||||
|  | ||||
|         private static ExceptionInfo? Parse(Queue<string> lines) | ||||
|         { | ||||
|             if (lines.Count == 0) | ||||
|             { | ||||
|                 // Error: No lines to parse | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             var line = lines.Dequeue(); | ||||
|             line = line.ReplaceExact(" ---> ", string.Empty); | ||||
|  | ||||
|             var match = _messageRegex.Match(line); | ||||
|             if (!match.Success) | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             var inner = (ExceptionInfo?)null; | ||||
|  | ||||
|             // Stack frames | ||||
|             var frames = new List<StackFrameInfo>(); | ||||
|             while (lines.Count > 0) | ||||
|             { | ||||
|                 if (lines.Peek().TrimStart().StartsWith("---> ", StringComparison.OrdinalIgnoreCase)) | ||||
|                 { | ||||
|                     inner = Parse(lines); | ||||
|                     if (inner == null) | ||||
|                     { | ||||
|                         // Error: Could not parse inner exception | ||||
|                         return null; | ||||
|                     } | ||||
|  | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 line = lines.Dequeue(); | ||||
|  | ||||
|                 if (string.IsNullOrWhiteSpace(line)) | ||||
|                 { | ||||
|                     // Empty line | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if (line.TrimStart().StartsWith("--- ", StringComparison.OrdinalIgnoreCase)) | ||||
|                 { | ||||
|                     // End of inner exception | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 var stackFrame = ParseStackFrame(line); | ||||
|                 if (stackFrame == null) | ||||
|                 { | ||||
|                     // Error: Could not parse stack frame | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
|                 frames.Add(stackFrame); | ||||
|             } | ||||
|  | ||||
|             return new ExceptionInfo( | ||||
|                 match.Groups["type"].Value, | ||||
|                 match.Groups["message"].Value, | ||||
|                 frames, inner); | ||||
|             var exceptionType = exception.GetType(); | ||||
|             var frames = exception.StackTrace?.SplitLines().Select(ParseStackFrame).Where(e => e != null).Cast<StackFrameInfo>().ToList() ?? new List<StackFrameInfo>(); | ||||
|             var inner = exception.InnerException is null ? null : Parse(exception.InnerException); | ||||
|             return new ExceptionInfo(exceptionType.FullName ?? exceptionType.Name, exception.Message, frames, inner); | ||||
|         } | ||||
|  | ||||
|         private static StackFrameInfo? ParseStackFrame(string frame) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user