在C#方法中获取堆栈跟踪

7
我想要实现通用的日志记录器,以便帮助我查看方法的调用堆栈。
我知道有一些来自System.Diagnostic的方法,但它们是在.net 4.0中引入的,我担心它们在xamarin或.net core等地方不起作用。因此,我想要更通用的解决方案。
另一个问题是async\await会导致一些混乱。
我考虑过在每个方法中传递附加参数,其中存储一些上下文并帮助我确定调用堆栈,但这个解决方案有点复杂。
我也可以使用不安全代码读取线程堆栈内存,并自己检查调用堆栈,但这不是可靠的。
是否还有其他解决方案?

1
你肯定可以绕过它:抛出异常,捕获它并从中读取调用堆栈 :) - MarcinJuraszek
@MarcinJuraszek 不错的技巧 :) 但我担心它会影响性能。 - Neir0
1个回答

10
你可以直接使用Environment.StackTrace,这是从框架一开始就存在的。 Environment.StackTrace会返回完整的堆栈跟踪(包括对Environment.StackTrace本身的调用),作为一个分隔符分隔的字符串。
类似于这样:

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at WpfApplication2.MainWindow.GetStack(Int32 removeLines)
at WpfApplication2.MainWindow.Button_Click(Object sender, RoutedEventArgs e)
...
at System.Threading.ThreadHelper.ThreadStart()

你只需要拆分/解析/格式化它,或者按照你想要的方式处理它。
由于你将在自己的类中使用它,请记得删除最新的X行。
这段代码应该到处都能工作,因为它是故意低级的。
private static string[] GetStack(int removeLines)
{
    string[] stack = Environment.StackTrace.Split(
        new string[] {Environment.NewLine},
        StringSplitOptions.RemoveEmptyEntries);

    if(stack.Length <= removeLines)
        return new string[0];

    string[] actualResult = new string[stack.Length - removeLines];
    for (int i = removeLines; i < stack.Length; i++)
        // Remove 6 characters (e.g. "  at ") from the beginning of the line
        // This might be different for other languages and platforms
        actualResult[i - removeLines] = stack[i].Substring(6);

    return actualResult;
}

1
有一个需要注意的地方,.net在不同语言下具有不同的堆栈跟踪输出,因此在删除“at”和其他依赖于语言的单词时需要小心。 - Neir0
好的想法。我会在未来的答案中包含它作为参考。 - Manfred Radlwimmer

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