1. 概述

JPAAS作为一个分布式微服务系统,如果在访问的过程中,系统出错了,我们需要记录日志,方便我们排查问题,我们需要解决一下几个问题:

1.错误日志落在各个微服务的系统中,我们需要打开多个日志文件去查找问题。
2.比如发起流程,如果表单出错,这个时候流程也会报错,那么我们在记录错误的时候,需要知道这两个错误是不是一个请求产生的。

现在系统解决了这个问题

  • 在系统出错时,我们通过全局错误捕获错误,并将错误信息通过队列,写入到数据库。
  • 在发起请求时,网关产生一个UID,后端的服务可以获取这个UID,并且可以通过FEIGN进行传递这个UID,这样我们在写错误日志的时候,我们会同时将这个UID写入到日志,方便我们查询。

2. 代码实现

2.1.网关实现

网关负责生成一个唯一ID,并添加到请求头中。

public class TracerFilter implements GlobalFilter, Ordered {
    @Autowired
    private TraceProperties traceProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.debug("traceProperties");
        if (traceProperties.getEnable()) {
            //链路追踪id
            String traceId = IdUtil.fastSimpleUUID();
            MDC.put(CommonConstant.LOG_TRACE_ID, traceId);
            ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate()
                    .headers(h -> h.add(CommonConstant.TRACE_ID_HEADER, traceId))
                    .build();

            ServerWebExchange build = exchange.mutate().request(serverHttpRequest).build();
            return chain.filter(build);
        }
        return chain.filter(exchange);

    }

2.2.微服务请求头处理

微服务请求过滤器,负责获取 traceId请求头,并将这个请求头放到MDC中。

public class TraceFilter implements Filter   {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            HttpServletRequest request=(HttpServletRequest)servletRequest;
            String traceId = request.getHeader(CommonConstant.TRACE_ID_HEADER);
            if (StringUtils.isNotEmpty(traceId)) {
                MDC.put(CommonConstant.LOG_TRACE_ID, traceId);
            }

            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            MDC.clear();
        }
    }
}

2.3. FEIGN处理

负责从上下文获取traceId,并放到下一个请求的 请求头中。

TokenRelayRequestIntecepor

// 2.传递TRACEID。
        String traceId = MDC.get(CommonConstant.LOG_TRACE_ID);
        if (StringUtils.isNotBlank(traceId)) {
            requestTemplate.header(CommonConstant.TRACE_ID_HEADER, traceId);
        }

2.4 写错误日志

ExceptionHandlerAdvice

private void handLog(String message){

        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String url=request.getRequestURI();
        SysErrorLogDto sysErrorLogDto=new SysErrorLogDto();
        sysErrorLogDto.setAppName(applicationName);
        sysErrorLogDto.setContent(message);
        sysErrorLogDto.setUrl(url);
        sysErrorLogDto.setTraceId(MDC.get(CommonConstant.LOG_TRACE_ID));

        errLogOutput.logOutput().send(MessageBuilder.withPayload(sysErrorLogDto).build());
    }

3. 最佳实践

我们在写代码的时候,不要catch错误,如果catch了,那么我们没有办法通过全局错误捕获,捕获到错误信息。如果捕获了,我们要么自己处理错误信息,要么 再次将异常抛出。

try{

}
catch(Exception ex){
     String message=ExceptionUtil.getExceptionMessage(e);
     MessageUtil.triggerException("启动流程失败!",message);
}
文档更新时间: 2021-07-19 18:41   作者:zyg