Grpc-java: Per request logging params in GRPC server

Created on 17 Sep 2016  路  2Comments  路  Source: grpc/grpc-java

We use a logging framework that uses thread local map to store parameters for logging templates like request id, client ip etc.
Params are usually set and reset in some request filter (interceptor), with the assumption that the same thread is going to be used to handle the request.
From what I observe, GRPC server thread that handles request might be different from the thread that runs interceptor.
Is there any way to implement per-request logging parameter in GRPC server?

Most helpful comment

You may not be setting the logging context in every callback. An example of how an interceptor would look that does you want is below. If you wanted to unset the context, or reset it to what it was, or anything like that, you'd wrap the super calls in a try{}finally{}

@Override
    public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        final Map<String, String> mdcContext = buildMdcContext();
        MDC.setContextMap(mdcContext);

        final Listener<ReqT> original = next.startCall(call, headers);
        return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(original) {
            @Override
            public void onMessage(final ReqT message) {
                MDC.setContextMap(mdcContext);
                super.onMessage(message);
            }

            @Override
            public void onHalfClose() {
                MDC.setContextMap(mdcContext);
                super.onHalfClose();
            }

            @Override
            public void onCancel() {
                MDC.setContextMap(mdcContext);
                super.onCancel();
            }

            @Override
            public void onComplete() {
                MDC.setContextMap(mdcContext);
                super.onComplete();
            }

            @Override
            public void onReady() {
                MDC.setContextMap(mdcContext);
                super.onReady();
            }
        };
    }

All 2 comments

You may not be setting the logging context in every callback. An example of how an interceptor would look that does you want is below. If you wanted to unset the context, or reset it to what it was, or anything like that, you'd wrap the super calls in a try{}finally{}

@Override
    public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        final Map<String, String> mdcContext = buildMdcContext();
        MDC.setContextMap(mdcContext);

        final Listener<ReqT> original = next.startCall(call, headers);
        return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(original) {
            @Override
            public void onMessage(final ReqT message) {
                MDC.setContextMap(mdcContext);
                super.onMessage(message);
            }

            @Override
            public void onHalfClose() {
                MDC.setContextMap(mdcContext);
                super.onHalfClose();
            }

            @Override
            public void onCancel() {
                MDC.setContextMap(mdcContext);
                super.onCancel();
            }

            @Override
            public void onComplete() {
                MDC.setContextMap(mdcContext);
                super.onComplete();
            }

            @Override
            public void onReady() {
                MDC.setContextMap(mdcContext);
                super.onReady();
            }
        };
    }

Thanks, @jhspaybar for the fast response!
It is very helpful!

Was this page helpful?
0 / 5 - 0 ratings