How do you read/log gRPC HTTP headers (not custom metadata)?

2.9k views Asked by At

I am working with gRPC and Protobuf, using a C++ server and a C++ client, as well as a grpc-js client. Is there a way to get a read on all of the HTTP request/response headers from the transport layer in gRPC? I am looking for the sort of typical client/server HTTP headers - particularly, I would like to see what version of the protocol is being used (whether it is HTTP1.1/2). I know that gRPC is supposed to be using HTTP2, but I am trying to confirm it at a low level.

In a typical gRPC client implementation you have something like this:

class PingPongClient {
 public:
  PingPongClient(std::shared_ptr<Channel> channel)
      : stub_(PingPong::NewStub(channel)) {}

  // Assembles the client's payload, sends it and presents the response back
  // from the server.
  PingPongReply PingPong(PingPongRequest request) {
    // Container for the data we expect from the server.
    PingPongReply reply;

    // Context for the client. It could be used to convey extra information to
    // the server and/or tweak certain RPC behaviors.
    ClientContext context;

    // The actual RPC.
    Status status = stub_->Ping(&context, request, &reply);

    // Act upon its status.
    if (status.ok()) {
        return reply;
    } else {
      auto errorMsg = status.error_code() + ": " + status.error_message();
      std::cout << errorMsg << std::endl;
      throw std::runtime_error(errorMsg);
    }
  }

 private:
  std::unique_ptr<PingPong::Stub> stub_;
};

and on the serverside, something like:

class PingPongServiceImpl final : public PingPong::Service {
  Status Ping(
    ServerContext* context,
    const PingPongRequest* request,
    PingPongReply* reply
  ) override {
    std::cout << "PingPong" << std::endl;
    printContextClientMetadata(context->client_metadata());

    if (request->input_msg() == "hello") {
      reply->set_output_msg("world");
    } else {
      reply->set_output_msg("I can't pong unless you ping me 'hello'!");
    }

    std::cout << "Replying with " << reply->output_msg() << std::endl;

    return Status::OK;
  }
};

I would think that either ServerContext or the request object might have access to this information, but context seems to only provide an interface into metadata, which is custom.

None of the gRPC C++ examples give any indication that there is such an API, nor do any of the associated source/header files in the gRPC source code. I have exhausted my options here in terms of tutorials, blog posts, videos, and documentation - I asked a similar question on the grpc-io forum, but have gotten no takers. Hoping the SO crew has some insights here!

I should also note that I experimented with passing a variety of environment variables as flags to the running processes to see if I can get details about HTTP headers, but even with these flags enabled (the HTTP-related ones), I do not see basic HTTP headers.

1

There are 1 answers

3
murgatroid99 On BEST ANSWER

First, the gRPC libraries absolutely do use HTTP/2. The protocol is explicitly defined in terms of HTTP/2.

The gRPC libraries do not directly expose the raw HTTP headers to the application. However, they do have trace logging options that can log a variety of information for debugging purposes, including headers. The tracers can be enabled by setting the environment variable GRPC_TRACE. The environment variable GRPC_VERBOSITY=DEBUG should also be set to make sure that all of the logs are output. More information can be found in this document describing how the library uses envinronment variables.

In the C++ library, the http tracer should log the raw headers. The grpc-js library has different internals and different tracer definitions, so you should use the call_stream tracer for that one. Those will also log other request information, but it should be pretty easy to pick out the headers.