注:记录开发,自己总结,随便写写,不喜勿喷。
问题描述
之前有聊过怎么去在web服务与dubbo服务记录调用日志。
web服务:https://blog.youkuaiyun.com/weixin_42459814/article/details/128961326
dubbo服务:https://blog.youkuaiyun.com/weixin_42459814/article/details/128960789
那问题来了,怎么把整个链路的日志连起来呢?不可能看参数吧?
解决方案
一般会考虑程序入口生成一个全局唯一的ID,也就是分布式唯一ID,然后在整个调用链传递下去,那具体怎么做呢?(分布式id生成这里不讲哈)
如在tomcat服务中加个拦截器(或者aop),如下:
@Aspect
@Component
public class Aspect {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("@annotation(esa.restlight.spring.shaded.org.springframework.web.bind.annotation.RequestMapping)" +
" || @annotation(esa.restlight.spring.shaded.org.springframework.web.bind.annotation.PostMapping)" +
" || @annotation(esa.restlight.spring.shaded.org.springframework.web.bind.annotation.GetMapping)"
)
public void controllerMethods() {
// Do nothing
}
@Around("controllerMethods()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
AsyncRequest request = RequestResponseHolder.getRequest();
long start = System.currentTimeMillis();
//request中取或者生成traceId存入MDC,看自己怎么生成
String traceId = getTraceId();
MDC.put("traceId", traceId);
LOGGER.info("<<==request:{},param {} ==>>", request.path(), pjp.getArgs());
Object result = pjp.proceed();
LOGGER.info("<<==response:{},param {},result ,{} ,time,{} ==>>",
request.path(), pjp.getArgs(), result, System.currentTimeMillis() - start);
//这里要删哦,MDC用的ThreadLocal
MDC.remove("traceId");
return result;
}
}
公共包给Dubbo服务增加filter
@Activate(
group = {Constants.CONSUMER}
)
public class MDCLogConsumerFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(RequestContextConsumerFilter.class);
@Override public Result invoke(
Invoker<?> invoker, Invocation invocation) throws RpcException {
String traceId = MDC.get("traceId");
logger.debug("trace id : {}", traceId);
try {
//没有traceId,要去创建一个哦
if (StringUtils.isEmpty(traceId)) {
traceId = getTraceId();
}
RpcInvocation rpcInvocation = (RpcInvocation)invocation;
rpcInvocation.setAttachment("traceId", traceId);
} catch (Throwable throwable) {
logger.warn("设置traceId 失败", throwable);
}
return invoker.invoke(invocation);
}
}
@Activate(
group = {Constants.PROVIDER}
)
public class MDCLogProviderFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(MDCLogProviderFilter.class);
@Override public Result invoke(
Invoker<?> invoker, Invocation invocation) throws RpcException {
String traceId = invocation.getAttachment("traceId");
logger.debug("trace id : {}", traceId);
if (StringUtils.isEmpty(traceId)) {
traceId = UUID.randomUUID().toString().replace("-", "");
logger.debug("获取traceId失败,生成新的traceId : {}", traceId);
}
Result result = null;
try {
MDC.put(KEY, traceId);
result = invoker.invoke(invocation);
} finally {
MDC.remove(KEY);
}
return result;
}
}
正常情况下,这样就在整个链路都有同一个traceId了,那我们在配置日志打印格式的时候,把traceId打印进去就好了,如下:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-[%traceId] %-5level %logger{36} - %msg%n