首先,问题是:我有几个免费的项目,而且作为任何软件,它们都包含bug。一些其他用户遇到bug时,会给我发送带有堆栈跟踪的bug报告。为了简化故障位置的查找,我希望在这个堆栈跟踪中看到行号。如果应用程序没有.pdb文件,那么所有的行信息都丢失了,所以目前我所有的项目都部署在.pdb文件中,所以生成的堆栈跟踪都有这个编号。但!但是我不希望看到这个文件在发行版中,并且希望删除所有的.pdb。它们混淆了用户,占用了安装程序中的空间等。
Delphi解决方案:很久以前,当我还是程序员时,我使用了以下技术:在例外情况下,我的应用程序在堆栈上行走并收集地址。然后,当我收到错误报告时,我使用了一个工具,根据收集到的地址和位于机器上的相应符号文件,用函数名和行号重构有效的堆栈跟踪。
问题:在.NET中是否有任何库、技术或其他方法来做同样的事情?
状态更新:非常有趣,经常问问题是开始自己调查的最好方法。例如,我想了一段时间这个问题,但几天前才开始寻找答案。
选项1: MiniDumps。在大量搜索之后,我找到了一种从代码创建迷你转储的方法,以及如何从托管的迷你转储重新创建堆栈。
然而,这个解决方案需要重新分发两个额外的程序集(~1mb的大小),微型转储占用了一些空间,用户通过电子邮件发送它们是不舒服的。所以就我而言,现在,这是不可接受的。
选项2:感谢韦库尔的线索。可以为每个堆栈帧提取托管的IL偏移量。现在的问题是如何根据这个偏移量从.pdb中获取行号。我所发现的是:
使用此工具,可以为每个版本构建创建xml文件并将其放入存储库。当异常发生在用户的机器上时,可以创建带有IL偏移的格式化错误消息。然后用户通过邮件发送此消息(非常小)。最后,可以创建一个简单的工具,根据格式化的错误消息重新创建结果堆栈。
我只想知道为什么没有其他人不实现这样的工具?我不相信这对我来说很有趣。
发布于 2009-06-24 13:25:56
您可以使用System.Diagnostics.StackTrace从异常获取最后一个MSIL指令的偏移量:
// Using System.Diagnostics
static void Main(string[] args)
{
try { ThrowError(); }
catch (Exception e)
{
StackTrace st = new System.Diagnostics.StackTrace(e);
string stackTrace = "";
foreach (StackFrame frame in st.GetFrames())
{
stackTrace = "at " + frame.GetMethod().Module.Name + "." +
frame.GetMethod().ReflectedType.Name + "."
+ frame.GetMethod().Name
+ " (IL offset: 0x" + frame.GetILOffset().ToString("x") + ")\n" + stackTrace;
}
Console.Write(stackTrace);
Console.WriteLine("Message: " + e.Message);
}
Console.ReadLine();
}
static void ThrowError()
{
DateTime myDateTime = new DateTime();
myDateTime = new DateTime(2000, 5555555, 1); // won't work
Console.WriteLine(myDateTime.ToString());
}输出:
在ConsoleApplicationN.exe.Program.Main (IL偏移: 0x7) at ConsoleApplicationN.exe.Program.ThrowError (IL偏移量: 0x1b) 在mscorlib.dll.DateTime..ctor (IL偏移量: 0x9) 在mscorlib.dll.DateTime.DateToTicks (IL偏移: 0x61) 消息:年、月和日参数描述一个无法表示的DateTime。
然后可以使用反射器或ILSpy来解释偏移量:
.method private hidebysig static void ThrowError() cil managed
{
.maxstack 4
.locals init (
[0] valuetype [mscorlib]System.DateTime myDateTime)
L_0000: nop
L_0001: ldloca.s myDateTime
L_0003: initobj [mscorlib]System.DateTime
L_0009: ldloca.s myDateTime
L_000b: ldc.i4 0x7d0
L_0010: ldc.i4 0x54c563
L_0015: ldc.i4.1
L_0016: call instance void [mscorlib]System.DateTime::.ctor(int32, int32, int32)
L_001b: nop
L_001c: ldloca.s myDateTime
L_001e: constrained [mscorlib]System.DateTime
L_0024: callvirt instance string [mscorlib]System.Object::ToString()
L_0029: call void [mscorlib]System.Console::WriteLine(string)
L_002e: nop
L_002f: ret
}您知道,0x1b之前的指令抛出了异常。很容易找到这方面的C#代码:
myDateTime = new DateTime(2000, 5555555, 1);您现在可以将IL代码映射到您的C#代码,但我认为增益太小,工作量太大(尽管可能有一个反射器插件)。你应该对IL偏移没什么意见。
发布于 2009-06-24 12:45:22
您应该使用Environment.FailFast,在Application.UnhandledException中调用FailFast,然后为您创建一个转储文件。
来自MSDN:
FailFast方法使用消息参数将日志条目写入日志,创建应用程序的转储,然后终止当前进程。 如果应用程序的状态损坏无法修复,则使用FailFast方法而不是Exit方法终止应用程序,并且执行应用程序的尝试--最终块和终结器将破坏程序资源。FailFast方法终止当前进程并执行任何CriticalFinalizerObject对象,但不执行任何活动的尝试-最终块或终结器。
您可以编写一个简单的应用程序来收集日志文件并将它们发送给您。
现在,打开转储文件有点棘手,Visual无法处理托管转储文件(固定在.NET 4.0中)--您可以使用WinDBG,但需要使用SOS。
发布于 2009-06-24 12:38:49
当有bug时,您可以创建一个应用程序minidump,并使用它进行脱机分析。这不要求您在客户端计算机上部署pdbs。这链接可以作为学习的良好起点。
https://stackoverflow.com/questions/1037925
复制相似问题