AOP+MySQL实现一个简历的日志收集工具

一、自定义日志注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description 日志监控自定义注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface WebLog {

    WebApiLogType logType() default WebApiLogType.NULL;

    String desc() default "";

    String name() default "";
}

二、定义AOP逻辑

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
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.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class WebLogApiAspect {

    private static final Logger log = LoggerFactory.getLogger(WebLogApiAspect.class);

    public final static String POST ="POST", GET = "GET";

    @Autowired
    private LogService logService;

    /**
     * 采用异步逻辑处理日志保存,降低整体调用的时间
     * <p>只开一个线程处理日志保存逻辑,防止流量洪峰压垮保存逻辑侧</p>
     * <p>拒绝策略采用直接拒绝而非交给主线程处理,则当前的监控日志只能承担1001的TPS</p>
     */
    public static Executor EXECUTOR = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new ThreadPoolExecutor.AbortPolicy());

    @Pointcut("@annotation(com.common.aop.WebLog) ")
    public void webLogPoint() {
    }

    @Around("webLogPoint()")
    public Object webLogRecord(ProceedingJoinPoint point) throws Throwable {

        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (Objects.isNull(requestAttributes)){
            return point.proceed();
        }
        HttpServletRequest request = requestAttributes.getRequest();
        Object result=null;
        Exception e = null;
        try {
            result= point.proceed();
        } catch (Exception exception) {
            e = exception;
            throw exception;
        } finally {
            try {
               save(request,point,result,e);
            } catch (Exception aopException) {
                log.error("webLogRecord error", aopException);
            }
        }
        return result;
    }

    private void save(HttpServletRequest request, ProceedingJoinPoint point, Object result, Exception e) {
        LogParam webApiLogParam = new LogParam();
        if (POST.equalsIgnoreCase(request.getMethod())){
            //根据不同的请求类型存入请求内容:POST
            String requestBody = WebLogUtil.buildPostParam(point);
            webApiLogParam.setRequestBody(requestBody);
            log.info("Request Args  :"+ WebLogUtil.buildPostParam(point));
        } else if (GET.equalsIgnoreCase(request.getMethod())) {
            //GET
           webApiLogParam.setRequestBody(request.getQueryString());
            log.info("get Args : "+ request.getQueryString());
        } else {
            log.info("接口监控只支持REST风格的GET/POST方法,当前方法为 {}", request.getMethod());
            return;
        }

        //请求参数组装
        buildRequestParam(webApiLogParam,request,point);
        //响应结果过组装
        buildResultParam(webApiLogParam, result);
        //异常信息组装
        if (null!=e) {
            buildExceptionParam(webApiLogParam, e);
        }
        EXECUTOR.execute(() -> {
            //日志model发送到api_web
            try {
                logService.getBaseMapper().insert(BeanUtil.copyProperties(webApiLogParam, WebApiLogParam.class));
            } catch (Exception exception) {
                log.error("日志监控保存失败",exception);
            }
        });
    }

    private void buildExceptionParam(LogParam webApiLogParam, Exception exception) {
        webApiLogParam.setException(1);
        webApiLogParam.setExceptionMessage(exception.toString());
        webApiLogParam.setErr(exception.toString());

    }

    private void buildRequestParam(LogParam webApiLogParam, HttpServletRequest request, ProceedingJoinPoint point) {
        //反射获取自定义注解
        WebLog webLog = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(WebLog.class);
        webApiLogParam.setUrl(request.getRequestURL().toString());
        webApiLogParam.setMethod(request.getMethod());
        webApiLogParam.setRetry(0);
        webApiLogParam.setApi(point.getSignature().toString());
        if (StringUtils.isNotEmpty(request.getServletPath())){
            webApiLogParam.setSourceCode(Objects.requireNonNull(webLog.name()));
            webApiLogParam.setSourceType(Objects.requireNonNull(webLog.desc()));
        }
        webApiLogParam.setCreator(IpUtils.getIpAddr(request));
        webApiLogParam.setCreateTime(new Date());
        webApiLogParam.setIsDeleted(0);

    }


    public void buildResultParam(LogParam webApiLogParam,Object result) {
        try {
            if (result instanceof ChannelResult) {
                ChannelResult<?> modelResult = (ChannelResult<?>) result;
                if (ChannelResultUtil.isSuccess(modelResult)) {
                    webApiLogParam.setResult(0);
                }else {
                    webApiLogParam.setResult(1);
                }
                webApiLogParam.setResponseBody(JSON.toJSONString(modelResult));
            } else if (result instanceof ChannelResult) {
                ChannelResult<?> modelResult = (ChannelResult<?>) result;
                if (ChannelResultUtil.isSuccess(modelResult)) {
                    webApiLogParam.setResult(0);
                }else {
                    webApiLogParam.setResult(1);
                }
                webApiLogParam.setResponseBody(JSON.toJSONString(modelResult));
            }else {
                webApiLogParam.setResult(0);
                webApiLogParam.setResponseBody(JSON.toJSONString(result));
            }
        } catch (Exception exception) {
            log.error("组装响应结果失败", exception);
        }
    }
}

三.日志类和工具

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Objects;

/**
 * @ClassName WebLogUtil
 */
@Component
public class WebLogUtil {

    public static String buildPostParam(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Annotation[] parameterAnnotation = parameterAnnotations[i];
            if (null != parameterAnnotation) {
                for (Annotation annotation : parameterAnnotation) {
                    Objects.equals(RequestBody.class, annotation.getClass());
                    if (args[i] == null) return null;
                    return JSON.toJSONString(args[i]);
                }
            }
        }
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (parameter.getType() != HttpServletRequest.class
                    && parameter.getType() != HttpServletResponse.class
                    && parameter.getType() != ServletRequest.class
                    && parameter.getType() != ServletResponse.class) {
                if (args[i] == null) return null;
                return JSON.toJSONString(args[i]);
            }
        }
        return null;
    }
}

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
 * @Description 日志监控模型
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class LogParam implements Serializable {

    private Long id;
    /**
     * 来源单号
     */
    private String sourceCode;
    /**
     * 来源类型
     */
    private String sourceType;
    /**
     * 请求方式
     */
    private String method;
    /**
     * 请求入参
     */
    private String requestBody;
    /**
     * 响应参数
     */
    private String responseBody;
    /**
     * 接口推送结果
     * 0成功1失败
     */
    private Integer result;
    /**
     * 错误信息
     */
    private String err;
    /**
     * 有无异常
     * 0有1没有
     */
    private Integer exception;
    /**
     * 异常信息
     */
    private String exceptionMessage;
    /**
     * 重试标志
     * 0是1否
     */
    private Integer retry;
    /**
     * 接口地址
     */
    private String url;
    /**
     * 请求方法
     */
    private String api;
    private Date createTime;
    private Date modifyTime;
    private Integer isDeleted;
    private String creator;
    private Long modifier;
}

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;

public class IpUtils {
    private static Logger logger = LoggerFactory.getLogger(IpUtils.class);
    public IpUtils() {
    }
    public static String getIpAddr(HttpServletRequest request) {
        String unknown = "unknown";
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception var4) {
            logger.error("IPUtils ERROR ", var4);
        }
        return ip;
    }
}
import com.baomidou.mybatisplus.extension.service.IService;
import com.dal.log.entity.WebApiLogParam;
public interface LogService extends IService<WebApiLogParam> {
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值