从 C# 打印堆栈跟踪信息

Posted

技术标签:

【中文标题】从 C# 打印堆栈跟踪信息【英文标题】:Print stack trace information from C# 【发布时间】:2010-09-08 06:47:05 【问题描述】:

作为我们产品中某些错误处理的一部分,我们希望转储一些堆栈跟踪信息。但是,我们体验到许多用户只会截取错误消息对话框的屏幕截图,而不是向我们发送程序中可用的完整报告的副本,因此我想在此对话框中提供一些最小的堆栈跟踪信息。

我机器上的 .NET 堆栈跟踪如下所示:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize)
at System.IO.StreamReader..ctor(String path)
at LVKWinFormsSandbox.MainForm.button1_Click(Object sender, EventArgs e) in C:\Dev\VS.NET\Gatsoft\LVKWinFormsSandbox\MainForm.cs:line 36

我有这个问题:

格式看起来是这样的:

at <class/method> [in file:line ##]

但是,atin 关键字,我认为如果它们运行,例如,挪威 .NET 运行时而不是我安装的英文运行时,它们将被本地化.

有什么方法可以让我以与语言无关的方式分离这个堆栈跟踪,这样我就可以只显示那些条目的文件和行号?

换句话说,我想从上面的文字中得到这些信息:

C:\Dev\VS.NET\Gatsoft\LVKWinFormsSandbox\MainForm.cs:line 36

您可以提供的任何建议都会有所帮助。

【问题讨论】:

我希望有人能给出解析答案,因为我正在处理来自任意应用程序的记录字符串,并且真的希望能得到一些细节。鉴于您可以控制 StackTrace 的来源,尽管您确实选择了正确的答案:) 【参考方案1】:

你应该能够通过说得到一个 StackTrace 对象而不是一个字符串

var trace = new System.Diagnostics.StackTrace(exception);

然后您可以自己查看框架,而无需依赖框架的格式。

另请参阅:StackTrace reference

【讨论】:

哦,太好了,我不知道!我一定会调查的。 在发布模式下你还能精确地获取异常的堆栈跟踪吗? 我在文件中序列化 exceptionSerializationHelper.Serialize(@"c:\temp\ConfigurationErrorsExceptions.ser", ex); 如果我从文件 var exception = SerializationHelper.Deserialize(@"ConfigurationErrorsExceptions.ser"); 反序列化 Trace不可用 var trace = new System.Diagnostics.StackTrace(exception as Exception); FrameCount 为 0 【参考方案2】:

这是我用来执行此操作的代码

public static void LogStack()

  var trace = new System.Diagnostics.StackTrace();
  foreach (var frame in trace.GetFrames())
  
    var method = frame.GetMethod();
    if (method.Name.Equals("LogStack")) continue;
    Log.Debug(string.Format("0::1", 
        method.ReflectedType != null ? method.ReflectedType.Name : string.Empty,
        method.Name));
  

【讨论】:

您可能会认为这将在某处内置功能,因为异常处理程序本身就是这样做的。【参考方案3】:

只是为了让这成为一个 15 秒的复制粘贴答案:

static public string StackTraceToString()

    StringBuilder sb = new StringBuilder(256);
    var frames = new System.Diagnostics.StackTrace().GetFrames();
    for (int i = 1; i < frames.Length; i++) /* Ignore current StackTraceToString method...*/
    
        var currFrame = frames[i];
        var method = currFrame.GetMethod();
        sb.AppendLine(string.Format("0:1",                    
            method.ReflectedType != null ? method.ReflectedType.Name : string.Empty,
            method.Name));
    
    return sb.ToString();

(基于林德霍尔姆的回答)

【讨论】:

谢谢。请注意,您可以使用 sb.AppendLine(...) 来避免对特定的行尾字符进行硬编码。【参考方案4】:

或者还有更短的版本..

Console.Write(exception.StackTrace);

【讨论】:

【参考方案5】:

作为替代方案,log4net 尽管有潜在危险,但比 System.Diagnostics 给了我更好的结果。基本上在 log4net 中,您有一个用于各种日志级别的方法,每个级别都有一个异常参数。因此,当您传递第二个异常时,它会将堆栈跟踪打印到您配置的任何附加程序。

示例:Logger.Error("Danger!!!", myException );

根据配置,输出看起来类似于

System.ApplicationException: Something went wrong.
   at Adapter.WriteToFile(OleDbCommand cmd) in C:\Adapter.vb:line 35
   at Adapter.GetDistributionDocument(Int32 id) in C:\Adapter.vb:line 181
   ...

【讨论】:

您能否澄清一下您所说的 log4net “潜在危险”是什么意思? 我不确定 Oglester 是什么意思,但我知道 ***.com 存在一些死锁问题,因为 log4net 正在将异常记录到数据库中。我个人没有任何问题,但我保持简单并坚持滚动文本文件。 如果你没有正确管理你的引用,你最终会出现内存泄漏。我不久前工作的网站广泛使用 log4net(滚动文件)。由于 log4net 引用文件(不安全),您必须确保清理 log4net 引用或保持最少。

以上是关于从 C# 打印堆栈跟踪信息的主要内容,如果未能解决你的问题,请参考以下文章

如何在 .NET 中毫无例外地打印当前的堆栈跟踪?

从程序内部调用 gdb 以打印其堆栈跟踪的最佳方法?

从堆栈跟踪中获取更多详细信息

如何使用带有行号信息的 gcc 获取 C++ 的堆栈跟踪?

使用 CORBA 时打印堆栈跟踪

获取完整的字符串堆栈跟踪,包括内部异常