JAVA中基于AOP做接口日志的打印及异常处理

直接上代码:

package com.xiyuan.cluster.middle.interceptor;

import com.alibaba.fastjson.JSON;
import com.xiyuan.cluster.middle.common.GlobalExceptionHandler;
import com.xiyuan.cluster.middle.entity.SysLog;
import com.xiyuan.cluster.middle.service.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;


/**
 * @author jerry
 * @desc 记录日志
 * @datetime 2023/07/31
 */
@Slf4j
@Component
@Aspect
public class LogAop {
    private static final Logger logger = LoggerFactory.getLogger(LogAop.class);

    /**
     * 全局异常处理类全限定名
     */
    private String exceptionAdviceName = GlobalExceptionHandler.class.getName();

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ISysLogService logService;

    //定义日志捕获范围 全局controller接口参数
//    @Pointcut("execution(* com.xiyuan.cluster.middle.controller..*.*(..)) || execution(* com.xiyuan.cluster.middle.common.GlobalExceptionHandler.*(..))")
    @Pointcut("execution(* com.xiyuan.cluster.middle.controller..*.*(..)))")
    public void logAroundPointCut() {
    }

    /**
     * controller层入参日志记录
     */
    @Around("logAroundPointCut()")
    public Object intoControllerLog(ProceedingJoinPoint point) throws Throwable {
        // 目标方法所在类全限定名
        String targetName = point.getSignature().getDeclaringType().getName();
        String className = ClassUtils.getShortName(targetName);
        // 目标方法名
        String methodName = point.getSignature().getName();
        StringBuilder reqStr = new StringBuilder(300);
        String phone = (String) request.getAttribute("phone");
        try {
            if (targetName.equals(exceptionAdviceName)) {
                // controller参数解析异常不会进入目标方法, 而直接请求异常处理器
                logger.error("全局日志【{}.{}】接口调用异常,用户手机号:{},异常信息:{}", className, methodName, phone, "请求异常, 未进入controller");
            } else {
                // 获取请求参数
                Object[] args = point.getArgs();
                String[] paramsName = ((MethodSignature) point.getSignature()).getParameterNames();
                //记录入参4
                if (args != null && paramsName != null && args.length > 0 && paramsName.length > 0) {
                    for (int i = 0; i < paramsName.length; i++) {
                        reqStr.append(" ").append(paramsName[i]).append(" = ").append(args[i]).append(",");
                    }
                    reqStr.deleteCharAt(reqStr.length() - 1);
                }
                logger.info("全局日志【{}.{}】接口开始调用,用户手机号:{},入参:{}", className, methodName, phone, reqStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("全局日志入参处理异常:{}", e.getMessage());
        }
        // 调用目标方法
        Object result = point.proceed();
        logger.info("全局日志【{}.{}】接口调用结束, 入参:{}, 出参:{}", className, methodName, reqStr, JSON.toJSONString(result));
        return result;
    }

    /**
     * 异常通知: 对目标对象发生异常下进行增强,有异常就执行,没有就不执行
     * 作用:目标代码出现异常,记录异常日志
     */
    @AfterThrowing(value = "execution(* com.xiyuan.cluster.middle.controller..*.*(..)))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        try {
            SysLog sysLog = new SysLog();
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            logger.warn("保存错误日志开始【{}.{}】", className, methodName);
            StringBuilder reqStr = new StringBuilder(300);
            String respStr = "";
            Object[] args = joinPoint.getArgs();
            String[] paramsName = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
            //记录入参
            if (args != null && paramsName != null && args.length > 0 && paramsName.length > 0) {
                for (int i = 0; i < paramsName.length; i++) {
                    reqStr.append(" ").append(paramsName[i]).append(" = ").append(args[i]).append(",");
                }
                reqStr.deleteCharAt(reqStr.length() - 1);
            }
            logger.error("错误日志【{}.{}】接口开始调用,入参:{}", className, methodName, reqStr);
            // 将异常的堆栈信息转换为字符串
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            String stackTrace = sw.toString();
            String phone = (String) request.getAttribute("phone");
            sysLog.setClassName(className);
            sysLog.setMethodName(methodName);
            sysLog.setRequest(reqStr.toString());
            sysLog.setResponse(respStr);
            sysLog.setException(stackTrace);
            sysLog.setPhone(phone);
            //保存异常信息
            logService.save(sysLog);
            logger.warn("保存错误日志结束【{}.{}】", className, methodName);
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("保存日志异常:{}", e.getMessage());
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值