'GRPC Java: Populate/Clear the MDC on every request/message

Given a GRPC service (no matter if it is a simple RPC or uni/bidirectional service) how to correctly deal with the MDC?

I thought I'd implement a Server Interceptor where:

  1. Needed fields are retrieved from metadata (headers) (ex. correalation-id)
  2. A new Context is created with the retrieved metadata.
  3. A SimpleForwardingServerCallListener is returned. In the callbacks of the SimpleForwardingServerCallListener the MDC is populated/cleared.

Here is the code, and it seems to work as expected. Is this the correct way to handle this use-case? Thank you

public class GRPCLoggingInterceptor implements ServerInterceptor {


@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
                                                             Metadata headers,
                                                             ServerCallHandler<ReqT, RespT> next) {

    // Get Headers
    String correlationId = headers.get(Metadata.Key.of(CORRELATION_ID_HEADER_KEY, Metadata.ASCII_STRING_MARSHALLER));

    // Put headers into current Context
    Context context = Context.current()
                             .withValue(Context.key(CORRELATION_ID_HEADER_KEY),correlationId);

    // Obtain a listener attached to the current Context (Needed to propagate current context)
    ServerCall.Listener<ReqT> ctxlistener = Contexts.interceptCall(context, call, headers, next);

    // Configure the Callbacks to enrich and clean the MDC
    return new SimpleForwardingServerCallListener<>(ctxlistener) {
        @Override
        public void onMessage(ReqT message) {
            enrichMDC(correlationId);
            try {
                super.onMessage(message);
            } finally {
                clearMDC();
            }
        }

        @Override
        public void onHalfClose() {
            enrichMDC(correlationId);
            try {
                super.onHalfClose();
            } finally {
                clearMDC();
            }
        }

        @Override
        public void onCancel() {
            enrichMDC(correlationId);
            try {
                super.onCancel();
            } finally {
                clearMDC();
            }
        }

        @Override
        public void onComplete() {
            enrichMDC(correlationId);
            try {
                super.onComplete();
            } finally {
                clearMDC();
            }
        }

        @Override
        public void onReady() {
            enrichMDC(correlationId);
            try {
                super.onReady();
            } finally {
                clearMDC();
            }
        }
    };
}

private void enrichMDC(String correlationId) {
    MDC.put(CORRELATION_ID_MDC_KEY, correlationId);
}

private void clearMDC() {
    MDC.clear();
}

}



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source