Java异常日志案例怎么记录

wen java案例 20

本文目录导读:

Java异常日志案例怎么记录

  1. 基础日志记录案例
  2. 不同级别异常记录
  3. 异步任务异常记录
  4. 批量处理异常记录
  5. 自定义异常日志格式
  6. Spring AOP 统一异常日志
  7. 最佳实践总结

我来介绍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>

这些案例展示了如何在实际开发中规范地记录异常日志,记住关键点:记录上下文、记录完整堆栈、合理使用日志级别、避免性能问题

抱歉,评论功能暂时关闭!