Is there a tidier way to get call stack information than Environment.StackTrace?

Viewed 581

I would like to record the call stack on an object that gets passed around through some complicated multi-threaded code. Environment.StackTrace gives you that call stack but it's very difficult to read.

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)\r\n   at System.Environment.get_StackTrace()\r\n   at Foo.Bar.Biz(Monolith monolith) in C:\\Users\\Me\\Google\\Source\\Search.cs :line 70\r\n   at Blah.Nonsense.Business(Monolith monolith) in C:\\Users\\Me\\Google\\Source\\Prediction.cs :line 129\r\n   at ... you get the point

I just need to see the file, class, method, and line. Is there a correct way to get that information? Below is the method that I wrote but it's pretty ugly because of all the string manipulation.

public static List<string[]> GetCallstack()
{
    List<string[]> callstack = new List<string[]>();

    string stackTrace = Environment.StackTrace;
    string[] stackInstances = stackTrace.Split(new string[] { "\r\n" }, StringSplitOptions.None);
    foreach (string stackInstance in stackInstances)
    {
        var stackInstanceComponents = stackInstance.Split(new string[] { ") in ", ":line " }, StringSplitOptions.None);
        if (stackInstanceComponents.Length == 3)
        {
            string classAndMethod = string.Join(".", stackInstanceComponents[0].Split('.').Reverse().Take(2).Reverse().ToArray()) + ")";
            string path = string.Join("/", stackInstanceComponents[1].Split(System.IO.Path.DirectorySeparatorChar).Reverse().Take(2).Reverse().ToArray()).Replace("at ", "");
            string line = stackInstanceComponents[2];

            if (classAndMethod != "Utility.GetCallstack()")
            {
                callstack.Add(new string[] { classAndMethod, path, line });
            }
        }
    }

    return callstack;
}
2 Answers

See http://www.csharp-examples.net/reflection-callstack/

using System.Diagnostics;

[STAThread]
public static void Main()
{
  StackTrace stackTrace = new StackTrace();           // get call stack
  StackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)

  // write call stack method names
  foreach (StackFrame stackFrame in stackFrames)
  {
    Console.WriteLine(stackFrame.GetMethod().Name);   // write method name
  }
}

Use StackTrace.GetFrames() to get all frames and then each StackFrame has all required methods: GetFileName(), GetMethod(), GetFileLineNumber() and for the classname you use GetMethod().DeclaringType...

You can use the System.Diagnostics.StackTrace class instead. It will give you a hierarchical view of your stack trace. Check out this for full details on the class and code examples that do what you want. Note however that you must also filter out what you need. However, StackTrace allows you to do it in a cleaner way. Another choice is to use the StackFrame class which provides more fine grained info. This class has the GetFileName(), GetMethod(), GetFileLineNumber() and for the class name you can use GetMethod().DeclaringType

Related