如何测试我的 stacktrace walker 是否正确跳过库代码
How to test that my stacktrace walker correctly skips library code
我的问题是:我试图跳过一些来自库代码的栈帧。如果我想对此进行测试,我该如何 best/easiest 强制出现堆栈跟踪顶部有一个或多个来自库代码的帧的情况?
详情:
我使用以下代码的目标是能够在我的源代码中记录异常的来源。但是,在某些情况下,异常是在库代码中触发的,所以我得到一个如下所示的堆栈跟踪:
System.Net.WebException: The operation has timed out
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()
at Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreClientHelperClass.d__7``2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreCoprocRequest.d__10`4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
所以基本上我想继续向下移动堆栈框架,直到我找到一个我有实际有用信息的地方,跳过没有真正告诉我任何有用信息的库方法。
这是我要测试的代码:
public static (string Path, string Method, int Line) TryGetExceptionOrigin(this Exception e, string defaultPath, string defaultMethod, int defaultLine)
{
var defaultRes = (Path: defaultPath, Method: defaultMethod, Line: defaultLine);
var st = new StackTrace(e.GetInnerMostException(), true);
if (st.FrameCount == 0)
{
return defaultRes;
}
// Walk down the stack, ignoring framework code etc. with no useful information. We need a file name to be happy
for (int i = 0; i < st.FrameCount; i++)
{
var bottomFrame = st.GetFrame(i);
if (!(string.IsNullOrEmpty(bottomFrame.GetFileName())))
{
return (
Path: bottomFrame.GetFileName() ?? string.Empty, // Is null if no debug information
Method: bottomFrame.GetMethod().Name, // Documentation does not say this can ever be null
Line: bottomFrame.GetFileLineNumber()); // Is 0 if no debug information
}
}
// OK no match, we return the default information
return defaultRes;
}
像这样一些不必要的复杂的东西应该做得很好:
try
{
Func<int> d = () =>
{
try
{
return Guid.Parse("*").ToByteArray()[0];
}
catch (Exception)
{
throw;
}
};
Action a = () => { String.Format("{0}", 1 / d()); };
a();
}
catch (Exception ex)
{
var useful = ex.TryGetExceptionOrigin(null, null, 0);
}
此示例导致异常调用堆栈具有三个用户代码和四个 framework/library 代码条目。
在 https://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/
找到它
private static void ThrowIt()
{
Divide(3M, 0M);
}
static decimal Divide(decimal a, decimal b)
{
return (a / b);
}
这将产生此堆栈跟踪:
st {
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.op_Division(Decimal d1, Decimal d2)
at ExceptionLogging.Program.Divide(Decimal a, Decimal b) in C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line
98 at ExceptionLogging.Program.ThrowIt() in
C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line
93 at ExceptionLogging.Program.ThrowLater() in
C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line
88 at ExceptionLogging.Program.Main(String[] args) in
C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line
17 } System.Diagnostics.StackTrace
我的问题是:我试图跳过一些来自库代码的栈帧。如果我想对此进行测试,我该如何 best/easiest 强制出现堆栈跟踪顶部有一个或多个来自库代码的帧的情况?
详情:
我使用以下代码的目标是能够在我的源代码中记录异常的来源。但是,在某些情况下,异常是在库代码中触发的,所以我得到一个如下所示的堆栈跟踪:
System.Net.WebException: The operation has timed out
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()
at Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreClientHelperClass.d__7``2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreCoprocRequest.d__10`4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
所以基本上我想继续向下移动堆栈框架,直到我找到一个我有实际有用信息的地方,跳过没有真正告诉我任何有用信息的库方法。
这是我要测试的代码:
public static (string Path, string Method, int Line) TryGetExceptionOrigin(this Exception e, string defaultPath, string defaultMethod, int defaultLine)
{
var defaultRes = (Path: defaultPath, Method: defaultMethod, Line: defaultLine);
var st = new StackTrace(e.GetInnerMostException(), true);
if (st.FrameCount == 0)
{
return defaultRes;
}
// Walk down the stack, ignoring framework code etc. with no useful information. We need a file name to be happy
for (int i = 0; i < st.FrameCount; i++)
{
var bottomFrame = st.GetFrame(i);
if (!(string.IsNullOrEmpty(bottomFrame.GetFileName())))
{
return (
Path: bottomFrame.GetFileName() ?? string.Empty, // Is null if no debug information
Method: bottomFrame.GetMethod().Name, // Documentation does not say this can ever be null
Line: bottomFrame.GetFileLineNumber()); // Is 0 if no debug information
}
}
// OK no match, we return the default information
return defaultRes;
}
像这样一些不必要的复杂的东西应该做得很好:
try
{
Func<int> d = () =>
{
try
{
return Guid.Parse("*").ToByteArray()[0];
}
catch (Exception)
{
throw;
}
};
Action a = () => { String.Format("{0}", 1 / d()); };
a();
}
catch (Exception ex)
{
var useful = ex.TryGetExceptionOrigin(null, null, 0);
}
此示例导致异常调用堆栈具有三个用户代码和四个 framework/library 代码条目。
在 https://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/
找到它 private static void ThrowIt()
{
Divide(3M, 0M);
}
static decimal Divide(decimal a, decimal b)
{
return (a / b);
}
这将产生此堆栈跟踪:
st {
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.op_Division(Decimal d1, Decimal d2)
at ExceptionLogging.Program.Divide(Decimal a, Decimal b) in C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line 98 at ExceptionLogging.Program.ThrowIt() in C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line 93 at ExceptionLogging.Program.ThrowLater() in C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line 88 at ExceptionLogging.Program.Main(String[] args) in C:\Users\anjohans\source\repos\ExceptionLogging\ExceptionLogging\Program.cs:line 17 } System.Diagnostics.StackTrace