java代码中捕获异常后可以简单通过ex.printStackTrace()打印出异常堆栈跟踪信息。但实际应用中经常需要通过log4j将日志打印到日志文件中,若直接使用ex.printStackTrace()会在每行堆栈信息前后加入log4j的格式,既有垃圾信息,又影响美观,可以采用获取所有的堆栈信息后一次打印的方法来优化。
/**
* 获取完整的堆栈信息
* @param ex
* @return
*/
public static String getStackTrace(Throwable ex)
{
if (ex == null)
{
return "";
}
StringWriter sw = null;
PrintWriter out = null;
String stackTraceInfo = "";
try
{
sw = new StringWriter();
out = new PrintWriter(sw);
ex.printStackTrace(out);
stackTraceInfo = sw.toString();
}
catch (Exception e)
{
logger.error(e.getMessage());
}
finally
{
if (sw != null)
{
try
{
sw.close();
}
catch (Exception e2)
{
logger.error(e2.getMessage());
}
}
if (out != null)
{
try
{
out.close();
}
catch (Exception e2)
{
logger.error(e2.getMessage());
}
}
}
return stackTraceInfo;
}
不过美中不足的是,分析堆栈信息发现,多数情况下,在调用自己写的代码之前会调用不少所引用组件的代码,这些堆栈信息完全是多余的,有些碍眼,在分析了Throwable类的堆栈打印方法后,写了两个比较笨的方法来满足这个需求。
/**
* 获取有用的堆栈信息
* @param ex
* @return
*/
public static String getStackTraceInfo(Throwable ex)
{
if (ex == null)
{
return "";
}
StringBuffer stackTraceInfo = new StringBuffer(ex.toString());
StackTraceElement[] astacktraceelement = ex.getStackTrace();
for (int i = 0, size = astacktraceelement.length; i < size; i++)
{
String tmp = astacktraceelement[i].toString();
// 只获取指定包的下的异常堆栈跟踪信息
if (tmp.startsWith("com.lu"))
{
stackTraceInfo.append("\r\n\tat ").append(tmp);
}
else
{
break;
}
}
return stackTraceInfo.toString();
}
/**
* 获取指定深度的堆栈信息
* @param ex
* @param depth 堆栈跟踪深度
* @return
*/
public static String getStackTraceInfo(Throwable ex, int depth)
{
if (ex == null)
{
return "";
}
StringBuffer stackTraceInfo = new StringBuffer(ex.toString());
StackTraceElement[] astacktraceelement = ex.getStackTrace();
// 取指定深度与堆栈深度中小的值
int size = depth > astacktraceelement.length ? astacktraceelement.length : depth;
for (int i = 0; i < size; i++)
{
stackTraceInfo.append("\r\n\tat ").append(astacktraceelement[i]);
}
return stackTraceInfo.toString();
}