首先,这个问题:我有几个免费项目,并作为任何软件,他们有bugs。 一些老乡用户时遇到的错误给我带堆栈跟踪的错误的报告。 为了简化找茬的地方,我想看看在这个堆栈跟踪的行号。 如果应用程序没有运.pdb文件,然后所有的线路信息丢失,所以部署.pdb文件目前我所有的项目,所以产生的堆栈跟踪有这个号码。 但! 但我不希望看到这种分布的文件和要删除所有的.pdb。 他们迷惑用户,消耗安装,空间等。
德尔福的解决方案:很久以前,当我是一个Delphi程序员,我用了以下技术:在例外我的应用程序走栈,并收集地址。 然后,当我收到错误报告,我用了一个工具,重构基于收集的地址和位于我的机器上相应的符号文件函数名和行号有效的堆栈跟踪。
问:是否有任何lib下,或技术或任何这样做的.NET?
状态更新:很有意思,经常问的一个问题就是,开始自己调查的最佳途径。 例如,我思考这个问题有一段时间了,但开始寻找答案只有数天前。
选项1:小型转储。 大量的谷歌搜索后,我已经找到一种方法来创建代码小型转储,以及如何重新创建管理小型转储堆栈。
- 可再发行组件创建小型转储表单代码- clrdump
- 博客文章有关使用以前的组装- 在.NET生产应用创建和分析小型转储
然而,这种解决方案需要重新分配两个附加组件(〜1MB大小),和迷你转储需要一些空间,这是不舒服的用户通过电子邮件发送给亲友。 所以,对于我而言,现在,这是不可接受的。
选项2:感谢weiqure的线索。 它能够提取管理IL每堆栈帧偏移。 现在的问题是如何从.PDB基于此偏移得到的行号。 而我发现:
- PDB文件内幕 ,只是信息,因为:
- ISymbolReader -管理接口来读取程序数据库文件
- 最后一个工具,文件转换.PDB以结构化的XML ,方便的XPath处理
使用这个工具,它可以创建XML文件为每个发行版本,并付诸repositary。 当异常用户的机器上时,它可以产生格式化的错误信息与IL偏移。 然后,用户通过邮件发送该邮件(很小)。 最后,它是可以创建重新产生从格式化的错误消息堆栈的简单工具。
我只是在想,为什么别人没有实现这样的工具? 我不相信,这仅仅是有趣的我。
你可以得到抵消使用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)
在ConsoleApplicationN.exe.Program.ThrowError(IL偏移:0x1b)
在mscorlib.dll.DateTime..ctor(IL偏移:0x9)
在mscorlib.dll.DateTime.DateToTicks(IL偏移:0x61)
消息:年,月和日参数描述一个未表示的日期时间。
然后,您可以使用反射或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偏移。
您应该使用Environment.FailFast ,调用FAILFAST在Application.UnhandledException和转储文件会为您创建。
从MSDN:
故障快速转移方法写入日志条目使用消息参数的Windows应用程序事件日志,创建应用程序的转储,然后终止当前进程。
使用故障快速转移方法而不是退出方法,如果你的应用程序的状态被损坏无法修复终止您的应用程序,并执行应用程序的尝试-finally块和终结会破坏程序的资源。 故障快速转移方法终止当前处理,并执行任何CriticalFinalizerObject对象,但不执行任何活动的try-最后块或终结。
你可以写一个简单的应用程序,将收集日志文件,并将它们发送给您。
现在,打开转储文件是有点棘手,Visual Studio中不能处理管理转储文件(固定在.NET 4.0中),可以使用WinDBG的 ,但你需要使用SOS 。
每当有一个错误您可以创建一个应用程序转储,并将其用于离线分析。 这并不需要您部署在客户机上PDBS。 这个链接可以作为一个很好的起点学习。
你绝对需要PDB文件准确地获取源和线路信息的正确的轨道上。 我怀疑任何察觉的问题与航运PDB文件,实际上是一个有效的关注,但是,假设有一个正当的理由,你可以做到这一点,但它需要更多的努力你的一部分,以创建相应的软件构建环境。
Microsoft符号服务器将索引调试符号,并将其存储在日后的使用,当你有一个崩溃转储,例如,需要符号可用。 您可以在自己的符号服务器实例指出无论是Visual Studio或WinDBG的,就像微软的 ,它会拉低该版本的应用程序(假设你在发货前与索引符号服务器的符号)调试所需的符号。
一旦你有一个构建相应的符号,你需要确保你有属于该生成相应的源文件。
这是微软的源服务器进来。就像这里符号Server索引符号 ,源服务器将索引源 ,以确保你有属于软件构建的源代码的相应版本。
版本控制 , 符号服务器和源服务器的工作版本应该是你的软件配置管理策略的一部分。
有第三方工具,一些商业,将会为您提供一个API生成应用程序快照,但是因为你已经明白了,你需要获得上传到您的环境不知何故这些快照的机制。
约翰罗宾斯上PDB文件
约翰罗宾斯在源服务器
退房WinDbg的文档上获得一个符号服务器启动和运行。