Created
August 16, 2013 13:42
-
-
Save thomaslevesque/6250080 to your computer and use it in GitHub Desktop.
Extension method to add "logical" stack trace to async methods, with usage example.
Copy/paste in Linqpad and add the following namespaces:
- System.Runtime.CompilerServices
- System.Threading.Tasks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment