【RPC】grpc 全局调用日志 & header 设置

269 阅读1分钟

实现目标

  • 日志输出 grpc 的 request 和 response 信息
  • 在 rpc 调用的 header 中添加调用链信息
  • 需要依赖将 message 序列化的工具(juejin.cn/post/738172…

代码

  • 拦截器实现
import com.google.protobuf.Message;
import io.grpc.*;
import net.devh.boot.grpc.client.interceptor.GrpcGlobalClientInterceptor;

import java.util.Optional;

/**
 * Example {@link ClientInterceptor} that logs all called methods in INFO log level, also request and response messages,
 * headers, trailers and interaction status in DEBUG log level. In this example it is added to Spring's application
 * context via {@link GlobalInterceptorConfiguration}, but is also possible to directly annotate this class with
 * {@link GrpcGlobalClientInterceptor}.
 */
public class GrpcClientGlobalInterceptor implements ClientInterceptor {
    private static final Metadata.Key<String> REQUEST_ID =
            Metadata.Key.of("request_id", Metadata.ASCII_STRING_MARSHALLER);
    private static final Metadata.Key<String> TRACE_ID =
            Metadata.Key.of("trace_id", Metadata.ASCII_STRING_MARSHALLER);

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
            final MethodDescriptor<ReqT, RespT> method, final CallOptions callOptions,
            final Channel next) {
        final long startTime = System.currentTimeMillis();

        return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
            ReqT requestMsg = null;

            @Override
            public void sendMessage(final ReqT message) {
                this.requestMsg = message;
                super.sendMessage(message);
            }

            @Override
            public void start(final Listener<RespT> responseListener, final Metadata headers) {
                // TODO: 添加调用链信息 
                headers.put(REQUEST_ID, "");
                headers.put(TRACE_ID, "");
                super.start(
                        new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
                            @Override
                            public void onMessage(final RespT message) {
                                super.onMessage(message);
                                // 日志
                                logGrpc(requestMsg, message, startTime);
                            }

                            @Override
                            public void onHeaders(final Metadata headers) {
                                super.onHeaders(headers);
                            }

                            @Override
                            public void onClose(final Status status, final Metadata trailers) {
                                super.onClose(status, trailers);
                            }
                        }, headers);
            }
        };
    }

    private void logGrpc(final Object req, final Object resp, final Long startTime) {
        try {
            final long timeCost = System.currentTimeMillis() - startTime;
            final String request = Optional.ofNullable(req)
                    .filter(r -> r instanceof Message)
                    .map(r -> GrpcFormatUtil.messageToStr((Message) r))
                    .orElse("null");
            final String response = Optional.ofNullable(resp)
                    .filter(r -> r instanceof Message)
                    .map(r -> GrpcFormatUtil.messageToStr((Message) r))
                    .orElse("null");
            // TODO: 打印日志 
        } catch (final Exception e) {
            // TODO: 异常处理 
        }
    }
}
  • 加载拦截器
/**  
 * Example configuration class that adds a {@link ClientInterceptor} to the global interceptor list.  
 */
@Configuration(proxyBeanMethods = false)  
public class GlobalInterceptorConfiguration {  
  
    /**  
     * Creates a new {@link LogGrpcInterceptor} bean and adds it to the global interceptor list. As an alternative you  
     * can directly annotate the {@code LogGrpcInterceptor} class and it will automatically be picked up by spring's  
     * classpath scanning.     *     * @return The newly created bean.  
     */    
    @GrpcGlobalClientInterceptor  
    LogGrpcInterceptor logClientInterceptor() {  
        return new LogGrpcInterceptor();  
    }  
  
}