// 基本版
package cn.com.utils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
public class ExceptionMsgUtils {
/**
* getExceptionInfo
* @param e
* @return result限制长度30000,MySQL text字段长65535,防止存不进去
*/
public static String getExceptionInfo(Exception e) {
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
e.printStackTrace(pw);
String result = sw.toString();
if(StringUtils.isNotBlank(result) && result.length() > 30000) {
result = result.substring(0,30000);
}
return result;
} finally {
if (null != sw) {
try {
sw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (null != pw) {
pw.close();
}
}
}
}
// 更加智能的升级版本
package cn.bevis;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ExceptionAdvUtil {
/**
* 项目基础包
*/
private static final String PROJECT_BASE_PACKAGE = "cn.bevis";
/**
* 将异常堆栈转换为字符串,智能过滤保留关键信息
* <p>
* 策略:
* 1. 前5行完整保留(包含异常类型、消息和关键调用位置)
* 2. 5行后只保留项目相关代码
* 3. 总长度不超过limit限制
* 4. 支持嵌套异常(Caused by)的关键信息提取
*
* @param e 异常对象
* @param limit 最大字符数限制
* @return 过滤后的异常堆栈字符串
*/
public static String stacktraceToString(Throwable e, int limit) {
try {
if (e == null || limit <= 0) {
return StrUtil.EMPTY;
}
String str = ExceptionUtil.stacktraceToString(e, 30000);
if (StrUtil.isBlank(str)) {
return StrUtil.EMPTY;
}
StringBuilder result = new StringBuilder(limit);
String[] lines = str.split(StrUtil.LF);
int lineCount = 0;
boolean inCausedBySection = false;
int causedByLineCount = 0;
for (String line : lines) {
// 检查是否超过限制长度
if (result.length() >= limit) {
break;
}
// 检测是否进入Caused by段落
if (line.trim().startsWith("Caused by:")) {
inCausedBySection = true;
causedByLineCount = 0;
}
// 判断是否应该保留该行
boolean shouldKeep = false;
if (!inCausedBySection) {
// 主异常:前5行全部保留
if (lineCount < 5) {
shouldKeep = true;
} else {
// 5行之后,只保留项目相关代码行
shouldKeep = isProjectRelevant(line);
}
} else {
// Caused by段落:每个cause的前3行保留(异常类型+消息+关键位置)
if (causedByLineCount < 3) {
shouldKeep = true;
} else {
// 之后只保留项目相关代码
shouldKeep = isProjectRelevant(line);
}
causedByLineCount++;
}
if (shouldKeep) {
appendLine(result, line, limit);
}
lineCount++;
}
return result.toString();
} catch (Throwable exception) {
log.warn("ExceptionAdvUtil.stacktraceToString 执行失败!", exception);
return ExceptionUtil.stacktraceToString(e, limit);
}
}
/**
* 安全地追加一行到结果中,确保不超过限制
*
* @param result 结果缓冲区
* @param line 要追加的行
* @param limit 最大长度限制
*/
private static void appendLine(StringBuilder result, String line, int limit) {
if (StrUtil.isBlank(line)) {
return;
}
int neededLength = line.length() + 1;
if (result.length() + neededLength <= limit) {
result.append(line).append(StrUtil.LF);
} else {
int remaining = limit - result.length();
if (remaining > 0) {
result.append(line.substring(0, remaining)).append(StrUtil.LF);
}
}
}
/**
* 判断该行是否与项目相关
*
* @param line 堆栈行
* @return 如果是项目相关代码返回true
*/
private static boolean isProjectRelevant(String line) {
return StrUtil.isNotBlank(line) && line.contains(PROJECT_BASE_PACKAGE);
}
}