arb*_*ter 16 .net c# debugging stack-trace
首先,问题是: 我有几个免费项目,并且任何软件都包含bug.一些用户在遇到bug时会向我发送一个带有堆栈跟踪的bug报告.为了简化查找故障位置,我想在此堆栈跟踪中查看行号.如果应用程序没有.pdb文件,那么所有行信息都会丢失,因此目前我的所有项目都部署了.pdb文件,因此生成的堆栈跟踪具有此数字.但!但我不希望在发行版中看到这些文件,并希望删除所有.pdb.它们会混淆用户,消耗安装程序中的空间等.
Delphi解决方案: 很久以前当我是delphi程序员时,我使用了以下技术:例外我的应用程序在堆栈上行走并收集地址.然后,当我收到错误报告时,我使用了一个工具,根据收集的地址和位于MY机器上的相应符号文件,使用函数名称和行号重建有效的堆栈跟踪.
问题: 在.NET中是否有任何lib,或技术或其他任何相同的操作?
状态更新:非常有趣,经常提出问题是开始自己调查的最佳方式.例如,我想了一段时间这个问题,但几天前才开始寻找答案.
选项1:MiniDumps.经过大量的谷歌搜索后,我找到了一种从代码创建迷你转储的方法,以及如何从托管小型转储中重新创建堆栈.
然而,该解决方案需要重新分配两个额外的组件(大小约为1mb),并且小型转储占用一些空间,并且用户通过电子邮件发送它们是不舒服的.所以对于我的目的,现在,这是不可接受的.
选项2:感谢weiqure的线索.可以为每个堆栈帧提取受管理的IL偏移量.现在问题是如何根据此偏移从.pdb获取行号.我发现了什么:
使用此工具,可以为每个发布版本创建xml文件并将它们放入repositary.当用户的机器上发生异常时,可以创建带有IL偏移的格式化错误消息.然后用户通过邮件发送此消息(非常小).最后,可以创建一个简单的工具,从格式化的错误消息重新创建结果堆栈.
我只是想知道为什么没有其他人没有实现这样的工具?我不相信这只对我有意义.
wei*_*ure 15
您可以使用System.Diagnostics.StackTrace从Exception获取最后一条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());
}
Run Code Online (Sandbox Code Playgroud)
输出:
位于 mscorlib.dll.DateTime的mscorlib.dll.DateTime..ctor(IL偏移量:0x9) 处的
ConsoleApplicationN.exe.Program.ThrowError(IL偏移量:0x1b)处的ConsoleApplicationN.exe.Program.Main(IL偏移量:0x7)处. DateToTicks(IL偏移量:0x61) 消息:年,月和日参数描述不可表示的DateTime.
.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
}
Run Code Online (Sandbox Code Playgroud)
你知道0x1b之前的指令引发了异常.很容易找到C#代码:
myDateTime = new DateTime(2000, 5555555, 1);
Run Code Online (Sandbox Code Playgroud)
您现在可以将IL代码映射到C#代码,但我认为增益太少而且工作量太大(尽管可能有反射器插件).IL偏移应该没问题.
您应该使用Environment.FailFast,在Application.UnhandledException中调用FailFast,并为您创建转储文件.
来自MSDN:
FailFast方法使用message参数将日志条目写入Windows应用程序事件日志,创建应用程序的转储,然后终止当前进程.
如果应用程序的状态损坏无法修复,则使用FailFast方法而不是Exit方法终止应用程序,并且执行应用程序的try-finally块和终结器将损坏程序资源.FailFast方法终止当前进程并执行任何CriticalFinalizerObject对象,但不执行任何活动的try-finally块或终结器.
您可以编写一个简单的应用程序来收集日志文件并将其发送给您.
现在,打开转储文件有点棘手,Visual Studio无法处理托管转储文件(在.NET 4.0中修复),您可以使用WinDBG,但您需要使用SOS.