Rethrowing exceptions and preserving the full call stack trace
Did you know that depending on the way you rethrow exceptions you may lose important information? There are already several blog posts that explain and demonstrate the difference between throw and throw ex. I'm realizing only now that none of the two solutions yields the complete call stack trace information!
Let's see what the problem is and I'll show you the real solution.
I'll use the following method to generate an exception:
private static void BadWork()
{
int i = 0;
int j = 12 / i; // Line 10: DivideByZeroException
int k = j + 1;
}
Let's consider what happens if we call BadWork and rethrow the exception with throw ex as follows:
try
{
BadWork();
}
catch (Exception ex)
{
// do something
// ...
throw ex; // Line 24
}
Here is the call stack trace that we get in this case:
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowEx() in Program.cs:line 24
at Program.Main(String[] args) in Program.cs:line 88
Line 24 is where throw ex is, not where the exception was thrown.
Let's now replace throw ex by throw:
try
{
BadWork();
}
catch
{
// do something
// ...
throw; // Line 38
}
This time, here is the call stack trace:
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.BadWork() in Program.cs:line 10
at Program.WithThrow() in Program.cs:line 38
at Program.Main(String[] args) in Program.cs:line 89
As you can see, we get one additional stack frame this time. Line 10 is where the exception was thrown, which is important information because this is the only information that identifies where the exception actually happened.
This shows that it's better to use throw rather than throw ex if you want the full stack trace information to be preserved. However, there are cases where throw is not enough. In the following example, throw does not preserve the full stack trace:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowIncomplete() in Program.cs:line 54
at Program.Main(String[] args) in Program.cs:line 106
This time, you can see that information is lost again. Line 54 is where throw is, not where the exception was thrown.
To preserve the full call stack information, you need to use the following method:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
This method can be used as follows:
try
{
int i = 0;
int j = 12 / i; // Line 78
int k = j + 1;
}
catch (Exception ex)
{
// do something
// ...
PreserveStackTrace(ex);
throw; // Line 86
}
Here is the new call stack information you get with the above code:
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowAndStackTracePreservation() in Program.cs:line 78
at Program.WithThrowAndStackTracePreservation() in Program.cs:line 86
at Program.Main(String[] args) in Program.cs:line 110
Here is the call stack information you get with throw ex and a call to PreserveStackTrace:
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.BadWork() in Program.cs:line 10
at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 62
at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 69
at Program.Main(String[] args) in Program.cs:line 109
Here we get the full call stack information. Lines 78 and 10 are where the exceptions were thrown. To my knowledge, this is the only way to get complete call stack information in your logs. Without it, it may be difficult to hunt down some bugs.
It's worth noting that if you call PreserveStackTrace, then you can use throw or throw ex and you'll equally get the full stack trace information.
I found this useful trick on Chris Taylor's blog. If you want to use this with .NET 1, you should refer to Chris' post because it seems that the InternalPreserveStackTrace method didn't exist before .NET 2.0.
The complete source code is attached to this post.
Rethrowing exceptions and preserving the full call stack trace的更多相关文章
- The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
好久没有冒泡了,最近在新环境上搭建应用时,启动报错: INFO: Illegal access: this web application instance has been stopped alre ...
- java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解
[2013-12-06 11:06:21,715] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|7 ...
- XDebug 自动开启PHP Stack Trace, 导致PHP Log 超1G
昨天早上突然发现测试服务器空间满了,用du挨个文件夹查看,发现是php debug log占地极大,有的log直接有1G,打开后发现极其多的php stack trace. 立刻到主服务器查看,主服务 ...
- dump 分析模式之 INCORRECT STACK TRACE - djm2005dy的专栏 - 博客频道 - CSDN.NET
Dump 分析模式之 INCORRECT STACK TRACE dump 分析模式之 INCORRECT STACK TRACE 翻译自 MDA-Anthology Page288 初学者常犯的错 ...
- Eclipse下Android开发错误之Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace
升级了Android版本后,在运行应用时提示: [2013-11-27 10:37:35 - Dex Loader] Unable to execute dex: java.nio.BufferOve ...
- Android -- java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
使用Bundle 的getParcelableArray 出现了以下错误: Class not found when unmarshallingjava.lang.ClassNotFoundExcep ...
- 让Xcode的 stack trace信息可读
让Xcode的 stack trace信息可读 昨天在写 iOS 代码的时候,调试的时候模拟器崩溃了.异常停在了如下整个 main 函数的入口处: int main(int argc, char *a ...
- 项目跑起来之后,一会儿后台就会报错Illegal access: this web application instance has been stopped already. Could not load [com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask]. The following stack trace
一月 24, 2016 6:42:54 下午 org.apache.catalina.loader.WebappClassLoaderBase checkStateForResourceLoading ...
- Java 抓取 thread dump (Full Thread Stack Trace) 方法汇总
顾名思义,表示一个时间点上,显示进程里面每一个线程的 stack trace,以及线程之间关联,比如等待 常用来定位一些 不响应,CPU 很高,内存使用很高问题 汇总表格如下 工具 操作系统 Java ...
随机推荐
- OAF_开发系列16_实现OAF与XML Publisher整合
http://wenku.baidu.com/link?url=y2SFKHP5qqn4bl_iNeqLGjXsTvhyFuhkMraIbWZdTXbzcv0vTefrZFFBDWie0cAAKuTw ...
- .NET并行编程 - 并行方式
使用多线程可以利用多核CPU的计算能力,可以提供更好的程序响应能力,但是每个线程都有开销,需要注意控制线程的数量. 1. System.Threading.Thread 使用多线程最直接的是使用Sys ...
- 解压版Tomcat配置
解压版Tomcat配置(本例Tomcat6): 一 配置Tomcat 1 下载Tomcat Zip压缩包,解压. 如果增加tomcat的用户名和密码,则修改/conf/tomcat-us ...
- Python基础(二)之模块
模块:人们写好的一系列用于实现某种功能的代码封装起来,需要使用的时候直接调用即可. 模块分类:标准模块.第三方模块 标准模块:不需要安装,直接调用即可 第三方模块:需要安装后才可使用 注意:自己创建的 ...
- 理解C++的inline函数
C++的inline函数就是编译器在编译代码时,将"对此函数的每一个调用"都以函数本体替换之,该过程发生在编译期间. inline函数的优点是,它可以省去函数调用所带来的额外开销, ...
- twitter点赞动画详解
今天在微博上看到@过气网红一丝 的一篇微博,codepen上贴出了twitter点赞那个动画效果的源码,地址 http://codepen.io/yisi/pen/LpXVJb .我看了下效果很好看, ...
- jQuery MiniUI开发系列之:Ajax处理超时、服务端错误
MiniUI所有组件的ajax交互,均使用标准.成熟的jQuery.ajax. 依赖于jquery ajax组件的完善性,我们可以拦截住每一次ajax请求处理. 比如,拦截ajax返回数据前,判断返回 ...
- js屏蔽浏览器右键菜单,粘贴,复制,剪切,选中(转)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)
PS:在前几天的面试中,被问到了这个题.然而当时只能用最低效的方法来解. 问题描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2, ...
- Python体验(10)-图形界面之计算器
import wx class Form(wx.Frame): def __init__( self, parent, id, title ): wx.Frame.__init__(self,pare ...