使用.net中用户错误报告的行号重新创建堆栈跟踪?首先,问题是:我有几个免费项目,任何软件都包含错误。有些用户在遇到错误时会向我发送带有堆栈跟踪的错误报告。为了简化查找??故障所在的过程,我想查看此堆栈跟踪中的行号。如果应用程序没有.pdb文件,那么所有行信息都会丢失,所以目前我所有的项目都部署了一个.pdb文件,所以生成的堆栈跟踪有这个数字。但!但我不想在分发版中看到那些文件,并希望删除所有.pdb。它们使用户感到困惑,占用安装程序空间等。Delphi解决方案:很久以前,当我还是一名Delphi程序员时,我使用了以下技术:Exception我的应用程序遍历堆栈并收集地址。然后,当我收到一个错误报告时,我使用一个工具从收集到的地址和位于我的机器上的相应符号文件中重建一个有效的堆栈跟踪,其中包含函数名和行号。问题:是否有任何库、技术或其他任何东西可以在.NET中做同样的事情?状态更新:非常有趣,经常提问是开始自己调查的最佳方式。例如,这个问题我想了一段时间,但几天前才开始寻找答案。选项1:小型转储。经过大量谷歌搜索后,我找到了一种从代码创建小型转储的方法,以及如何从托管小型转储重新创建堆栈的方法。但是,此解决方案需要重新分配两个额外的组件(大小约为1MB),并且小型转储需要一些空间,并且用户不愿意通过电子邮件发送它们。所以就我的目的而言,现在,这是不可接受的。选项2:感谢weiqure提供的线索。可以为每个堆栈帧提取托管IL偏移量。现在的问题是如何根据这个偏移量从.pdb中获取行号。我的发现:使用这个工具,可以为每个发布版本创建xml文件并将它们放入存储库中。当用户机器上发生异常时,可以创建带有IL偏移量的格式化错误消息。然后用户通过邮件发送此消息(非常小)。最后,可以创建一个简单的工具,从格式化的错误消息中重新创建结果堆栈。我只是想知道为什么没有其他人实施这样的工具?我不相信这只对我有意义。您可以使用System.Diagnostics.StackTrace从异常中获取最后一个MSIL指令的偏移量://UsingSystem.DiagnosticsstaticvoidMain(string[]args){try{ThrowError();}catch(Exceptione){StackTracest=newSystem.Diagnostics.StackTrace(e);字符串stackTrace="";foreach(StackFrameframeinst.GetFrames()){stackTrace="at"+frame.GetMethod().Module.Name+"."+frame.GetMethod().ReflectedType.Name+"."+frame.GetMethod().Name+"(ILoffset:0x"+frame.GetILOffset().ToString("x")+")n"+stackTrace;}Console.Write(stackTrace);Console.WriteLine("消息:"+e.Message);}控制台.ReadLine();}staticvoidThrowError(){DateTimemyDateTime=newDateTime();myDateTime=newDateTime(2000,5555555,1);//不会工作Console.WriteLine(myDateTime.ToString());}输出:在ConsoleApplicationN.exe.Program.Main(IL偏移量:0x7)在ConsoleApplicationN.exe.Program.ThrowError(IL偏移量:0x1b)在mscorlib.dll.DateTime..ctor(IL偏移量:0x9)在mscorlib.dll.DateTime.DateToTicks(我Loffset:0x61)Message:Year,monthanddayparametersdescribeanon-representableDateTime然后你可以使用Reflector或ILSpy来解释偏移量:.methodprivatehidebysigstaticvoidThrowError()cilmanaged{.maxstack4.localsinit([0]值类型[mscorlib]System.DateTimemyDateTime)L_0000:nopL_0001:ldloca.smyDateTimeL_0003:initobj[mscorlib]System.DateTimeL_0009:ldloca.smyDateTimeL_000b:ldc.i40x7d0L_0010:ldc.i463x5:L_00ldc.i4.1L_0016:调用实例void[mscorlib]System.DateTime::.ctor(int32,int32,int32)L_001b:nopL_001c:ldloca.smyDateTimeL_001e:constrained[mscorlib]System.DateTimeL_0024:callvirt实例字符串[mscorlib]System.Object::ToString()L_0029:callvoid[mscorlib]System.Console::WriteLine(string)L_002e:nopL_002f:ret}你知道0x1b之前的指令引发了异常。很容易找到C#代码:myDateTime=newDateTime(2000,5555555,1);您现在可以将IL代码映射到C#代码,但我认为收益太少而且工作量太大(尽管反射器插件是可能的)。IL偏移量应该没问题。您应该使用Environment.FailFast,在Application.UnhandledException中调用FailFast,并为您创建转储文件。来自MSDN:FailFast方法使用消息参数将日志条目写入Windows应用程序事件日志,创建应用程序的转储,然后终止当前进程。如果应用程序的状态损坏到无法修复,请使用FailFast方法而不是Exit方法来终止应用程序,并且执行应用程序的try-finally块和终结器将损坏程序资源。FailFast方法终止当前进程并执行任何CriticalFinalizerObject对象,但不执行任何活动的try-finally块或终结器。您可以编写一个简单的应用程序来收集日志文件并将它们发送给您。现在,打开转储文件有点棘手,VisualStudio无法处理托管转储文件(已在.NET4.0中修复),您可以使用WinDBG,但需要使用SOS。您可以在发生错误时创建应用程序小型转储,并将它们用于离线分析。这不需要您在客户端计算机上部署pdb。此链接可以作为学习的良好起点。您需要PDB文件来准确获取源代码和行信息,这是完全正确的。我会质疑PDB文件出现的任何问题,因为它实际上是一个有效的问题,但是,假设有一个有效的理由,你可以这样做,但你需要付出更多的努力来创建一个合适的软件构建环境.MicrosoftSymbolServer将对调试符号进行索引并存储它们以备后用,当使用故障转储时需要符号可用。您可以将VisualStudio或Windbg指向您自己的符号服务器实例,就像Microsoft所做的那样,它会提取调试该应用程序版本所需的符号(假设您在发布前使用符号服务器对符号进行索引)。一旦为您的构建获得了合适的符号,您需要确保您拥有属于该构建的合适的源文件。这就是MicrosoftSourceServer的用武之地。就像SymbolServer索引符号一样,源服务器将索引源代码以确保您拥有属于您的软件构建的适当版本的源代码。版本控制、符号服务器和源服务器的工作版本应该是您的软件配置管理策略的一部分。有3rd方工具,一些是商业工具,它们会给你一个API来生成你的应用程序的快照,但正如你已经知道的那样,你需要一种机制来以某种方式将这些快照上传到你的环境。JohnRobbins谈PDB文件JohnRobbins谈源服务器查看有关启动和运行符号服务器的WinDbg文档。以上是C#学习教程:Recreatethestacktraceusingthelinenumberreportedbytheusererrorin.net?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
