├── .editorconfig ├── .gitattributes ├── .gitignore ├── COPYING.txt ├── Public.cs ├── README.md ├── StackTraceParser.cs ├── StackTraceParser.csproj ├── StackTraceParser.sln ├── StackTraceParserTests.cs └── global.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 11 | indent_size = 2 12 | 13 | [*.{sln}] 14 | indent_style = tab 15 | 16 | [*.{json,yml}] 17 | indent_size = 2 18 | 19 | [*.{cs,tt}] 20 | charset = utf-8 21 | indent_style = space 22 | indent_size = 4 23 | max_line_length = 100 24 | 25 | [*.cs] 26 | # Prefer "var" everywhere 27 | csharp_style_var_for_built_in_types = true:suggestion 28 | csharp_style_var_when_type_is_apparent = true:suggestion 29 | csharp_style_var_elsewhere = true:suggestion 30 | 31 | # Prefer method-like constructs to have a block body 32 | csharp_style_expression_bodied_methods = false:none 33 | csharp_style_expression_bodied_constructors = false:none 34 | csharp_style_expression_bodied_operators = false:none 35 | 36 | # Prefer property-like constructs to have an expression-body 37 | csharp_style_expression_bodied_properties = true:none 38 | csharp_style_expression_bodied_indexers = true:none 39 | csharp_style_expression_bodied_accessors = true:none 40 | 41 | # Suggest more modern language features when available 42 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 43 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 44 | csharp_style_inlined_variable_declaration = true:suggestion 45 | csharp_style_throw_expression = true:suggestion 46 | csharp_style_conditional_delegate_call = true:suggestion 47 | csharp_prefer_simple_default_expression = true:suggestion 48 | 49 | # Spacing 50 | csharp_space_after_cast = false 51 | csharp_space_after_keywords_in_control_flow_statements = true 52 | csharp_space_between_method_declaration_parameter_list_parentheses = false 53 | 54 | # Wrapping 55 | csharp_preserve_single_line_statements = true 56 | csharp_preserve_single_line_blocks = true 57 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # Visual Studio 2015 cache/options directory 11 | .vs/ 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Roslyn cache directories 26 | *.ide/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | #NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | sql/ 155 | *.Cache 156 | ClientBin/ 157 | [Ss]tyle[Cc]op.* 158 | ~$* 159 | *~ 160 | *.dbmdl 161 | *.dbproj.schemaview 162 | *.pfx 163 | *.publishsettings 164 | node_modules/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # ========================= 190 | # Operating System Files 191 | # ========================= 192 | 193 | # OSX 194 | # ========================= 195 | 196 | .DS_Store 197 | .AppleDouble 198 | .LSOverride 199 | 200 | # Thumbnails 201 | ._* 202 | 203 | # Files that might appear on external disk 204 | .Spotlight-V100 205 | .Trashes 206 | 207 | # Directories potentially created on remote AFP share 208 | .AppleDB 209 | .AppleDesktop 210 | Network Trash Folder 211 | Temporary Items 212 | .apdisk 213 | 214 | # Windows 215 | # ========================= 216 | 217 | # Windows image file caches 218 | Thumbs.db 219 | ehthumbs.db 220 | 221 | # Folder config file 222 | Desktop.ini 223 | 224 | # Recycle Bin used on file shares 225 | $RECYCLE.BIN/ 226 | 227 | # Windows Installer files 228 | *.cab 229 | *.msi 230 | *.msm 231 | *.msp 232 | 233 | # Windows shortcuts 234 | *.lnk 235 | *.pp 236 | 237 | # Packaging 238 | /dist/** 239 | *.pp 240 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /Public.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace Elmah { public static partial class StackTraceParser { } } 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stack Trace Parser 2 | 3 | StackTraceParser is a single C# function that can parse a stack trace text 4 | output (e.g. typically returned by [`Environment.StackTrace`][envst] or 5 | [`Exception.StackTrace`][exst]) back into a sequence of stack trace frames, 6 | including the following components: 7 | 8 | - Type 9 | - Method 10 | - Parameter types and names 11 | - File and line information, if present 12 | 13 | It is available as a [NuGet *source* package][srcpkg] that directly embeds into 14 | a C# project. 15 | 16 | ## Usage 17 | 18 | `StackTraceParser` has a single function called `Parse` that takes the source 19 | text to parse and a number of functions to project/construct each component of 20 | a stack frame as it is parsed: 21 | 22 | ```c# 23 | public static IEnumerable Parse( 24 | string text, 25 | Func tokenSelector, 26 | Func methodSelector, 27 | Func parameterSelector, 28 | Func, TParameters> parametersSelector, 29 | Func sourceLocationSelector, 30 | Func selector) 31 | ``` 32 | 33 | Here is one example of how you would call it: 34 | 35 | ```c# 36 | var result = StackTraceParser.Parse( 37 | Environment.StackTrace, 38 | (idx, len, txt) => new // the token is the smallest unit, made of: 39 | { 40 | Index = idx, // - the index of the token text start 41 | Length = len, // - the length of the token text 42 | Text = txt, // - the actual token text 43 | }, 44 | (type, method) => new // the method and its declaring type 45 | { 46 | Type = type, 47 | Method = method, 48 | }, 49 | (type, name) => new // this is called back for each parameter with: 50 | { 51 | Type = type, // - the parameter type 52 | Name = name, // - the parameter name 53 | }, 54 | (pl, ps) => new // the parameter list and sequence of parameters 55 | { 56 | List = pl, // - spans all parameters, including parentheses 57 | Parameters = ps, // - sequence of individual parameters 58 | }, 59 | (file, line) => new // source file and line info 60 | { // called back if present 61 | File = file, 62 | Line = line, 63 | }, 64 | (f, tm, p, fl) => new // finally, put all the components of a frame 65 | { // together! The result of the parsing function 66 | Frame = f, // is a sequence of this. 67 | tm.Type, 68 | tm.Method, 69 | ParameterList = p.List, 70 | p.Parameters, 71 | fl.File, 72 | fl.Line, 73 | }); 74 | ``` 75 | 76 | Suppose [`Environment.StackTrace`][envst] returns (produced by running 77 | `Environment.StackTrace` as an expression in [LINQPad][linqpad]): 78 | 79 | at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) 80 | at System.Environment.get_StackTrace() 81 | at UserQuery.RunUserAuthoredQuery() in c:\Users\johndoe\AppData\Local\Temp\LINQPad\_piwdiese\query_dhwxhm.cs:line 33 82 | at LINQPad.ExecutionModel.ClrQueryRunner.Run() 83 | at LINQPad.ExecutionModel.Server.RunQuery(QueryRunner runner) 84 | at LINQPad.ExecutionModel.Server.StartQuery(QueryRunner runner) 85 | at LINQPad.ExecutionModel.Server.<>c__DisplayClass36.b__35() 86 | at LINQPad.ExecutionModel.Server.SingleThreadExecuter.Work() 87 | at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 88 | at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 89 | at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 90 | at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 91 | at System.Threading.ThreadHelper.ThreadStart() 92 | 93 | Parsing it using the `StackTraceParser.Parse` example call shown earlier 94 | will yield the following object graph: 95 | 96 | > [Output][egout] 97 | 98 | If all you care about is the text of each component then you can use a simpler 99 | overload of the `Parse` method: 100 | 101 | ```c# 102 | var result = StackTraceParser.Parse( 103 | Environment.StackTrace, 104 | (f, t, m, pl, ps, fn, ln) => new 105 | { 106 | Frame = f, 107 | Type = t, 108 | Method = m, 109 | ParameterList = pl, 110 | Parameters = ps, 111 | File = fn, 112 | Line = ln, 113 | }); 114 | ``` 115 | 116 | ## Background 117 | 118 | `StackTraceParser` was born as part of the [ELMAH][elmah] project and used to 119 | [color the stack traces][elmaheg], as can be seen from the screenshot below: 120 | 121 | ![ELMAH](http://www.hanselman.com/blog/content/binary/Windows-Live-Writer/NuGet-Package-of-the-Week-7---ELMAH-Erro_B9F2/Error_%20System.Web.HttpException%20%5B30158b95-0112-4081-91ab-c5ec7848a12c%5D%20-%20Windows%20Internet%20Explorer%20(74)_2.png) 122 | 123 | See the [`ErrorDetailPage` source code][errdp] from the ELMAH repo for a real 124 | example of [how the output of `StackTraceParser` was used for marking up the 125 | stack trace in HTML][elmaheg]. 126 | 127 | [envst]: https://msdn.microsoft.com/en-us/library/system.environment.stacktrace(v=vs.110).aspx 128 | [exst]: https://msdn.microsoft.com/en-us/library/system.exception.stacktrace(v=vs.110).aspx 129 | [srcpkg]: https://www.nuget.org/packages/StackTraceParser.Source 130 | [elmah]: https://elmah.github.io/ 131 | [elmaheg]: https://github.com/elmah/Elmah/blob/b1016733fb51a4c9272c81b0ed37d4faa6769d25/src/Elmah.AspNet/ErrorDetailPage.cs#L45-L125 132 | [errdp]: https://github.com/elmah/Elmah/blob/b1016733fb51a4c9272c81b0ed37d4faa6769d25/src/Elmah.AspNet/ErrorDetailPage.cs 133 | [linqpad]: https://www.linqpad.net/ 134 | [egout]: https://atifaziz.github.io/projects/stack-trace-parser/linqpad-example-output.html 135 | -------------------------------------------------------------------------------- /StackTraceParser.cs: -------------------------------------------------------------------------------- 1 | // 2 | #region Copyright (c) 2011 Atif Aziz. All rights reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | #endregion 17 | 18 | // ReSharper disable once CheckNamespace 19 | 20 | namespace Elmah 21 | { 22 | #region Imports 23 | 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Text.RegularExpressions; 28 | 29 | #endregion 30 | 31 | // ReSharper disable once PartialTypeWithSinglePart 32 | 33 | partial class StackTraceParser 34 | { 35 | const string Space = @"[\x20\t]"; 36 | const string NotSpace = @"[^\x20\t]"; 37 | 38 | static readonly Regex Regex = new Regex(@" 39 | ^ 40 | " + Space + @"* 41 | \w+ " + Space + @"+ 42 | (? 43 | (? " + NotSpace + @"+ ) \. 44 | (? " + NotSpace + @"+? ) " + Space + @"* 45 | (? \( ( " + Space + @"* \) 46 | | (? .+?) " + Space + @"+ (? .+?) 47 | (, " + Space + @"* (? .+?) " + Space + @"+ (? .+?) )* \) ) ) 48 | ( " + Space + @"+ 49 | ( # Microsoft .NET stack traces 50 | \w+ " + Space + @"+ 51 | (? ( [a-z] \: # Windows rooted path starting with a drive letter 52 | | / ) # *nix rooted path starting with a forward-slash 53 | .+? ) 54 | \: \w+ " + Space + @"+ 55 | (? [0-9]+ ) \p{P}? 56 | | # Mono stack traces 57 | \[0x[0-9a-f]+\] " + Space + @"+ \w+ " + Space + @"+ 58 | <(? [^>]+ )> 59 | :(? [0-9]+ ) 60 | ) 61 | )? 62 | ) 63 | \s* 64 | $", 65 | RegexOptions.IgnoreCase 66 | | RegexOptions.Multiline 67 | | RegexOptions.ExplicitCapture 68 | | RegexOptions.CultureInvariant 69 | | RegexOptions.IgnorePatternWhitespace 70 | | RegexOptions.Compiled, 71 | // Cap the evaluation time to make it obvious should the expression 72 | // fall into the "catastrophic backtracking" trap due to over 73 | // generalization. 74 | // https://github.com/atifaziz/StackTraceParser/issues/4 75 | TimeSpan.FromSeconds(5)); 76 | 77 | public static IEnumerable Parse( 78 | string text, 79 | Func>, string, string, T> selector) 80 | { 81 | if (selector == null) throw new ArgumentNullException("selector"); 82 | 83 | return Parse(text, (idx, len, txt) => txt, 84 | (t, m) => new { Type = t, Method = m }, 85 | (pt, pn) => new KeyValuePair(pt, pn), 86 | // ReSharper disable once PossibleMultipleEnumeration 87 | (pl, ps) => new { List = pl, Items = ps }, 88 | (fn, ln) => new { File = fn, Line = ln }, 89 | (f, tm, p, fl) => selector(f, tm.Type, tm.Method, p.List, p.Items, fl.File, fl.Line)); 90 | } 91 | 92 | public static IEnumerable Parse( 93 | string text, 94 | Func tokenSelector, 95 | Func methodSelector, 96 | Func parameterSelector, 97 | Func, TParameters> parametersSelector, 98 | Func sourceLocationSelector, 99 | Func selector) 100 | { 101 | if (tokenSelector == null) throw new ArgumentNullException("tokenSelector"); 102 | if (methodSelector == null) throw new ArgumentNullException("methodSelector"); 103 | if (parameterSelector == null) throw new ArgumentNullException("parameterSelector"); 104 | if (parametersSelector == null) throw new ArgumentNullException("parametersSelector"); 105 | if (sourceLocationSelector == null) throw new ArgumentNullException("sourceLocationSelector"); 106 | if (selector == null) throw new ArgumentNullException("selector"); 107 | 108 | return from Match m in Regex.Matches(text) 109 | select m.Groups into groups 110 | let pt = groups["pt"].Captures 111 | let pn = groups["pn"].Captures 112 | select selector(Token(groups["frame"], tokenSelector), 113 | methodSelector( 114 | Token(groups["type"], tokenSelector), 115 | Token(groups["method"], tokenSelector)), 116 | parametersSelector( 117 | Token(groups["params"], tokenSelector), 118 | from i in Enumerable.Range(0, pt.Count) 119 | select parameterSelector(Token(pt[i], tokenSelector), 120 | Token(pn[i], tokenSelector))), 121 | sourceLocationSelector(Token(groups["file"], tokenSelector), 122 | Token(groups["line"], tokenSelector))); 123 | } 124 | 125 | static T Token(Capture capture, Func tokenSelector) 126 | { 127 | return tokenSelector(capture.Index, capture.Length, capture.Value); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /StackTraceParser.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452 5 | true 6 | $(NoWarn);NU5128;NU5105 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | true 16 | StackTraceParser.Source 17 | StackTraceParser (C# Source) 18 | stack;trace;parser;diagnostics;exception 19 | Parser for .NET and Mono stack traces. 20 | Copyright © 2011 Atif Aziz. All rights reserved. 21 | 1.3.1 22 | Atif Aziz 23 | Apache-2.0 24 | en-us 25 | false 26 | https://github.com/atifaziz/StackTraceParser 27 | https://github.com/atifaziz/StackTraceParser.git 28 | git 29 | .\dist 30 | See https://github.com/atifaziz/StackTraceParser/releases/tag/v1.3.1 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 62 | 63 | 64 | 65 | 66 | <_PackageFiles Include="StackTraceParser.cs.pp"> 67 | Compile 68 | content\App_Packages\StackTraceParser\;contentFiles\cs\any\StackTraceParser\ 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /StackTraceParser.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30711.63 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackTraceParser", "StackTraceParser.csproj", "{4658EDD5-D30A-44EB-9CA5-8E43F83481D6}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D87432AC-4056-4B7F-8292-51376C6BE965}" 9 | ProjectSection(SolutionItems) = preProject 10 | COPYING.txt = COPYING.txt 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {4658EDD5-D30A-44EB-9CA5-8E43F83481D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {4658EDD5-D30A-44EB-9CA5-8E43F83481D6}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {4658EDD5-D30A-44EB-9CA5-8E43F83481D6}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {4658EDD5-D30A-44EB-9CA5-8E43F83481D6}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {DF8949F0-59AA-4D45-BA4C-B23A44D226DA} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /StackTraceParserTests.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011 Atif Aziz. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | #endregion 16 | 17 | // ReSharper disable once CheckNamespace 18 | 19 | namespace Tests 20 | { 21 | #region Imports 22 | 23 | using System; 24 | using System.Linq; 25 | using NUnit.Framework; 26 | using StackTraceParser = Elmah.StackTraceParser; 27 | 28 | #endregion 29 | 30 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 31 | class StackTraceTestCase : TestCaseAttribute 32 | { 33 | public StackTraceTestCase(string stackTrace, int index, string frame) : 34 | base(stackTrace, index, frame) {} 35 | 36 | public StackTraceTestCase(string stackTrace, int index, 37 | string frame, 38 | string type, string method, string parameterList, string parameters, 39 | string file, string line) : 40 | base(stackTrace, index, frame, type, method, parameterList, parameters, file, line) {} 41 | } 42 | 43 | [TestFixture] 44 | public sealed class StackTraceParserTests 45 | { 46 | [Test] 47 | public void ParseWithSimpleOverloadFailsWithNullSelector() 48 | { 49 | var e = Assert.Throws(() => StackTraceParser.Parse(string.Empty, null)); 50 | Assert.That(e.ParamName, Is.EqualTo("selector")); 51 | } 52 | 53 | [Test] 54 | public void ParseFailsWithNullTokenSelector() 55 | { 56 | var e = Assert.Throws(() => 57 | StackTraceParser.Parse( 58 | string.Empty, 59 | null, 60 | delegate { return null; }, 61 | delegate { return null; }, 62 | delegate { return null; }, 63 | delegate { return null; }, 64 | delegate { return null; })); 65 | Assert.That(e.ParamName, Is.EqualTo("tokenSelector")); 66 | } 67 | 68 | [Test] 69 | public void ParseFailsWithNullMethodSelector() 70 | { 71 | var e = Assert.Throws(() => 72 | StackTraceParser.Parse( 73 | string.Empty, 74 | delegate { return null; }, 75 | null, 76 | delegate { return null; }, 77 | delegate { return null; }, 78 | delegate { return null; }, 79 | delegate { return null; })); 80 | Assert.That(e.ParamName, Is.EqualTo("methodSelector")); 81 | } 82 | 83 | [Test] 84 | public void ParseFailsWithNullParameterSelector() 85 | { 86 | var e = Assert.Throws(() => 87 | StackTraceParser.Parse( 88 | string.Empty, 89 | delegate { return null; }, 90 | delegate { return null; }, 91 | null, 92 | delegate { return null; }, 93 | delegate { return null; }, 94 | delegate { return null; })); 95 | Assert.That(e.ParamName, Is.EqualTo("parameterSelector")); 96 | } 97 | 98 | [Test] 99 | public void ParseFailsWithNullParametersSelector() 100 | { 101 | var e = Assert.Throws(() => 102 | StackTraceParser.Parse( 103 | string.Empty, 104 | delegate { return null; }, 105 | delegate { return null; }, 106 | delegate { return null; }, 107 | null, 108 | delegate { return null; }, 109 | delegate { return null; })); 110 | Assert.That(e.ParamName, Is.EqualTo("parametersSelector")); 111 | } 112 | 113 | [Test] 114 | public void ParseFailsWithNullSourceLocationSelector() 115 | { 116 | var e = Assert.Throws(() => 117 | StackTraceParser.Parse( 118 | string.Empty, 119 | delegate { return null; }, 120 | delegate { return null; }, 121 | delegate { return null; }, 122 | delegate { return null; }, 123 | null, 124 | delegate { return null; })); 125 | Assert.That(e.ParamName, Is.EqualTo("sourceLocationSelector")); 126 | } 127 | 128 | [Test] 129 | public void ParseFailsWithNullSelector() 130 | { 131 | var e = Assert.Throws(() => 132 | StackTraceParser.Parse( 133 | string.Empty, 134 | delegate { return null; }, 135 | delegate { return null; }, 136 | delegate { return null; }, 137 | delegate { return null; }, 138 | delegate { return null; }, 139 | null)); 140 | Assert.That(e.ParamName, Is.EqualTo("selector")); 141 | } 142 | 143 | const string DotNetStackTrace = @" 144 | Elmah.TestException: This is a test exception that can be safely ignored. 145 | at Elmah.ErrorLogPageFactory.FindHandler(String name) in C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs:line 126 146 | at Elmah.ErrorLogPageFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated) in C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs:line 66 147 | at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) 148 | at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 149 | at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)"; 150 | 151 | [StackTraceTestCase(DotNetStackTrace, 0, 152 | /* Frame */ @"Elmah.ErrorLogPageFactory.FindHandler(String name) in C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs:line 126", 153 | /* Type */ @"Elmah.ErrorLogPageFactory", 154 | /* Method */ @"FindHandler", 155 | /* ParameterList */ @"(String name)", 156 | /* Parameters */ @"String name", 157 | /* File */ @"C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs", 158 | /* Line */ @"126")] 159 | [StackTraceTestCase(DotNetStackTrace, 1, 160 | /* Frame */ @"Elmah.ErrorLogPageFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated) in C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs:line 66", 161 | /* Type */ @"Elmah.ErrorLogPageFactory", 162 | /* Method */ @"GetHandler", 163 | /* ParameterList */ @"(HttpContext context, String requestType, String url, String pathTranslated)", 164 | /* Parameters */ @"HttpContext context, String requestType, String url, String pathTranslated", 165 | /* File */ @"C:\ELMAH\src\Elmah\ErrorLogPageFactory.cs", 166 | /* Line */ @"66")] 167 | [StackTraceTestCase(DotNetStackTrace, 2, 168 | /* Frame */ @"System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)", 169 | /* Type */ @"System.Web.HttpApplication", 170 | /* Method */ @"MapHttpHandler", 171 | /* ParameterList */ @"(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)", 172 | /* Parameters */ @"HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig", 173 | /* File */ "", 174 | /* Line */ "")] 175 | [StackTraceTestCase(DotNetStackTrace, 3, 176 | /* Frame */ @"System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()", 177 | /* Type */ @"System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep", 178 | /* Method */ @"Execute", 179 | /* ParameterList */ @"()", 180 | /* Parameters */ "", 181 | /* File */ "", 182 | /* Line */ "")] 183 | [StackTraceTestCase(DotNetStackTrace, 4, 184 | /* Frame */ @"System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)", 185 | /* Type */ @"System.Web.HttpApplication", 186 | /* Method */ @"ExecuteStep", 187 | /* ParameterList */ @"(IExecutionStep step, Boolean& completedSynchronously)", 188 | /* Parameters */ @"IExecutionStep step, Boolean& completedSynchronously", 189 | /* File */ "", 190 | /* Line */ "")] 191 | 192 | public void ParseDotNetStackTrace(string stackTrace, int index, 193 | string frame, 194 | string type, string method, string parameterList, string parameters, 195 | string file, string line) 196 | { 197 | Parse(stackTrace, index, frame, type, method, parameterList, parameters, file, line); 198 | } 199 | 200 | const string DotNetStackLinuxTrace = @" 201 | Elmah.TestException: This is a test exception that can be safely ignored. 202 | at Elmah.ErrorLogPageFactory.FindHandler(String name) in /ELMAH/src/Elmah/ErrorLogPageFactory.cs:line 126 203 | at Elmah.ErrorLogPageFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated) in /ELMAH/src/Elmah/ErrorLogPageFactory.cs:line 66 204 | at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) 205 | at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 206 | at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)"; 207 | 208 | [StackTraceTestCase(DotNetStackLinuxTrace, 0, 209 | /* Frame */ @"Elmah.ErrorLogPageFactory.FindHandler(String name) in /ELMAH/src/Elmah/ErrorLogPageFactory.cs:line 126", 210 | /* Type */ @"Elmah.ErrorLogPageFactory", 211 | /* Method */ @"FindHandler", 212 | /* ParameterList */ @"(String name)", 213 | /* Parameters */ @"String name", 214 | /* File */ @"/ELMAH/src/Elmah/ErrorLogPageFactory.cs", 215 | /* Line */ @"126")] 216 | [StackTraceTestCase(DotNetStackLinuxTrace, 1, 217 | /* Frame */ @"Elmah.ErrorLogPageFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated) in /ELMAH/src/Elmah/ErrorLogPageFactory.cs:line 66", 218 | /* Type */ @"Elmah.ErrorLogPageFactory", 219 | /* Method */ @"GetHandler", 220 | /* ParameterList */ @"(HttpContext context, String requestType, String url, String pathTranslated)", 221 | /* Parameters */ @"HttpContext context, String requestType, String url, String pathTranslated", 222 | /* File */ @"/ELMAH/src/Elmah/ErrorLogPageFactory.cs", 223 | /* Line */ @"66")] 224 | [StackTraceTestCase(DotNetStackLinuxTrace, 2, 225 | /* Frame */ @"System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)", 226 | /* Type */ @"System.Web.HttpApplication", 227 | /* Method */ @"MapHttpHandler", 228 | /* ParameterList */ @"(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)", 229 | /* Parameters */ @"HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig", 230 | /* File */ "", 231 | /* Line */ "")] 232 | [StackTraceTestCase(DotNetStackLinuxTrace, 3, 233 | /* Frame */ @"System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()", 234 | /* Type */ @"System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep", 235 | /* Method */ @"Execute", 236 | /* ParameterList */ @"()", 237 | /* Parameters */ "", 238 | /* File */ "", 239 | /* Line */ "")] 240 | [StackTraceTestCase(DotNetStackLinuxTrace, 4, 241 | /* Frame */ @"System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)", 242 | /* Type */ @"System.Web.HttpApplication", 243 | /* Method */ @"ExecuteStep", 244 | /* ParameterList */ @"(IExecutionStep step, Boolean& completedSynchronously)", 245 | /* Parameters */ @"IExecutionStep step, Boolean& completedSynchronously", 246 | /* File */ "", 247 | /* Line */ "")] 248 | 249 | public void ParseDotNetLinuxStackTrace(string stackTrace, int index, 250 | string frame, 251 | string type, string method, string parameterList, string parameters, 252 | string file, string line) 253 | { 254 | Parse(stackTrace, index, frame, type, method, parameterList, parameters, file, line); 255 | } 256 | 257 | // See https://github.com/elmah/Elmah/issues/320 258 | 259 | const string MonoStackTrace = @" 260 | System.Web.HttpException: The controller for path '/helloworld' was not found or does not implement IController. 261 | at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance (System.Web.Routing.RequestContext requestContext, System.Type controllerType) [0x00000] in :0 262 | at System.Web.Mvc.DefaultControllerFactory.CreateController (System.Web.Routing.RequestContext requestContext, System.String controllerName) [0x00000] in :0 263 | at System.Web.Mvc.MvcHandler.ProcessRequestInit (System.Web.HttpContextBase httpContext, IController& controller, IControllerFactory& factory) [0x00000] in :0 264 | at System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContextBase httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in :0 265 | at System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContext httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in :0 266 | at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest (System.Web.HttpContext context, System.AsyncCallback cb, System.Object extraData) [0x00000] in :0 267 | at System.Web.HttpApplication+c__Iterator3.MoveNext () [0x00000] in :0"; 268 | const string Zero = "0"; 269 | const string FilenameUnknown = "filename unknown"; 270 | 271 | [StackTraceTestCase(MonoStackTrace, 0, 272 | /* Frame */ "System.Web.Mvc.DefaultControllerFactory.GetControllerInstance (System.Web.Routing.RequestContext requestContext, System.Type controllerType) [0x00000] in :0", 273 | /* Type */ "System.Web.Mvc.DefaultControllerFactory", 274 | /* Method */ "GetControllerInstance", 275 | /* ParameterList */ "(System.Web.Routing.RequestContext requestContext, System.Type controllerType)", 276 | /* Parameters */ "System.Web.Routing.RequestContext requestContext, System.Type controllerType", 277 | FilenameUnknown, Zero)] 278 | [StackTraceTestCase(MonoStackTrace, 1, 279 | /* Frame */ "System.Web.Mvc.DefaultControllerFactory.CreateController (System.Web.Routing.RequestContext requestContext, System.String controllerName) [0x00000] in :0", 280 | /* Type */ "System.Web.Mvc.DefaultControllerFactory", 281 | /* Method */ "CreateController", 282 | /* ParameterList */ "(System.Web.Routing.RequestContext requestContext, System.String controllerName)", 283 | /* Parameters */ "System.Web.Routing.RequestContext requestContext, System.String controllerName", 284 | FilenameUnknown, Zero)] 285 | [StackTraceTestCase(MonoStackTrace, 2, 286 | /* Frame */ "System.Web.Mvc.MvcHandler.ProcessRequestInit (System.Web.HttpContextBase httpContext, IController& controller, IControllerFactory& factory) [0x00000] in :0", 287 | /* Type */ "System.Web.Mvc.MvcHandler", 288 | /* Method */ "ProcessRequestInit", 289 | /* ParameterList */ "(System.Web.HttpContextBase httpContext, IController& controller, IControllerFactory& factory)", 290 | /* Parameters */ "System.Web.HttpContextBase httpContext, IController& controller, IControllerFactory& factory", 291 | FilenameUnknown, Zero)] 292 | [StackTraceTestCase(MonoStackTrace, 3, 293 | /* Frame */ "System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContextBase httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in :0", 294 | /* Type */ "System.Web.Mvc.MvcHandler", 295 | /* Method */ "BeginProcessRequest", 296 | /* ParameterList */ "(System.Web.HttpContextBase httpContext, System.AsyncCallback callback, System.Object state)", 297 | /* Parameters */ "System.Web.HttpContextBase httpContext, System.AsyncCallback callback, System.Object state", 298 | FilenameUnknown, Zero)] 299 | [StackTraceTestCase(MonoStackTrace, 4, 300 | /* Frame */ "System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContext httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in :0", 301 | /* Type */ "System.Web.Mvc.MvcHandler", 302 | /* Method */ "BeginProcessRequest", 303 | /* ParameterList */ "(System.Web.HttpContext httpContext, System.AsyncCallback callback, System.Object state)", 304 | /* Parameters */ "System.Web.HttpContext httpContext, System.AsyncCallback callback, System.Object state", 305 | FilenameUnknown, Zero)] 306 | [StackTraceTestCase(MonoStackTrace, 5, 307 | /* Frame */ "System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest (System.Web.HttpContext context, System.AsyncCallback cb, System.Object extraData) [0x00000] in :0", 308 | /* Type */ "System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler", 309 | /* Method */ "BeginProcessRequest", 310 | /* ParameterList */ "(System.Web.HttpContext context, System.AsyncCallback cb, System.Object extraData)", 311 | /* Parameters */ "System.Web.HttpContext context, System.AsyncCallback cb, System.Object extraData", 312 | FilenameUnknown, Zero)] 313 | [StackTraceTestCase(MonoStackTrace, 6, 314 | /* Frame */ "System.Web.HttpApplication+c__Iterator3.MoveNext () [0x00000] in :0", 315 | /* Type */ "System.Web.HttpApplication+c__Iterator3", 316 | /* Method */ "MoveNext", 317 | /* ParameterList */ "()", 318 | /* Parameters */ "", 319 | FilenameUnknown, Zero)] 320 | 321 | public void ParseMonoStackTrace(string stackTrace, int index, 322 | string frame, 323 | string type, string method, string parameterList, string parameters, 324 | string file, string line) 325 | { 326 | Parse(stackTrace, index, frame, type, method, parameterList, parameters, file, line); 327 | } 328 | 329 | // Tests bug reported in issue #2: 330 | // https://github.com/atifaziz/StackTraceParser/issues/2 331 | 332 | const string SpaceBugStackTrace = @" 333 | System.Web.HttpUnhandledException (0x80004005): Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.ArgumentException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). 334 | Parameter name: 9f567029-a6c4-4232-bab0-177ab8d5a67x ---> System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). 335 | at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException) 336 | at System.Guid.TryParseGuidWithDashes(String guidString, GuidResult& result) 337 | at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result) 338 | at System.Guid..ctor(String g) 339 | at Elmah.XmlFileErrorLog.GetError(String id) 340 | --- End of inner exception stack trace --- 341 | at Elmah.XmlFileErrorLog.GetError(String id) 342 | at Elmah.ErrorDetailPage.OnLoad(EventArgs e) 343 | at System.Web.UI.Control.LoadRecursive() 344 | at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 345 | at System.Web.UI.Page.HandleError(Exception e) 346 | at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 347 | at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 348 | at System.Web.UI.Page.ProcessRequest() 349 | at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) 350 | at System.Web.UI.Page.ProcessRequest(HttpContext context) 351 | at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 352 | at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)"; 353 | 354 | [StackTraceTestCase(SpaceBugStackTrace, 00, @"System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException)")] 355 | [StackTraceTestCase(SpaceBugStackTrace, 01, @"System.Guid.TryParseGuidWithDashes(String guidString, GuidResult& result)")] 356 | [StackTraceTestCase(SpaceBugStackTrace, 02, @"System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)")] 357 | [StackTraceTestCase(SpaceBugStackTrace, 03, @"System.Guid..ctor(String g)")] 358 | [StackTraceTestCase(SpaceBugStackTrace, 04, @"Elmah.XmlFileErrorLog.GetError(String id)")] 359 | [StackTraceTestCase(SpaceBugStackTrace, 05, @"Elmah.XmlFileErrorLog.GetError(String id)")] 360 | [StackTraceTestCase(SpaceBugStackTrace, 06, @"Elmah.ErrorDetailPage.OnLoad(EventArgs e)")] 361 | [StackTraceTestCase(SpaceBugStackTrace, 07, @"System.Web.UI.Control.LoadRecursive()")] 362 | [StackTraceTestCase(SpaceBugStackTrace, 08, @"System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)")] 363 | [StackTraceTestCase(SpaceBugStackTrace, 09, @"System.Web.UI.Page.HandleError(Exception e)")] 364 | [StackTraceTestCase(SpaceBugStackTrace, 10, @"System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)")] 365 | [StackTraceTestCase(SpaceBugStackTrace, 11, @"System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)")] 366 | [StackTraceTestCase(SpaceBugStackTrace, 12, @"System.Web.UI.Page.ProcessRequest()")] 367 | [StackTraceTestCase(SpaceBugStackTrace, 13, @"System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)")] 368 | [StackTraceTestCase(SpaceBugStackTrace, 14, @"System.Web.UI.Page.ProcessRequest(HttpContext context)")] 369 | [StackTraceTestCase(SpaceBugStackTrace, 15, @"System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()")] 370 | [StackTraceTestCase(SpaceBugStackTrace, 16, @"System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)")] 371 | public void ParseSpaceBugStackTrace(string stackTrace, int index, string frame) 372 | { 373 | Parse(stackTrace, index, frame); 374 | } 375 | 376 | // Tests bug reported in issue #4: 377 | // https://github.com/atifaziz/StackTraceParser/issues/4 378 | 379 | const string RunawayBugStackTrace = @" 380 | NHibernate.Exceptions.GenericADOException: Failed to execute multi query[SQL: select codingques0_.Id as Id2_0_, choicename1_.TextID as TextID130_1_, choicename1_.LanguageID as LanguageID130_1_, codingques0_.VersionStamp as VersionS2_2_0_, codingques0_.CreatedBy as CreatedBy2_0_, codingques0_.CreatedDateTime as CreatedD4_2_0_, codingques0_.LastUpdateBy as LastUpda5_2_0_, codingques0_.LastUpdateDateTime as LastUpda6_2_0_, codingques0_.CodingQuestionID as CodingQu7_2_0_, codingques0_.TreeID as TreeID2_0_, codingques0_.CodingSpec as CodingSpec2_0_, codingques0_.ClassificationKeywordID as Classif10_2_0_, codingques0_.ChoiceTextLTID as ChoiceT11_2_0_, codingques0_.PositionIndex as Positio12_2_0_, codingques0_.CodingValue as CodingV13_2_0_, codingques0_.ChoiceNumber as ChoiceN14_2_0_, codingques0_.[TreeID].GetLevel() as formula1_0_, (select case when exists(select 1 from Survey.CodingQuestionChoice a where a.CodingQuestionID = codingques0_.CodingQuestionID and a.TreeID.GetAncestor(1) = codingques0_.TreeID) then 1 else 0 end) as formula2_0_, choicename1_.LocalizedText as Localize3_130_1_, choicename1_.TextID as TextID0__, choicename1_.LanguageID as LanguageID0__ from Survey.CodingQuestionChoice codingques0_ left outer join Administration.LocalizedTextSequenced choicename1_ on codingques0_.ChoiceTextLTID=choicename1_.TextID where codingques0_.CodingQuestionID=?; 381 | select codingques0_.Id as Id2_0_, codingques1_.ID as ID3_1_, codingques0_.VersionStamp as VersionS2_2_0_, codingques0_.CreatedBy as CreatedBy2_0_, codingques0_.CreatedDateTime as CreatedD4_2_0_, codingques0_.LastUpdateBy as LastUpda5_2_0_, codingques0_.LastUpdateDateTime as LastUpda6_2_0_, codingques0_.CodingQuestionID as CodingQu7_2_0_, codingques0_.TreeID as TreeID2_0_, codingques0_.CodingSpec as CodingSpec2_0_, codingques0_.ClassificationKeywordID as Classif10_2_0_, codingques0_.ChoiceTextLTID as ChoiceT11_2_0_, codingques0_.PositionIndex as Positio12_2_0_, codingques0_.CodingValue as CodingV13_2_0_, codingques0_.ChoiceNumber as ChoiceN14_2_0_, codingques0_.[TreeID].GetLevel() as formula1_0_, (select case when exists(select 1 from Survey.CodingQuestionChoice a where a.CodingQuestionID = codingques0_.CodingQuestionID and a.TreeID.GetAncestor(1) = codingques0_.TreeID) then 1 else 0 end) as formula2_0_, codingques1_.VersionStamp as VersionS2_3_1_, codingques1_.CodingQuestionChoiceID as CodingQu3_3_1_, codingques1_.StringPath as StringPath3_1_, codingques1_.StartCodingValue as StartCod5_3_1_, codingques1_.EndCodingValue as EndCodin6_3_1_, codingques1_.CodingSpec as CodingSpec3_1_, codingques1_.CreatedBy as CreatedBy3_1_, codingques1_.CreatedDateTime as CreatedD9_3_1_, codingques1_.LastUpdateBy as LastUpd10_3_1_, codingques1_.LastUpdateDateTime as LastUpd11_3_1_, codingques1_.CodingQuestionChoiceID as CodingQu3_0__, codingques1_.ID as ID0__ from Survey.CodingQuestionChoice codingques0_ left outer join Survey.CodingQuestionChoiceCodingRange codingques1_ on codingques0_.Id=codingques1_.CodingQuestionChoiceID where codingques0_.CodingQuestionID=?; 382 | ] ---> System.IO.FileLoadException: Could not load file or assembly 'Microsoft.SqlServer.Types, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) 383 | at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) 384 | at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) 385 | at System.Reflection.Assembly.Load(AssemblyName assemblyRef) 386 | at System.Data.SqlClient.SqlConnection.ResolveTypeAssembly(AssemblyName asmRef, Boolean throwOnError) 387 | at System.TypeNameParser.ResolveAssembly(String asmName, Func`2 assemblyResolver, Boolean throwOnError, StackCrawlMark& stackMark) 388 | at System.TypeNameParser.ConstructType(Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError, Boolean ignoreCase, StackCrawlMark& stackMark) 389 | at System.TypeNameParser.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError, Boolean ignoreCase, StackCrawlMark& stackMark) 390 | at System.Type.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError) 391 | at System.Data.SqlClient.SqlConnection.CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, Boolean fThrow) 392 | at System.Data.SqlClient.SqlDataReader.GetValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData metaData) 393 | at System.Data.SqlClient.SqlDataReader.GetValue(Int32 i) 394 | at NHibernate.Type.AbstractStringType.Get(IDataReader rs, Int32 index) 395 | at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name) 396 | at NHibernate.Persister.Entity.AbstractEntityPersister.Hydrate(IDataReader rs, Object id, Object obj, ILoadable rootLoadable, String[][] suffixedPropertyColumns, Boolean allProperties, ISessionImplementor session) 397 | at NHibernate.Loader.Loader.LoadFromResultSet(IDataReader rs, Int32 i, Object obj, String instanceClass, EntityKey key, String rowIdAlias, LockMode lockMode, ILoadable rootPersister, ISessionImplementor session) 398 | at NHibernate.Loader.Loader.InstanceNotYetLoaded(IDataReader dr, Int32 i, ILoadable persister, EntityKey key, LockMode lockMode, String rowIdAlias, EntityKey optionalObjectKey, Object optionalObject, IList hydratedObjects, ISessionImplementor session) 399 | at NHibernate.Loader.Loader.GetRow(IDataReader rs, ILoadable[] persisters, EntityKey[] keys, Object optionalObject, EntityKey optionalObjectKey, LockMode[] lockModes, IList hydratedObjects, ISessionImplementor session) 400 | at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies, IResultTransformer forcedResultTransformer) 401 | at NHibernate.Impl.MultiQueryImpl.DoList()"; 402 | 403 | [StackTraceTestCase(RunawayBugStackTrace, 00, @"System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)")] 404 | [StackTraceTestCase(RunawayBugStackTrace, 01, @"System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)")] 405 | [StackTraceTestCase(RunawayBugStackTrace, 02, @"System.Reflection.Assembly.Load(AssemblyName assemblyRef)")] 406 | [StackTraceTestCase(RunawayBugStackTrace, 03, @"System.Data.SqlClient.SqlConnection.ResolveTypeAssembly(AssemblyName asmRef, Boolean throwOnError)")] 407 | [StackTraceTestCase(RunawayBugStackTrace, 04, @"System.TypeNameParser.ResolveAssembly(String asmName, Func`2 assemblyResolver, Boolean throwOnError, StackCrawlMark& stackMark)")] 408 | [StackTraceTestCase(RunawayBugStackTrace, 05, @"System.TypeNameParser.ConstructType(Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError, Boolean ignoreCase, StackCrawlMark& stackMark)")] 409 | [StackTraceTestCase(RunawayBugStackTrace, 06, @"System.TypeNameParser.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError, Boolean ignoreCase, StackCrawlMark& stackMark)")] 410 | [StackTraceTestCase(RunawayBugStackTrace, 07, @"System.Type.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError)")] 411 | [StackTraceTestCase(RunawayBugStackTrace, 08, @"System.Data.SqlClient.SqlConnection.CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, Boolean fThrow)")] 412 | [StackTraceTestCase(RunawayBugStackTrace, 09, @"System.Data.SqlClient.SqlDataReader.GetValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData metaData)")] 413 | [StackTraceTestCase(RunawayBugStackTrace, 10, @"System.Data.SqlClient.SqlDataReader.GetValue(Int32 i)")] 414 | [StackTraceTestCase(RunawayBugStackTrace, 11, @"NHibernate.Type.AbstractStringType.Get(IDataReader rs, Int32 index)")] 415 | [StackTraceTestCase(RunawayBugStackTrace, 12, @"NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name)")] 416 | [StackTraceTestCase(RunawayBugStackTrace, 13, @"NHibernate.Persister.Entity.AbstractEntityPersister.Hydrate(IDataReader rs, Object id, Object obj, ILoadable rootLoadable, String[][] suffixedPropertyColumns, Boolean allProperties, ISessionImplementor session)")] 417 | [StackTraceTestCase(RunawayBugStackTrace, 14, @"NHibernate.Loader.Loader.LoadFromResultSet(IDataReader rs, Int32 i, Object obj, String instanceClass, EntityKey key, String rowIdAlias, LockMode lockMode, ILoadable rootPersister, ISessionImplementor session)")] 418 | [StackTraceTestCase(RunawayBugStackTrace, 15, @"NHibernate.Loader.Loader.InstanceNotYetLoaded(IDataReader dr, Int32 i, ILoadable persister, EntityKey key, LockMode lockMode, String rowIdAlias, EntityKey optionalObjectKey, Object optionalObject, IList hydratedObjects, ISessionImplementor session)")] 419 | [StackTraceTestCase(RunawayBugStackTrace, 16, @"NHibernate.Loader.Loader.GetRow(IDataReader rs, ILoadable[] persisters, EntityKey[] keys, Object optionalObject, EntityKey optionalObjectKey, LockMode[] lockModes, IList hydratedObjects, ISessionImplementor session)")] 420 | [StackTraceTestCase(RunawayBugStackTrace, 17, @"NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies, IResultTransformer forcedResultTransformer)")] 421 | [StackTraceTestCase(RunawayBugStackTrace, 18, @"NHibernate.Impl.MultiQueryImpl.DoList()")] 422 | public void ParseRunawayBugStackTrace(string stackTrace, int index, string frame) 423 | { 424 | Parse(stackTrace, index, frame); 425 | } 426 | 427 | static void Parse(string stackTrace, int index, 428 | string frame, 429 | string type, string method, string parameterList, string parameters, 430 | string file, string line) 431 | { 432 | var actuals = StackTraceParser.Parse(stackTrace, 433 | (f, t, m, pl, ps, fn, ln) => new 434 | { 435 | Frame = f, 436 | Type = t, 437 | Method = m, 438 | ParameterList = pl, 439 | Parameters = string.Join(", ", from e in ps select e.Key + " " + e.Value), 440 | File = fn, 441 | Line = ln, 442 | }); 443 | 444 | var actual = actuals.ElementAt(index); 445 | 446 | Assert.That(frame , Is.EqualTo(actual.Frame) , "Frame"); 447 | Assert.That(type , Is.EqualTo(actual.Type) , "Type"); 448 | Assert.That(method , Is.EqualTo(actual.Method) , "Method"); 449 | Assert.That(parameterList, Is.EqualTo(actual.ParameterList), "ParameterList"); 450 | Assert.That(parameters , Is.EqualTo(actual.Parameters) , "Parameters"); 451 | Assert.That(file , Is.EqualTo(actual.File) , "File"); 452 | Assert.That(line , Is.EqualTo(actual.Line) , "Line"); 453 | } 454 | 455 | static void Parse(string stackTrace, int index, string frame) 456 | { 457 | var actuals = StackTraceParser.Parse(stackTrace, 458 | (f, t, m, pl, ps, fn, ln) => f); 459 | 460 | var actual = actuals.ElementAt(index); 461 | 462 | Assert.That(frame, Is.EqualTo(actual)); 463 | } 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "5.0.100", 4 | "rollForward": "minor" 5 | } 6 | } 7 | --------------------------------------------------------------------------------