Spring统一日志处理(AOP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zc_ad/article/details/83306123

来现在公司的缘故,公司大佬使用的AOP比较多,本来在校时候对AOP只是一知半解,在现在公司呆了半年,用到了各种拦截器,对AOP有了许多新的认识。此处用统一日志处理就是使用的是Spring AOP实现的。

定义统一日志表,用在将所有请求都记录在表中,方便以后查阅。

CREATE TABLE `t_union_log`  (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `dev_mac` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备MAC',
  `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户身份',
  `level` int(11) NULL DEFAULT 0 COMMENT '日志级别,0-最高级别',
  `method` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作方式',
  `remote_host` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作IP地址',
  `request_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求URI',
  `user_agent` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户代理',
  `module_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '模块名称',
  `param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求参数',
  `result` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '结果',
  `spent` bigint(20) NULL DEFAULT NULL COMMENT '耗费时间-毫秒',
  `ctime` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) 

定义实体类与DAO,此处使用的是mybatis-plus,使用其他的也可以,自行选择,这些都不重要,重要的是后面的aop拦截器。

@TableName("t_union_log")
public class UnionLogEntity {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

    private String devMac;

    private String userId;

    private Integer level;

    private String method;

    private String remoteHost;

    private String requestUri;

    private String userAgent;

    private String moduleName;

    private String param;

    private String result;

    private Long spent;

    private Date ctime;

    Getter...
    Setter...
}
@Mapper
public interface UnionLogMapper extends BaseMapper<UnionLogEntity>{
}

实现统一日志的拦截。原理很简单,只要懂得一些AOP方面的知识,看代码很容易看的懂。特别注意的是,在不需要拦截的URI,一定不能进行日志打印(如:文件下载接口,会报内存溢出错误,以前写文件下载的时候遇到,再次铭记)

/**统一日志处理*/
@Aspect
@Component
public class GlobalLogAspect {
    private Logger logger = LoggerFactory.getLogger(GlobalLogAspect.class);
    private static final String POINTCUT = "execution(* com.xichuan.wechat.*.controller.*.*(..)) ";

    private static final ThreadLocal<Map<Object,Object>> paramLocal = new ThreadLocal<>();
    private static final ThreadLocal<Map<Object,Object>> resultsLocal = new ThreadLocal<>();
    private static final ThreadLocal<Long> start = new ThreadLocal<>();
    private static final ThreadLocal<Long> end = new ThreadLocal<>();
    private static final ThreadLocal<HttpServletRequest> httpRequest = new ThreadLocal<>();

    @Autowired
    UnionLogMapper unionLogMapper;

    @Before(POINTCUT)
    public void beforeAspectHandler(){
        start.set(System.currentTimeMillis());
    }

    @After(POINTCUT)
    public void afterAspectHandler(){

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String uri = request.getRequestURI();
        if(uri.equals("")){ /**不进行日志拦截的URI*/
            logger.info("global log Aspect untreated uri:"+uri);
        }else{
            end.set(System.currentTimeMillis());
            this.tracer();
        }
    }

    @Around(POINTCUT)
    public Object aroundAspectHandler(ProceedingJoinPoint joinPoint)throws Throwable{
        Object[] param = joinPoint.getArgs();
        Map<Object,Object> argMap = new LinkedHashMap<>();
        argMap.put("params",param);
        paramLocal.set(argMap);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        httpRequest.set(request);
        Object result = joinPoint.proceed();

        Map<Object,Object> resMap = new LinkedHashMap<>();
        resMap.put("results",result);
        resultsLocal.set(resMap);

        return result;
    }

    public void tracer(){
        try {
            HttpServletRequest request = httpRequest.get();
            Gson gson = new Gson();
            logger.info("Request PATH: {}, Time: {}, Consumed: {}ms, Param: {}, Result: {}\n",
                    "["+request.getRequestURI()+"]",
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:s").format(start.get()),
                    (end.get()-start.get()),
                    gson.toJson(paramLocal.get()),
                    gson.toJson(resultsLocal.get()));

            UnionLogEntity unionLog = new UnionLogEntity();
            unionLog.setCtime(new Date());
            unionLog.setMethod(request.getMethod());
            unionLog.setRequestUri(request.getRequestURI());
            unionLog.setRemoteHost(request.getRemoteHost());
            unionLog.setUserAgent(request.getHeader("User-Agent"));
            unionLog.setParam(gson.toJson(paramLocal.get()));
            unionLog.setResult(gson.toJson(resultsLocal.get()));
            unionLog.setSpent(end.get()-start.get());
            unionLog.setUserId(request.getHeader(("account_id")));
            unionLog.setDevMac(request.getHeader(("dev_mac")));
            unionLog.setModuleName("cmd");
            unionLogMapper.insert(unionLog);

        }finally {
            httpRequest.remove();
            paramLocal.remove();
            resultsLocal.remove();
            start.remove();
            end.remove();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zc_ad/article/details/83306123