本文目录导读:

我来介绍Java异常日志记录的几种典型案例和最佳实践。
基础日志记录案例
使用SLF4J + Logback
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExceptionLoggerDemo {
private static final Logger logger = LoggerFactory.getLogger(ExceptionLoggerDemo.class);
public void processData(String data) {
try {
// 业务处理逻辑
validateData(data);
saveToDatabase(data);
} catch (IllegalArgumentException e) {
// 错误案例:只记录异常信息
logger.error("处理数据失败:" + e.getMessage());
// 正确案例:记录完整异常堆栈
logger.error("处理数据失败,data={}", data, e);
} catch (SQLException e) {
// 记录关键上下文和异常
logger.error("数据库操作失败,data={},错误代码={}", data, e.getErrorCode(), e);
} catch (Exception e) {
// 兜底异常处理
logger.error("处理数据时发生未知异常,data={}", data, e);
}
}
}
不同级别异常记录
@Service
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public Order createOrder(OrderRequest request) {
try {
// 1. 参数校验异常 - WARN级别
if (request.getAmount() <= 0) {
logger.warn("订单金额异常,request={}", request);
throw new BusinessException("订单金额必须大于0");
}
// 2. 业务逻辑异常 - ERROR级别
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> {
logger.error("用户不存在,userId={}", request.getUserId());
return new BusinessException("用户不存在");
});
// 3. 外部服务调用异常 - ERROR级别
try {
paymentService.process(request.getAmount());
} catch (PaymentException e) {
logger.error("支付服务调用失败,orderId={},amount={}",
request.getOrderId(), request.getAmount(), e);
throw new BusinessException("支付失败", e);
}
// 4. 性能监控 - INFO级别
logger.info("订单创建成功,orderId={},userId={},amount={}",
order.getId(), request.getUserId(), request.getAmount());
return order;
} catch (BusinessException e) {
// 业务异常直接抛出
throw e;
} catch (Exception e) {
// 未知异常
logger.error("创建订单失败,request={}", request, e);
throw new RuntimeException("系统异常,请稍后重试", e);
}
}
}
异步任务异常记录
@Component
public class AsyncTaskLogger {
private static final Logger logger = LoggerFactory.getLogger(AsyncTaskLogger.class);
@Async
public void processTask(Task task) {
// 记录任务开始
logger.info("开始处理异步任务,taskId={},taskType={}",
task.getId(), task.getType());
try {
// 业务处理
task.execute();
// 记录任务完成
logger.info("异步任务处理完成,taskId={},耗时={}ms",
task.getId(), task.getDuration());
} catch (Exception e) {
// 异步任务异常必须记录完整信息
logger.error("异步任务执行失败,taskId={},taskType={},parameters={}",
task.getId(), task.getType(), task.getParameters(), e);
// 可以发送告警通知
alertService.sendAlert("异步任务失败", task.getId(), e);
}
}
}
批量处理异常记录
public class BatchProcessor {
private static final Logger logger = LoggerFactory.getLogger(BatchProcessor.class);
public void batchProcess(List<Record> records) {
int successCount = 0;
int failCount = 0;
List<String> errorMessages = new ArrayList<>();
for (int i = 0; i < records.size(); i++) {
Record record = records.get(i);
try {
processRecord(record);
successCount++;
// 定期打印进度
if ((i + 1) % 100 == 0) {
logger.info("批量处理进度:{}/{},成功:{},失败:{}",
i + 1, records.size(), successCount, failCount);
}
} catch (Exception e) {
failCount++;
String errorMsg = String.format("第%d条记录处理失败,recordId=%s,原因:%s",
i + 1, record.getId(), e.getMessage());
logger.error(errorMsg, e);
errorMessages.add(errorMsg);
}
}
// 汇总日志
logger.info("批量处理完成,总数:{},成功:{},失败:{}",
records.size(), successCount, failCount);
if (!errorMessages.isEmpty()) {
logger.warn("失败详情:{}", String.join("; ", errorMessages));
}
}
}
自定义异常日志格式
public class LoggingUtil {
private static final Logger logger = LoggerFactory.getLogger(LoggingUtil.class);
// 统一异常日志格式
public static void logException(Exception e, String businessType,
Map<String, Object> context) {
LogEvent logEvent = LogEvent.builder()
.businessType(businessType)
.exceptionClass(e.getClass().getName())
.exceptionMessage(e.getMessage())
.context(context)
.timestamp(LocalDateTime.now())
.build();
// 记录结构化日志
logger.error("业务异常日志: {}", logEvent.toJson(), e);
}
// 使用示例
public void businessMethod() {
try {
// 业务逻辑
} catch (Exception e) {
Map<String, Object> context = new HashMap<>();
context.put("userId", 12345);
context.put("orderId", "ORDER20231234");
context.put("requestAmount", 100.0);
LoggingUtil.logException(e, "ORDER_CREATE", context);
}
}
}
Spring AOP 统一异常日志
@Aspect
@Component
public class ExceptionLogAspect {
private static final Logger logger = LoggerFactory.getLogger(ExceptionLogAspect.class);
@Around("@annotation(LogException)")
public Object handleException(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().toShortString();
Object[] args = joinPoint.getArgs();
try {
Object result = joinPoint.proceed();
// 记录成功日志
logger.info("方法调用成功:{},参数:{},耗时:{}ms",
methodName, args, System.currentTimeMillis() - startTime);
return result;
} catch (BusinessException e) {
// 业务异常,记录WARN级别
logger.warn("业务异常:{},方法:{},参数:{}",
e.getMessage(), methodName, args);
throw e;
} catch (Exception e) {
// 系统异常,记录ERROR级别,包含完整堆栈
logger.error("系统异常:{},方法:{},参数:{},耗时:{}ms",
methodName, args, System.currentTimeMillis() - startTime, e);
throw new RuntimeException("系统繁忙,请稍后重试", e);
}
}
}
最佳实践总结
日志记录原则:
public class LoggingBestPractices {
// ✅ 正确:记录上下文信息和异常
public void correctExample() {
try {
// 业务逻辑
} catch (Exception e) {
logger.error("处理订单失败,orderId={},userId={}", orderId, userId, e);
}
}
// ❌ 错误:只记录异常信息
public void wrongExample() {
try {
// 业务逻辑
} catch (Exception e) {
logger.error(e.getMessage()); // 丢失堆栈信息
logger.error("处理失败"); // 没有上下文
}
}
// ✅ 正确:区分日志级别
public void levelExample() {
// 业务异常用WARN
if (amount <= 0) {
logger.warn("金额异常,amount={}", amount);
}
// 系统异常用ERROR
try {
databaseService.save(data);
} catch (SQLException e) {
logger.error("数据库保存失败,data={}", data, e);
}
// 正常流程用INFO
logger.info("数据保存成功,id={}", savedId);
// 调试信息用DEBUG
if (logger.isDebugEnabled()) {
logger.debug("详细参数:{}", JSON.toJSONString(complexObject));
}
}
// ✅ 正确:避免日志级别判断
public void performanceExample() {
// ❌ 错误:字符串拼接无论是否记录日志都会执行
logger.debug("User data: " + JSON.toJSONString(user));
// ✅ 正确:使用占位符,只在需要记录时才会处理
logger.debug("User data: {}", JSON.toJSONString(user));
}
}
配置文件示例(logback-spring.xml):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 异常日志单独文件 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/error.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 所有日志文件 -->
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/all.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
这些案例展示了如何在实际开发中规范地记录异常日志,记住关键点:记录上下文、记录完整堆栈、合理使用日志级别、避免性能问题。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播