spring cloud中实现日志追踪

  • 网关中设置filter对每一个请求的header中进行设置traceID(用于追踪每一个请求),并将traceSort(用于对后续请求进行排序)存入redis中
  • 在其余微服务中添加AOP对需要追踪的进行日志搜集

部分代码示例

package com.zy.zygateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zy.core.model.RedisKey;
import com.zy.zygateway.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import java.util.UUID;

/**
 * 〈为每一个请求添加traceid〉
 */
@Component
@Slf4j
public class TraceIDFilter extends ZuulFilter {

    @Autowired
    private RedisService redisService;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        // 每一个请求都必须拦截
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        // 为每一个请求添加traceid
        String traceId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        String traceSort = new Integer(0).toString();

        RequestContext requestContext = RequestContext.getCurrentContext();

        requestContext.addZuulRequestHeader("Trace-Id", traceId);
//        requestContext.addZuulRequestHeader("Request-Sort", traceSort);
        redisService.set(RedisKey.LOG.OPERATIONLOG + traceId, traceSort, 20L);
        log.info("请求【{}】,进入TraceIDFilter,成功分配Trace-Id【{}】",
                requestContext.getRequest().getRequestURL(),
                traceId);
        return null;
    }
}
package com.zy.zypayservice.config;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Configuration
public class HystrixCredentialsContext {

    private static final HystrixRequestVariableDefault<Authentication> authentication = new HystrixRequestVariableDefault<>();

    private static final HystrixRequestVariableDefault<HttpServletRequest> httpRequest = new HystrixRequestVariableDefault<>();

    public static HystrixRequestVariableDefault<Authentication> getInstance() {
        return authentication;
    }

    public static HystrixRequestVariableDefault<HttpServletRequest> getHttpRequestInstance() {
        return httpRequest;
    }

    @Bean
    public RequestInterceptor requestTokenBearerInterceptor() {

        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                Authentication auth = HystrixCredentialsContext.getInstance().get();
                HttpServletRequest request = HystrixCredentialsContext.getHttpRequestInstance().get();
                if (auth != null) {
                    requestTemplate.header("Trace-Id",
                            request.getHeader("Trace-Id"));
//                    requestTemplate.header("Request-Sort",
//                            String.valueOf(Integer.valueOf(request.getHeader("Request-Sort")).intValue() + 1));
                    if (!StringUtils.isEmpty(auth.getPrincipal()) && !auth.getPrincipal().toString().equals("anonymousUser")) {
                        if (auth instanceof OAuth2Authentication && auth.getDetails() instanceof OAuth2AuthenticationDetails) {
                            requestTemplate.header("Authorization",
                                    "bearer " + ((OAuth2AuthenticationDetails) auth.getDetails()).getTokenValue());

                        } else {
                            requestTemplate.header("Authorization", "");
                        }
                    } else {
                        requestTemplate.header("Authorization", "");
                    }
                }
            }
        };

    }

    @Bean
    public FilterRegistrationBean hystrixFilter() {

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new Filter() {

            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
            }

            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {

                HystrixRequestContext.initializeContext();
                SecurityContext securityContext = SecurityContextHolder.getContext();
                if (securityContext != null) {
                    Authentication auth = (Authentication) securityContext.getAuthentication();
                    HystrixCredentialsContext.getInstance().set(auth);
                }
                chain.doFilter(request, response);

            }

            @Override
            public void destroy() {

            }

        });

        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;

    }
}

package com.zy.zypayservice.aop;

import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.zy.api.client.ZyRemoteClient.log.ZyHistoryRecordClient;
import com.zy.common.log.ZYLoggerManage;
import com.zy.core.annotation.ZyBizAnnBean;
import com.zy.core.annotation.ZyBizAnnotation;
import com.zy.core.model.BDic;
import com.zy.core.model.RedisKey;
import com.zy.model.log.in.AddZyHistoryRecordIn;
import com.zy.model.utils.ZyUserUtil;
import com.zy.zypayservice.config.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.NamedThreadLocal;
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 javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.CompletableFuture;

@Component
@Aspect
@Slf4j
public class RsetAPIAspectj {

    @Autowired
    private ZyHistoryRecordClient zyHistoryRecordClient;

    private static final ThreadLocal<AddZyHistoryRecordIn> paramThreadLocal = new NamedThreadLocal<AddZyHistoryRecordIn>("Param beginTime");

    @Value("${spring.application.name}")
    private String projectName;

    @Autowired
    private RedisService redisService;

    @Pointcut("execution(* com.zy.zypayservice.controller..*.*(..)) || execution(* com.zy.core.base.ZyBaseController.exceptionHandler())")
    public void resetAPIPointcut() {}

    /**
     * <方法执行之前>
     *
     * @param jp
     * @return void
     * @date 2019/1/3 10:22
     */
    @Before(value = "resetAPIPointcut()")
    public void restAPIBefore(JoinPoint jp) {
        String httpReqParam = null;
        String ip = null;

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        StringBuilder sb = new StringBuilder();
        try {
            AddZyHistoryRecordIn in = new AddZyHistoryRecordIn();

            for (Object obj : jp.getArgs()) {
                if (obj instanceof HttpServletRequest) {
                    in.setParams(JSONObject.toJSONString(((HttpServletRequest) obj).getParameterMap()));
                } else if (obj instanceof HttpServletResponse) {

                } else if (obj instanceof Throwable) {
                    in.setException(obj.getClass().getName());
                    in.setExceptionDescribe(((Throwable) obj).getMessage());
                    in.setType(BDic.LOG_LEVEL.ERROR);
                } else {
                    ip = "ip:[" + request.getRemoteAddr() + "]";
                    httpReqParam = JSONObject.toJSONString(obj);

                    in.setParams(httpReqParam);
                    sb.append(ip).append(httpReqParam);
                    sb.append(JSONObject.toJSONString(obj));
                }
            }

            // 获取方法中注释内容
            ZyBizAnnBean mthodRemark = getMthodRemark(jp);
            // 获取追踪ID
            String traceId = request.getHeader("Trace-Id");
            // 获取请求次序号
            Integer requestSort = 0;
            boolean flag = true;
            do {
                Object obj = null;
                try {
                    obj = redisService.get(RedisKey.LOG.OPERATIONLOG + traceId);
                    if (obj != null) {
                        requestSort = Integer.valueOf(String.valueOf(obj));
                        redisService.set(RedisKey.LOG.OPERATIONLOG + traceId,
                                requestSort + 1,
                                200L);
                        flag = false;
                    }
                } catch (Exception e) {
                    flag = false;
                }
            } while (flag);
            // 判断是否有 ZyBizAnnBean 注解,有:执行历史记录 没有:不执行
            if (mthodRemark != null) {
                in.setTraceId(traceId);
                in.setProjectName(projectName);
                in.setSort(requestSort);
                String account = "";
                if (ZyUserUtil.getLoginUser() == null) {
                    account = "匿名";
                } else {
                    account = ZyUserUtil.getLoginUser().getAccount();
                }
                in.setAccount(account);
                in.setContent(mthodRemark.getOption());
                in.setSource(BDic.LOG_MODULE.BACK_MANAGER);
                in.setUrl(request.getRequestURL().toString());
                in.setIp(request.getRemoteAddr());
                in.setType(BDic.LOG_LEVEL.INFO);
                in.setUrlType(request.getMethod());
                in.setMethod(jp.getSignature().getName());
                in.setClassname(jp.getTarget().getClass().getName());
                in.setCreateTime(new Date());
                // 将请求参数存储到本地线程中
                paramThreadLocal.set(in);
            }
        }
        catch(Exception e) {
            log.error("AOP异常【{}】" + e.getMessage());
        } finally {
            log.info("====调用【{}】方法-开始:{}", jp.getSignature().toString(), sb);
        }
    }

    /**
     * <方法执行完成之后>
     *
     * @param jp
     * @param returnVal
     * @return void
     * @date 2019/1/3 10:21
     */
    @AfterReturning(pointcut = "resetAPIPointcut()", returning = "returnVal")
    public void restAPIAfter(JoinPoint jp, Object returnVal) {
        AddZyHistoryRecordIn addZyHistoryRecordIn = paramThreadLocal.get();
        StringBuilder sb = new StringBuilder();
        try {
            if (addZyHistoryRecordIn != null) {

                addZyHistoryRecordIn.setResParams(JSONObject.toJSONString(returnVal));
                addZyHistoryRecordIn.setEndTime(new Date());

                CompletableFuture.runAsync(() -> {
                    HystrixRequestContext context = HystrixRequestContext.initializeContext();
                    try {
                        zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    } finally {
                        context.shutdown();
                    }
                });
            }
        } catch(Exception e) {
            log.error("AOP异常【{}】" + e.getMessage());
        } finally {
            sb.append(JSONObject.toJSONString(returnVal));
            log.info("====调用【{}】方法-开始:{}", jp.getSignature().toString(), sb);
        }
    }

    /**
     * <方法抛出异常>
     *
     * @param joinPoint
     * @param e
     * @return void
     * @date 2018/12/29 11:27
     */
    @AfterThrowing(pointcut = "resetAPIPointcut()", throwing = "e")
    public void restAPIAfterThrow(JoinPoint joinPoint, Throwable e) {

        try {
            AddZyHistoryRecordIn addZyHistoryRecordIn = paramThreadLocal.get();
            addZyHistoryRecordIn.setType(BDic.LOG_LEVEL.ERROR);
            addZyHistoryRecordIn.setException(e.toString());
            addZyHistoryRecordIn.setEndTime(new Date());
            zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
            CompletableFuture.runAsync(() -> {
                try {
                    HystrixRequestContext.initializeContext();
                    zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            });
        } catch (Exception e1) {
            ZYLoggerManage.error(this.getClass(), "后置异常日志拦截异常", e1);
        }
    }

    /**
     * <获取方法的注释信息>
     *
     * @param joinPoint
     * @return com.zy.core.annotation.ZyBizAnnBean
     * @date 2018/12/28 16:16
     */
    public ZyBizAnnBean getMthodRemark(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();

        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        ZyBizAnnBean zab = null;
        for (Method m : method)
        {
            if (m.getName().equals(methodName))
            {
                Class[] tmpCs = m.getParameterTypes();
                if (tmpCs.length == arguments.length)
                {
                    ZyBizAnnotation methodCache = m.getAnnotation(ZyBizAnnotation.class);
                    if (methodCache != null)
                    {
                        String option = methodCache.option();
                        String name = methodCache.name();
                        zab = new ZyBizAnnBean();
                        zab.setName(name);
                        zab.setOption(option);
                        return zab;
                    }
                }
            }
        }
        return zab;
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值