gRPC trial version: logback.xml and request response

Gatling version: 3.12.0 (must be up to date)

Hi, currently I’m looking into Gatling’s gRPC trial version, when I tried to run against server with this below code:

class GreetingSimulation extends Simulation {

  private val baseGrpcProtocol =
    grpc.forTarget("endpoint:80/subgrpc").usePlaintext
    val greeting = (session: io.gatling.core.session.Session) =>{
        GetPriceDetailRequest(
            appIds = Seq(1)
        )
    }
  private val unary = scenario("Greet Unary")
    .exec(
      grpc("GetPriceDetails")
        .unary(MyServiceGrpc.METHOD_MY_METHOD)
        .send(greeting)
        .check(
          statusCode.is(Status.Code.OK),
        )
    )
  setUp(
    unary.inject(atOnceUsers(1))
  ).protocols(baseGrpcProtocol)
}

I encounter 2 issues (maybe my skill issue? :smiley: )

  • logback.xml: enabling this
    <logger name="io.gatling.grpc.engine.response" level="TRACE" />
    doesn’t return any request/response details, I have put it in src/test/resources as demo project showcased.
  • When the request sent, I got the error: statusCode.is(OK), but actually found UNKNOWN; HTTP status code 500 invalid content-type: application/json;charset=UTF-8 headers: Metadata(:status=500,content-type=application/json;charset=UTF-8,date=Wed, 11 Sep 2024 07:22:32 GMT,x-unique-req-id=x,content-length=168) DATA---response data here---, but I can send on Postman normally, is there possibilities that I missed a specific settings in my code?

For point number 1, sadly the response logger doesn’t log much yet… we’ll see what we can do about that when we have the time.

However, for point number 2, the content type of a gRPC payload should always be application/grpc, we don’t understand how you end up with application/json. AFAICT, the use of application/grpc is hardcoded by the library we use.

  • How was the METHOD_MY_METHOD method descriptor generated?
  • Can we see the proto file or have any way to reproduce?
  • What does the server do?
  • Do you have some kind of proxy in between that transforms the payload such as gRPC-gateway?

Here is my protobuf file of METHOD_MY_METHOD:

syntax = "proto3";

package grpc.v1;

import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

message MyMethodRequest {
    repeated int64 app_ids = 1;
}

message MyMethodResponse {
    google.protobuf.Int32Value status_code = 1;
    repeated PriceDetail price_details = 2;
}

service MyService {
    rpc MyDetail(MyMethodRequest) returns (MyMethodResponse);
}

Sadly it is a little bit abstract, but I think name change only doesn’t affect much.

So for your Questions:
1/ If you ask about the way it was generated, I followed up with Gatling gRPC protocol reference - project setup, but if you ask about src_managed generated content then it will take me sometime to filter some information.
2/ Proto file above
3/ The server only send simple response back to client.
4/ Endpoint is direct access (not went through proxy).

We can’t reproduce yet. We don’t have the proto for PriceDetail, so we replaced it with a dummy one but I don’t think that would change much. We used the server from our demo project, changed it to use your proto file and removed TLS. It seems to work fine for us.

The main thing is that we don’t see any way that content type application/json would appear in our gRPC code. Is it possible to share the server you are using?

@notdryft
Sure, I will talk to my dev team and get back as soon as possible.
For your concern, it caused me attention that dev team may have not followed some baseline settings in internal env, I will also confirm with them about this.
.
More or less, the postman request was also not configured with any external headers or metadata, I’m unsure how was Postman managed to pass this

Then, I guess it is a possibility that, while the server is capable of receiving gRPC request, it is answering JSON with the wrong content type. Content type should always be application/grpc or application/grpc+json IIRC. If it is the case, I’m not sure how gRPC would behave, as I expect you would need a custom Unmarshaller or something.

Some extra Information:

  • That single Server is used to handle 2 gRPC service and 1 REST service, gRPC is on port 80 and REST is 443.
  • The response is in JSON format, no header would go along with it, in both dev document and Kreya’s (similar to Postman) check, In Postman it was coming with application/grpc and in Gatling is application/json.

I’m still going on checking with dev, but is there any slight chance that tool may fill the header itself?

Hi @trinp (just so you know, I work with @notdryft)

The response is in JSON format

This seems weird to me, because your protobuf file example above specifies a protobuf response (MyMethodResponse).

For what it’s worth, I just tried Postman’s gRPC support on our demo server (which is pure protobuf, no JSON support); Postman shows the request and response messages as JSON, but that’s just a way to display them (makes sense since the actual protobuf format is a binary format, and not human-readable). Just want to make sure there is no confusion there.

None of that explains the error, though. I’m afraid it’s kinda hard for us to understand without being able top reproduce/observe the actual server behavior.

There is another thing I just noticed: in your initial code sample, you specify the gRPC server address with grpc.forTarget("endpoint:80/subgrpc").

In gRPC Java (which we use in Gatling gRPC), as far as I know, it is not possible to change the path: only the host/port you specify will be taken into account (endpoint:80), and the path will be automatically constructed based on your service descriptor (so it will be endpoint:80/serviceName/methodName, not e.g. endpoint:80/subgrpc/serviceName/methodName).

See for example:

Seems like I couldn’t get any further information on server’s work, but according to your document, it seems that they have done some different configuration in routing (potentially this maybe the issue but they kind of refusing to fix it since Postman calls was OK).
.
Also, I did some comparison in Gatling’s official plugin and 3rd old party plugin before (sorry if this cause some uneasy feelings), it also convinced me that devs settings actually having problems, because both side return one same error :slight_smile: It is not Gatling’s problem
Thanks for your help, and sorry for being not able to provide more information.

but they kind of refusing to fix it since Postman calls was OK

The thing here is that there are many different gRPC implementations and there can be different bugs or different implementations. They are not identical.
Gatling’s gRPC support is currently based on the official grpc-java. But I guess Postman uses a different one, probably grpc-js or grpc-go.

So claiming that “it’s fine because it works with Postman” is probably a mistake. The application might be compatible with other client implementations.

1 Like

Maybe my expression was bad.
I meant my dev team refuse to fix, not the official gRPC-Java plugin team

That’s exactly what I understood. Your dev team shouldn’t reach the conclusion that “it works” because it works with Postman. It might not work with other client libraries, including official ones.

@ggaly @notdryft @slandelle thanks for helping me out.
Can’t believe I found this randomly:

grpc.forTarget("myTarget:80").overrideAuthority("/subgrpc").usePlaintext

That’s it :slight_smile: This is completely my skill issue now.
Confirmed working now.

Reference: grpc-node/packages/grpc-js/README.md at 605f14a0b5918bf6044d3652189ddacf97bfd421 · grpc/grpc-node · GitHub

Glad you managed to make it work. This is a bit surprising though, as from our understanding we see two different approaches:

  • With postman presumably using a subpath (assuming that is where your initial attempt with forTarget("endpoint:80/subgrpc") comes from). This means the request path would be /subgrpc/serviceName/methodName.
  • With Gatling using an authority override. This means the request path would be /serviceName/methodName but the pseudo header :authority would be set to /subgrpc (and we suspect it might work with just subgrpc).

These two are not equivalent so not sure how it works, maybe your server accepts both? Out of curiosity, what did the Postman configuration look like?

For Postman configuration, it’s completely fresh as newly downloaded, no extra configuration was made (I only use system proxy, but either turn on or off doesn’t affect this).
.
I am not sure if my findings were correct, I think this is what the Postman team has been doing: GitHub - postmanlabs/grpc-node: gRPC for Node.js
Just did some check with the Functional framework MochaJS, they did have to also enable this option as:

const client = new proto.MyService(myTargetHost, channel, {
     'grpc.default_authority': myTargetHost + '/subgrpc'
})

A way to debug similar stuff in the future is to use wireshark. When you can see the actual bytes sent, it’s much easier to see how the requests from Postman and gRPC-Java differ.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.