dubbo分布式日志追踪:
需要修改两个地方,一个是consumer端的 InvokerInvocationHandler.java,红色是修改的地方
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
RpcInvocation invocation;
if (RpcUtils.hasGeneratedFuture(method)) {
Class<?> clazz = method.getDeclaringClass();
String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length());
Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes());
invocation = new RpcInvocation(syncMethod, args);
invocation.setAttachment(Constants.FUTURE_GENERATED_KEY, "true");
invocation.setAttachment(Constants.ASYNC_KEY, "true");
} else {
invocation = new RpcInvocation(method, args);
if (RpcUtils.hasFutureReturnType(method)) {
invocation.setAttachment(Constants.FUTURE_RETURNTYPE_KEY, "true");
invocation.setAttachment(Constants.ASYNC_KEY, "true");
}
}
// 这里将cosumer 端的traceId放入RpcInvocation
invocation.setAttachment("traceId", TraceIdUtil.getTraceId());
return invoker.invoke(invocation).recreate();
}
}
Provider端 DubboProtocol.java ,红色是修改的地方
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
@Override
public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
// need to consider backward-compatibility if it's a callback
if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) {
String methodsStr = invoker.getUrl().getParameters().get("methods");
boolean hasMethod = false;
if (methodsStr == null || !methodsStr.contains(",")) {
hasMethod = inv.getMethodName().equals(methodsStr);
} else {
String[] methods = methodsStr.split(",");
for (String method : methods) {
if (inv.getMethodName().equals(method)) {
hasMethod = true;
break;
}
}
}
if (!hasMethod) {
logger.warn(new IllegalStateException("The methodName " + inv.getMethodName()
+ " not found in callback service interface ,invoke will be ignored."
+ " please update the api interface. url is:"
+ invoker.getUrl()) + " ,invocation is :" + inv);
return null;
}
}
RpcContext rpcContext = RpcContext.getContext();
boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false);
if (supportServerAsync) {
CompletableFuture<Object> future = new CompletableFuture<>();
rpcContext.setAsyncContext(new AsyncContextImpl(future));
}
rpcContext.setRemoteAddress(channel.getRemoteAddress());
// 这里将收到的consumer端的traceId放入provider端的thread local
TraceIdUtil.setTraceId(inv.getAttachment("traceId"));
Result result = invoker.invoke(inv);
if (result instanceof AsyncRpcResult) {
return ((AsyncRpcResult) result).getResultFuture().thenApply(r -> (Object) r);
} else {
return CompletableFuture.completedFuture(result);
}
}
throw new RemotingException(channel, "Unsupported request: "
+ (message == null ? null : (message.getClass().getName() + ": " + message))
+ ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
自定义一个TraceIdUtil.java
/**
* Created by abin on 2018/7/31.
*/
public class TraceIdUtil {
private static final ThreadLocal<String> TRACE_ID = new ThreadLocal<String>();
public static String getTraceId() {
return TRACE_ID.get();
}
public static void setTraceId(String traceId) {
TRACE_ID.set(traceId);
}
}
dubbo客户端consumer代码和配置如下:
dubbo-consumer.xml:
<dubbo:consumer filter="logSessionFilter" timeout="9000"/>
/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter里面添加
logSessionFilter=com.abin.lee.dubbo.rpc.consumer.filter.RpcLogSessionFilter
RpcLogSessionFilter.java内容为:
public class RpcLogSessionFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String sessionId = UUID.randomUUID().toString();
String traceId = RpcContext.getContext().getAttachment("traceId");
if (StringUtils.isNotBlank(traceId)) {
System.out.println("accept traceId=" + traceId);
} else {
traceId = sessionId ;
System.out.println("create traceId=" + traceId);
}
RpcContext.getContext().setAttachment("traceId", traceId);
System.out.println("transfer traceId=" + traceId);
return invoker.invoke(invocation);
}
public static void main(String[] args) {
System.out.println(UUID.randomUUID().toString());
}
}
DubboClientServer.java
package com.abin.lee.dubbo.rpc.consumer;
import com.abin.lee.dubbo.rpc.api.DubboService;
import com.abin.lee.dubbo.rpc.api.GlobalService;
import com.abin.lee.dubbo.rpc.common.util.JsonUtil;
import com.abin.lee.dubbo.rpc.enums.UserRole;
import com.abin.lee.dubbo.rpc.model.UserInfo;
import com.google.common.collect.Lists;
import org.apache.dubbo.common.TraceIdUtil;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
/**
* Created by abin on 2017/9/7 2017/9/7.
* march-svr
* com.abin.lee.march.svr.dubbo.client.view
*/
public class DubboClientServer {
public static void main(String[] args) throws InterruptedException {
//traceId
main_filter();
}
public static void main_filter() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath*:spring/dubbo-consumer.xml"});
context.start();
DubboService dubboService = (DubboService) context.getBean("dubboService"); // 获取bean
String message = "";
try {
int randomTraceId = (int) (Math.random() * 1000);
TraceIdUtil.setTraceId(randomTraceId+"");
message = dubboService.build("2016-10-20");
System.out.println("dubboService.build-- the message from server is:" + message);
List<Integer> list = dubboService.findById(5);
System.out.println("dubboService.findById--- the message from server is:" + JsonUtil.toJson(list));
String traceId = RpcContext.getContext().getAttachment("traceId");
System.out.println(" the message from server is result traceId :" + traceId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端Provider:
dubbo-provider.xml
<dubbo:provider filter="logSessionFilter" timeout="9000"/>
/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter里面添加
logSessionFilter=com.abin.lee.dubbo.rpc.provider.filter.ProviderRpcLogSessionFilter
ProviderRpcLogSessionFilter.java
import org.apache.dubbo.rpc.*;
/**
*
*/
public class ProviderRpcLogSessionFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String traceId = RpcContext.getContext().getAttachment("traceId");
System.out.println("ProviderRpcLogSessionFilter accept traceId=" + traceId);
//服务段处理完了,给客户端回传回去之前他自己传过来的traceId
// RpcContext.getContext().setAttachment("traceId", traceId);
return invoker.invoke(invocation);
}
}
DubboServer.java
package com.abin.lee.dubbo.rpc.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by abin on 2017/9/7 2017/9/7.
* march-svr
* com.abin.lee.march.svr.dubbo.server.view
*/
public class DubboServer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"classpath*:spring/dubbo-provider.xml"});
context.start();
System.out.println("................................................");
System.out.println(".......Dubbo Server is Running now!..............");
System.out.println("................................................");
System.in.read(); // 按任意键退出
}
}