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