title: How to intercept the headers from in call to one service and insert it to another request in gRPC-java?
body: <p>I have two servers - HelloServer and WorldServer.</p>
  <p>Both implement the same proto file:</p>
  <pre class="lang-proto prettyprint-override"><code>// The greeting service definition.
  service GreeterService {
      // Sends a greeting
      rpc GreetWithHelloOrWorld (GreeterRequest) returns (GreeterReply) {}
      rpc GreetWithHelloWorld (GreeterRequest) returns (GreeterReply) {}
  }
  
  message GreeterRequest {
      string id = 1;
  }
  
  // The response message containing the greetings
  message GreeterReply {
      string message = 1;
      string id = 2;
  }
  </code></pre>
  <p>I want to add traceIds to the requests. As far as I understand, this is achieved through adding the traceId in the Metadata object.</p>
  <p>Here is the test I am using to check that the traceIds are passed along. The request is made to the HelloServer which in turns calls the WorldServer and then finally returns the response.</p>
  <pre class="lang-java prettyprint-override"><code>@Test
  public void greetHelloWorld() {
      String traceId = UUID.randomUUID().toString();
      Metadata metadata = new Metadata();
      metadata.put(MetadataKeys.TRACE_ID_METADATA_KEY, traceId);
  
      Greeter.GreeterRequest greeterRequest = Greeter.GreeterRequest.newBuilder().setId(traceId).build();
  
      ManagedChannel channel = ManagedChannelBuilder
          .forAddress(&quot;localhost&quot;, 8080)
          .usePlaintext(true)
          .build();
  
      AtomicReference&lt;Metadata&gt; trailersCapture = new AtomicReference&lt;&gt;();
      AtomicReference&lt;Metadata&gt; headersCapture = new AtomicReference&lt;&gt;();
      ClientInterceptor clientInterceptor = MetadataUtils.newAttachHeadersInterceptor(metadata);
      ClientInterceptor metadataCapturingClientInterceptor = MetadataUtils.newCaptureMetadataInterceptor(headersCapture, trailersCapture);
  
      GreeterServiceBlockingStub blockingStub = GreeterServiceGrpc.newBlockingStub(ClientInterceptors.intercept(channel, clientInterceptor, metadataCapturingClientInterceptor));
      GreeterServiceStub asyncStub = GreeterServiceGrpc.newStub(channel);
  
      try {
          Greeter.GreeterReply greeterReply = blockingStub.greetWithHelloWorld(greeterRequest);
          String idInResponse = greeterReply.getId();
          String idInHeaders = headersCapture.get().get(MetadataKeys.TRACE_ID_METADATA_KEY);
          logger.info(&quot;Response from HelloService and WorldService  -- , id = {}, headers = {}&quot;, greeterReply.getMessage(), idInResponse, idInHeaders);
          assertEquals(&quot;Ids in response and header did not match&quot;, idInResponse, idInHeaders);
      } catch (StatusRuntimeException e) {
          logger.warn(&quot;Exception when calling HelloService and WorldService\n&quot; +  e);
          fail();
      } finally {
          channel.shutdown();
      }
  }
  </code></pre>
  <p>Implementation of ServerInterceptor:</p>
  <pre class="lang-java prettyprint-override"><code>@Override
  public &lt;ReqT, RespT&gt; ServerCall.Listener&lt;ReqT&gt; interceptCall(ServerCall&lt;ReqT, RespT&gt; call, Metadata headers, ServerCallHandler&lt;ReqT, RespT&gt; next) {
  
      String traceId = headers.get(MetadataKeys.TRACE_ID_METADATA_KEY);
      logger.info(&quot;objId=&quot; + this.toString().substring(this.toString().lastIndexOf('@')) + &quot; Trace id -- 1=&quot; + headers.get(MetadataKeys.TRACE_ID_METADATA_KEY));
      return next.startCall(new ForwardingServerCall.SimpleForwardingServerCall&lt;ReqT, RespT&gt;(call) {
          @Override
          public void sendHeaders(Metadata headers) {
              headers.put(MetadataKeys.TRACE_ID_METADATA_KEY, traceId);
              logger.info(&quot;objId=&quot; + this.toString().substring(this.toString().lastIndexOf('@')) + &quot; Trace id -- 2  &quot; + headers.get(MetadataKeys.TRACE_ID_METADATA_KEY));
              super.sendHeaders(headers);
          }
  
          @Override
          public void sendMessage(RespT message) {
             logger.info(&quot;objId=&quot; + this.toString().substring(this.toString().lastIndexOf('@')) + &quot; message=&quot; + message.toString());
              super.sendMessage(message);
          }
      }, headers);
  </code></pre>
  <p>Here is the implementation of the greetWithHelloWorld() method:</p>
  <pre class="lang-java prettyprint-override"><code>public void greetWithHelloWorld(com.comcast.manitoba.world.hello.Greeter.GreeterRequest request,
                                          io.grpc.stub.StreamObserver&lt;com.comcast.manitoba.world.hello.Greeter.GreeterReply&gt; responseObserver) {
          Greeter.GreeterRequest greeterRequest = Greeter.GreeterRequest.newBuilder().setId(request.getId()).build();
      
          Metadata metadata = new Metadata();
          metadata.put(MetadataKeys.TRACE_ID_METADATA_KEY, &quot;&quot;);
      
          ManagedChannel channel = ManagedChannelBuilder.forAddress(&quot;localhost&quot;, 8081)
                  .usePlaintext(true).build();
      
          AtomicReference&lt;Metadata&gt; trailersCapture = new AtomicReference&lt;&gt;();
          AtomicReference&lt;Metadata&gt; headersCapture = new AtomicReference&lt;&gt;();
          ClientInterceptor clientInterceptor = MetadataUtils.newAttachHeadersInterceptor(metadata);
          ClientInterceptor metadataCapturingClientInterceptor = MetadataUtils.newCaptureMetadataInterceptor(headersCapture, trailersCapture);
      
          GreeterServiceGrpc.GreeterServiceBlockingStub blockingStub = GreeterServiceGrpc.newBlockingStub(ClientInterceptors.intercept(channel, clientInterceptor, metadataCapturingClientInterceptor));
      
          String messageFromWorldService = &quot;&quot;;
          String replyIdFromWorldService = &quot;&quot;;
          try {
              Greeter.GreeterReply greeterReply = blockingStub.greetWithHelloOrWorld(greeterRequest);
              messageFromWorldService = greeterReply.getMessage();
              replyIdFromWorldService = greeterReply.getId();
              logger.info(&quot;Response from WorldService  -- {}, id = {}&quot;, messageFromWorldService, replyIdFromWorldService);
          } catch (StatusRuntimeException e) {
              logger.warn(&quot;Exception when calling HelloService\n&quot; +  e);
          }
      
          Greeter.GreeterReply greeterReply = Greeter.GreeterReply.newBuilder().setMessage(&quot;Hello&quot; + messageFromWorldService).setId(replyIdFromWorldService).build();
          responseObserver.onNext(greeterReply);
          responseObserver.onCompleted();
      }
  </code></pre>
  <p>The problem is in the greetWithHelloWorld() method, I don't have access to Metadata, so I cannot extract the traceId from the header and attach it to the request to the World server. However, if I put a breakpoint in that method, I can see that request object does have the traceId in it which is private to it and unaccessible.</p>
  <p>Any ideas how can I achieve this? Also, is this the best way to do pass traceIds around? I found some references to using Context. What is the difference between Context and Metadata?</p>