Exception's Stack trace not complete when throwing in Func

1.4k Views Asked by At

I have an issue where when an exception is thrown inside a method accessed via a func the stack trace is getting truncated. Consider the following simple reproduction:

static void Main(string[] args)
{
    Test();
    Console.ReadLine();
}

public static void Test()
{
    try
    {
        Func<string> func = () => MyFunc();
        func();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception.StackTrace:");
        Console.WriteLine(ex.StackTrace.ToString());
    }
}

public static string MyFunc()
{
    Console.WriteLine("Environment.StackTrace:");
    Console.WriteLine(Environment.StackTrace);
    Console.WriteLine(new String('*', 20));
    throw new Exception("Where is my stack trace?");
}

I would expect the stack trace written out in the catch block to be basically the same as that written out in MyFuncbut in fact what gets written out as the stack trace of the exception is:

at FuncStackTraceIssue.Program.MyFunc() in Program.cs:line 36
at FuncStackTraceIssue.Program.<>c.<Test>b__1_0() in Program.cs:line 21
at FuncStackTraceIssue.Program.Test() in Program.cs:line 22

As you can see it only goes back as far as the Function where I invoked the func (Test). The writing out of the stack trace in MyFunc is:

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at FuncStackTraceIssue.Program.MyFunc() in Program.cs:line 34
at FuncStackTraceIssue.Program.<>c.<Test>b__1_0() in Program.cs:line 21
at FuncStackTraceIssue.Program.Test() in Program.cs:line 22
at FuncStackTraceIssue.Program.Main(String[] args) in Program.cs:line 13

The reason this is causing me problems is that in the real code this is being called from several different places and passing in variables and other such things and when it goes wrong I log the exception including the stack trace. I want to be able to see exactly what the code path is that led to the error and preferably without having to change how I log.

So the question is why do I not get a full stack trace and is there anything I can do to make it give me a full stack trace?

1

There are 1 best solutions below

0
On BEST ANSWER

To add to @Dark Falcon's comment above:

This is not necessarily an issue with Func<>, but has to do with how the StackTrace property works.

From MSDN's exception class docs (emphasis mine):

"In contrast, if the exception is re-thrown by using the statement [example follows]... the full call stack is not preserved, and the example would generate the following output [example follows]... A slightly more cumbersome alternative is to throw a new exception, and to preserve the original exception's call stack information in an inner exception. The caller can then use the new exception's InnerException property to retrieve stack frame and other information about the original exception."

As a possible workaround to log the full stack trace, you might consider inheriting from the Exception class and adding something like a stack tracer property:

public class StackTraceableException : Exception
{
    readonly string stackTrace;

    public StackTraceableException() : base() { }

    public StackTraceableException(string message, string stackTrace) :
        base(message)
    {
        this.stackTrace = stackTrace;
    }

    public string StackTrace { get { return stackTrace; } }
}

...and, to follow through with the existing catch block:

catch (StackTraceableException ex)
{
    Console.WriteLine("Exception.StackTrace:");
    Console.WriteLine(ex.StackTrace);
}