Skip to content

Instantly share code, notes, and snippets.

@thomaslevesque
Created August 16, 2013 13:42

Revisions

  1. thomaslevesque created this gist Aug 16, 2013.
    99 changes: 99 additions & 0 deletions AsyncStackTrace.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    async void Main()
    {
    try
    {
    await FooAsync().AsyncTrace();
    }
    catch(Exception ex)
    {
    ex.FullTrace().Dump();
    }
    }

    async Task FooAsync()
    {
    await Console.Out.WriteLineAsync("Entering FooAsync");
    await BarAsync().AsyncTrace();
    await Console.Out.WriteLineAsync("Leaving FooAsync");
    }

    async Task BarAsync()
    {
    await Console.Out.WriteLineAsync("Entering BarAsync");
    string s = await BazAsync().AsyncTrace();
    Console.WriteLine(s);
    await Console.Out.WriteLineAsync("Leaving BarAsync");
    }


    async Task<string> BazAsync()
    {
    await Console.Out.WriteLineAsync("Entering BazAsync");
    throw new Exception("Oops");
    return "hello world";
    await Console.Out.WriteLineAsync("Leaving BazAsync");
    }


    static class AsyncExceptionExtensions
    {
    public static async Task AsyncTrace(
    this Task task,
    [CallerMemberName] string callerMemberName = null,
    [CallerFilePath] string callerFilePath = null,
    [CallerLineNumber] int callerLineNumber = 0)
    {
    try
    {
    await task;
    }
    catch (Exception ex)
    {
    AddAsyncStackTrace(ex, callerMemberName, callerFilePath, callerLineNumber);
    throw;
    }
    }

    public static async Task<T> AsyncTrace<T>(
    this Task<T> task,
    [CallerMemberName] string callerMemberName = null,
    [CallerFilePath] string callerFilePath = null,
    [CallerLineNumber] int callerLineNumber = 0)
    {
    try
    {
    return await task;
    }
    catch (Exception ex)
    {
    AddAsyncStackTrace(ex, callerMemberName, callerFilePath, callerLineNumber);
    throw;
    }
    }

    private static void AddAsyncStackTrace(Exception ex, string callerMemberName, string callerFilePath, int callerLineNumber = 0)
    {
    var trace = ex.Data["_AsyncStackTrace"] as IList<string>;
    if (trace == null)
    trace = new List<string>();
    trace.Add(string.Format("@{0}, in '{1}', line {2}", callerMemberName, callerFilePath, callerLineNumber));
    ex.Data["_AsyncStackTrace"] = trace;
    }

    public static string AsyncTrace(this Exception ex)
    {
    var trace = ex.Data["_AsyncStackTrace"] as IList<string>;
    if (trace == null)
    return string.Empty;
    return string.Join("\n", trace);
    }

    public static string FullTrace(this Exception ex)
    {
    var trace = ex.Data["_AsyncStackTrace"] as IList<string>;
    if (trace == null)
    return string.Empty;
    return string.Format("{0}\n--- Async stack trace:\n\t", ex)
    + string.Join("\n\t", trace);
    }
    }