如何记录完整的调用堆栈信息以及异常?

5
我想使用ELMAH记录异常(而不是将其全部抛到调用堆栈),并记录整个调用堆栈。
示例代码:
    protected void Page_Load(object sender, EventArgs e)
    {
        DoSomething();
    }

    private void DoSomething()
    {
        try { TrySomething(); }
        catch (Exception ex) { LogException(ex); }
    }

    private void TrySomething()
    {
        throw new NotImplementedException();
    }

    public static void LogException(Exception ex)
    {
        var currentStack = new System.Diagnostics.StackTrace(true);
        Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    }

现在,在LogException方法中,我可以看到调用堆栈告诉我DoSomething()调用了TrySomething(),并且抛出了异常,但我无法看到调用堆栈显示Page_Load()调用了DoSomething()。我希望能够看到完整的调用堆栈。

以下是在LogException方法中ex.StackTrace的示例:

at WebApplication1._Default.TrySomething() in C:\Projects\test\GeneralTests\WebApplication1\Default.aspx.cs:line 26
at WebApplication1._Default.DoSomething() in C:\Projects\test\GeneralTests\WebApplication1\Default.aspx.cs:line 20

我可以使用System.Diagnostics.StackTrace()获取完整的调用堆栈,例如:

at WebApplication1._Default.LogException(Exception ex)
at WebApplication1._Default.DoSomething()
at WebApplication1._Default.Page_Load(Object sender, EventArgs e)
[snip]

(我可以通过遍历StackTrace的每个帧来获取行号和源文件详细信息)。
但是,我该如何将此注入异常或引发具有此调用堆栈详细信息的新异常?有没有一种优雅的方法来做到这一点?我是否忽略了什么非常明显的东西?

请查看以下相关问题的答案,以更好地理解为什么您无法获取完整的调用堆栈:https://dev59.com/I1fUa4cB1Zd3GeqPIXga#6094700 和 https://dev59.com/goDba4cB1Zd3GeqPIcX5#24297684 - Jeff B
3个回答

6
您可以像这样获取完整的堆栈信息,以便在出现错误时进行调试:
var currentStack = new System.Diagnostics.StackTrace(true);
return currentStack.ToString();

2

当应用程序在没有调试标志的情况下编译时,堆栈不一定会在执行中被保留。只有通过在每个方法中添加try / catch才能保证每个项都被记录。


你的意思是方法调用可以内联到执行序列中吗?否则我不确定我理解你的意思 - 调用堆栈必须被保留! - Alex
是的,我认为这是内联。尝试使用try/catch绕过它,或者始终在调试模式下构建。 - cjk
@Alex:他的意思是编译器(和JIT)通常通过内联方法来优化您的代码(尽管您可以使用MethodImplAttribute防止此操作);在这种情况下,您将无法获得完整的堆栈跟踪。 - ShdNx
当处于发布模式时,我将调试信息设置为仅限pdb。我不知道编译器是否以某种方式标记内联方法,以便可以解开/完全调试 - 这似乎是可能的。无论如何,在完全调试版本中,问题仍然是相关的,因为完整的调用堆栈肯定是可用的。非常感谢任何进一步的帮助。谢谢大家。 - Alex
你说得完全正确,我刚刚查阅了有关代码在编译为优化(非调试、发布模式)时被内联的相关资料,因此它不会显示在调用堆栈中。所以它的使用显然是有限制的。再次感谢。 - Alex

1

你看过Exception.ToString()的结果吗?它包含了堆栈跟踪。它是否包含你要查找的那种类型?


4
ex.StackTrace是当前(内部)调用栈的字符串表示,但它不会显示异常外的堆栈。我将更新问题描述,附上ex.StackTrace的结果和我需要的内容。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接