Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gRPC client instrumentation #687

Merged

Conversation

alanwest
Copy link
Member

@alanwest alanwest commented May 19, 2020

This PR partially addresses issue #482 adding client-side instrumentation for grpc-dotnet.

Copy link
Contributor

@pjanotti pjanotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @alanwest - just an initial quick pass, it will be interesting to put this together with some gRPC client and tests (I assume this comes when it is not draft anymore).

var rx = new Regex(@"(?<package>\w+).(?<service>\w+)/(?<method>\w+)", RegexOptions.Compiled);
var rpcService = rx.Match(path).Groups["service"].Value;

span.SetAttribute("rpc.service", rpcService);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@cijothomas we probably should create a package with the OTel semantic tags.

@pjanotti
Copy link
Contributor

BTW @alanwest you will need to sign the CLA :)

@alanwest
Copy link
Member Author

alanwest commented May 19, 2020

BTW @alanwest you will need to sign the CLA :)

Done.

it will be interesting to put this together with some gRPC client and tests (I assume this comes when it is not draft anymore).

Yes, I will plan to include something. I've been testing locally with some of the example applications from the grpc-dotnet repository. There's an example setup to work with Open Telemetry: https://github.com/grpc/grpc-dotnet/tree/master/examples#aggregator.

span.SetAttribute("net.peer.port", request.RequestUri.Port);
}

// Do we want to propagate trace context here? GrpcClient is built on top of HttpClient.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to understand this better. Do we end up with 2 spans, one from httpclient, and another from grpcclient, both essentially representing the same thing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, two spans are generated. First the one from the grpcclient and then one from httpclient as a child.

I think it makes sense to only produce the span from the grpcclient. HttpClient instrumentation checks for the traceparent header which seems to suggest this kind of scenario was anticipated? Though traceparent assumes W3C format, so it seems like there needs to be a more general check here if we want to prevent both spans from being generated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual order of events would be like Grpc.Start, HttpClient.Start, HttpClient.Stop, Grpc.Stop right? The httpclient span would be the child of grpc one.

This is essentially same as a user making a httpclient call inside a using(span=startactivespan()) block, which result in 2 span, 1 from customer created, and other from httpclient. In this case, we'd want to see both spans. customer span as parent, httpclient span as child.

Applying this principle to Grpc->HttpClient, it looks okay to see both spans. But if both are essentially same information then its redundant. Maybe let user decide if they want to suppress the child.?

Instead of looking at traceparent presence, we can check the activity.Parent inside httpclient, which would be that of Grpc.

(Just my initial thoughts, we need to discuss this more)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual order of events would be like Grpc.Start, HttpClient.Start, HttpClient.Stop, Grpc.Stop right? The httpclient span would be the child of grpc one.

Correct.

My initial impression was that the information was redundant, though I can understand why it may be desirable to show both since it is an accurate representation of what's really happening.

I've seen similar cases from some database drivers that use HttpClient or HttpWebRequest behind the scenes. I've found it intuitive to show only a span for the database operation but not the underlying http request.

I'll share some screenshots of some traces in the gitter channel tomorrow, so we can discuss further.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay.
Adding @shirhatti to this discussion :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The traces I've generated seem to suggest that the HttpClient activity ends with the request headers being received. I can dig into the code to be sure of this. Though here's a trace I've captured:

Screen Shot 2020-05-22 at 6 18 39 PM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and I think having both HTTP and gRPC spans is a little untidy, however I do think it's important to indicate the gPRC call was made over HTTP (it is theoretically possible to use other transports than HTTP).

It may also help identify an issue with the HTTP client when trying to help diagnose an issue by highlighting extra latency / errors.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is theoretically possible to use other transports than HTTP

Ah yes, interesting. I had not thought about this use case. Agreed it would be useful to note that the call was over HTTP in this case. As far as I know, the library currently only supports HTTP/2 at the moment (perhaps I'm wrong about this?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cijothomas and I spoke briefly regarding this issue. His thoughts:

my take would be this - lets not make any assumptions about what user wants - make it configurable to user. let user decide if they want to see grpc only or httpclient only or both. we can discuss the default behavior later.

I think this stance makes sense for now. My thought for this PR is to move forward without any attempt to suppress the spans generated from the HttpClient instrumentation. Then perhaps follow up as a separate effort with the idea of making this configurable and deciding on defaults.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and think we should show everything as you are now. If we need to tighten up later, we can, maybe though configuration.

@alanwest alanwest force-pushed the alanwest/grpc-dotnet-instrumentation branch from 8d0f366 to 0f45daa Compare May 20, 2020 19:47
@alanwest
Copy link
Member Author

I signed it

@funkeyfreak
Copy link

funkeyfreak commented Jun 16, 2020

@alanwest, do you need any help on this PR? My team is moving a ton of high-use protocols to GRPC, so this is very interesting to me :)

<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />

<PackageReference Include="Google.Protobuf" Version="3.12.3" />
<PackageReference Include="Grpc.AspNetCore" Version="2.25.0" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should update to 2.30.0. It resolves race conditions between the response task being completed and the listener being written to.

Otherwise looks good to go.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Yep did the trick. I updated to 2.30.0-pre1 since it appears that 2.30.0 has not been published for all the dependencies yet. I can come back and update this again when they have been published.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh oh. Hehe, seems we're back to the same build error I was experiencing a few days back. You mentioned there may be other ways to resolve this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, we can ignore the Azure pipeline. i think we will just use Github Actions for now...
@cijothomas , what do you think?

@cijothomas cijothomas merged commit 401737e into open-telemetry:master Jul 6, 2020
@JamesNK
Copy link
Contributor

JamesNK commented Jul 7, 2020

🍰 🎉 🎈

@alanwest alanwest deleted the alanwest/grpc-dotnet-instrumentation branch July 7, 2020 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants