Dubbo 自定义Filter实现日志追踪
背景
dubbo : 3.0.9
Spring Boot: 2.0.X
错误的写法
官网的描述:
在 Dubbo 3 中,RpcContext 被拆分为四大模块(ServerContext、ClientAttachment、ServerAttachment 和 ServiceContext)。
它们分别承担了不同的职责:
- ServiceContext:在 Dubbo 内部使用,用于传递调用链路上的参数信息,如 invoker 对象等
- ClientAttachment:在 Client 端使用,往 ClientAttachment 中写入的参数将被传递到 Server 端
- ServerAttachment:在 Server 端使用,从 ServerAttachment 中读取的参数是从 Client 中传递过来的
- ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在>调用结束后可以在 Client 端的 ServerContext 获取到
消费端
@Activate(group = {CommonConstants.CONSUMER},order = Integer.MIN_VALUE)
public class CustomDubboTraceConsumerFilter implements Filter {
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*
* @param invoker
* @param invocation
*/
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String traceId = ThreadMdcUtil.getTraceId();
if (traceId != null) {
//将追踪ID写入到上下文,给生产端使用
RpcContext.getClientAttachment().setAttachment(FrameConstant.REQUEST_ID_KEY,traceId);
}
// 调用下一个 Filter 或直接执行 RPC 调用
Result result = invoker.invoke(invocation);
return result;
}
}
生产端
@Activate(group = {CommonConstants.PROVIDER},order = Integer.MIN_VALUE)
public class CustomDubboTraceProviderFilter implements Filter {
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*
* @param invoker
* @param invocation
*/
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//读取消费端传入的追踪ID
String traceId = RpcContext.getServerAttachment().getAttachment(FrameConstant.REQUEST_ID_KEY);
if (traceId != null) {
//写入日志上下文
ThreadMdcUtil.setTraceId(traceId);
}
try {
// 调用下一个 Filter 或直接执行 RPC 调用
Result result = invoker.invoke(invocation);
return result;
} finally {
if (traceId != null) {
// 根据需要清理 MDC,避免对后续请求造成影响
ThreadMdcUtil.removeTraceId();
}
}
}
}
正确的写法
消费端
@Activate(group = {CommonConstants.CONSUMER},order = Integer.MIN_VALUE)
public class CustomDubboTraceConsumerFilter implements Filter {
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*
* @param invoker
* @param invocation
*/
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String traceId = ThreadMdcUtil.getTraceId();
if (traceId != null) {
//将追踪ID写入到上下文,给生产端使用
invocation.setAttachment(FrameConstant.REQUEST_ID_KEY,traceId);
}
// 调用下一个 Filter 或直接执行 RPC 调用
Result result = invoker.invoke(invocation);
return result;
}
}
生产端
@Activate(group = {CommonConstants.PROVIDER},order = Integer.MIN_VALUE)
public class CustomDubboTraceProviderFilter implements Filter {
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*
* @param invoker
* @param invocation
*/
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//读取消费端传入的追踪ID
String traceId = invocation.getAttachment(FrameConstant.REQUEST_ID_KEY);
if (traceId != null) {
//写入日志上下文
ThreadMdcUtil.setTraceId(traceId);
}
try {
// 调用下一个 Filter 或直接执行 RPC 调用
Result result = invoker.invoke(invocation);
return result;
} finally {
if (traceId != null) {
// 根据需要清理 MDC,避免对后续请求造成影响
ThreadMdcUtil.removeTraceId();
}
}
}
}
通过SPI 方式启用
在项目中新建 src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter
文本文件,配置自定义的过滤器:
customDubboTraceConsumerFilter=com.abc.springboot.frame.dubbo.CustomDubboTraceConsumerFilter
customDubboTraceProviderFilter=com.abc.springboot.frame.dubbo.CustomDubboTraceProviderFilter
参数传递总结
消费端 | 服务端 |
---|---|
RpcContext.getClientAttachment().setAttachment | invocation.getAttachment |
RpcContext.getServerAttachment().setAttachment | 取不到 |
RpcContext.getServerContext().setAttachment | 取不到 |
invocation.setAttachment | invocation.getAttachment |
服务端 | 消费端 |
---|---|
RpcContext.getClientAttachment().setAttachment | 取不到 |
RpcContext.getServerAttachment().setAttachment | 取不到 |
RpcContext.getServerContext().setAttachment | 取不到 |
invocation.setAttachment | 取不到 |