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

CP-44752: propagate System.Diagnostics tracing information using W3C traceparent header #5929

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

edwintorok
Copy link
Contributor

The newer System.Net.Http would propagate this automatically, but the older WebRequest doesn't.

Retrieve the span identifier and add the header ourselves. The WebRequest object is fresh for each request, so setting the headers shouldn't cause race conditions.

This adds a dependency on a library that is part of .Net source repository, but distributed outside of it on NuGet: System.Diagnostics. Lock the dependency to a given hash to avoid accidental/malicious changes.
This dependency is not available on .Net45, so all the code and build dependencies are wrapped with appropriate conditional compilation directives (which may look kind of ugly, they can be dropped once XenServer.dll drops support for .Net45 and switches to .Net462 minimum).

No new instrumentation is created, so if the application using XenServer.dll is not configured/set up to use OpenTelemetry or System.Diagnostics.DiagnosticSource, then this is a no-op.

I've tested this using the Powershell 7 module.

Draft PR because:

  • I haven't tested the version with the locked dependencies yet
  • There is one TODO in the code about obtaining a version number

…ency

This only exists on .Net 4.6+, so add it conditionally only when target >Netstandard 2.0
(which includes .Net 4.6).

This allows creating activity spans, independently of the tracing framework used.

Signed-off-by: Edwin Török <[email protected]>
@edwintorok
Copy link
Contributor Author

Internal build succeeded with locked package dependencies too.

@edwintorok edwintorok marked this pull request as ready for review August 12, 2024 14:57
@edwintorok
Copy link
Contributor Author

I think I'll also need NET462_OR_GREATER otherwise XC won't pick this up.

Doesn't exist on .Net45.

Signed-off-by: Edwin Török <[email protected]>
This is not available on .Net 4.5

Signed-off-by: Edwin Török <[email protected]>
To avoid someone injecting a malicious binary with the same version in the future,
lock all dependencies.

Signed-off-by: Edwin Török <[email protected]>
@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from c2723ca to 3037f81 Compare August 12, 2024 16:17
@danilo-delbusso danilo-delbusso requested review from kc284 and danilo-delbusso and removed request for kc284 August 21, 2024 09:51
Copy link
Member

@danilo-delbusso danilo-delbusso left a comment

Choose a reason for hiding this comment

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

haven't tested it yet but I spotted a couple of things on the first run

for SDK PRs also please request reviews manually, because we don't monitor the repo as often as toolstack does, so it helps to see PR reviews under https://github.com/pulls

@@ -155,6 +158,11 @@ public partial class JsonRpcClient
{
private int _globalId;

#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
// TODO: get proper version string from build
Copy link
Member

Choose a reason for hiding this comment

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

We never merge source with TODOs on master.

Use the name of the package XenServer.NET and its version. I think we can get it from https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assemblyname.version?view=netstandard-2.0, but needs testing

If not, this needs a placeholder, and changes to pipelines. We can advise on that if needed

Copy link
Contributor

Choose a reason for hiding this comment

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

If the client code uses the C# SDK as a project in their code, typeof(JsonRpcClient).Assembly.GetName().Version should return the SDK version, but in the corner case of someone dropping the sources in a client project (like XenCenter does), it should return the client project version (in XC it would return XenModel's version, which is XC's version).

If we can't have the ocaml build use a placeholder and replace it with the tag (we ran into some trouble with @psafont when we tried it for the API reference), I suggest using new ActivitySource("XenAPI.JsonRpcClient", "@SDK_VERSION@") (the truth is I dislike placeholders like this, but we have one more insance of it in the PS code).

By the way, is it indeed the SDK version we need here? (As opposed to a string that will be representing the implementing client, somehting like the UserAgent, for example).

Copy link
Member

Choose a reason for hiding this comment

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

but in the corner case of someone dropping the sources in a client project (like XenCenter does)

we could do without the placeholder and just add a line in the README 🤷

Copy link
Member

Choose a reason for hiding this comment

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

By the way, is it indeed the SDK version we need here? (As opposed to a string that will be representing the implementing client, somehting like the UserAgent, for example).

for this, I'd say so

if a client wants to use open telemetry, it should add it itself and then use its own user agent

I may be wrong - I'm not that familiar with what the expected behaviour is

Copy link
Contributor

Choose a reason for hiding this comment

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

it should add it itself and then use its own user agent

Yes, the thing is we offer the option to use own UserAgent (albeit it sub-optimally designed in my opinion), but we don't offer this option for the activity source with this design.

@@ -225,6 +241,10 @@ protected virtual T Rpc<T>(string callName, JToken parameters, JsonSerializer se

using (var responseStream = new MemoryStream())
{
#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
// https://opentelemetry.io/docs/specs/semconv/rpc/json-rpc/
Copy link
Member

Choose a reason for hiding this comment

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

please add a comment explaining the tag within the source. links can change and not work anymore. If you still think it'd be useful to have a link, I'd use https://archive.org/

if (errorArray != null) {
#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
activity?.SetTag("otel.status_code", "ERROR");
//activity?.SetTag("rpc.jsonrpc.error_message", errorArray);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
//activity?.SetTag("rpc.jsonrpc.error_message", errorArray);

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be imlementing this properly rather than commenting it out - currently there is disparity between v1 and v2 implementation.

if (errorArray != null)
if (errorArray != null) {
#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
activity?.SetTag("otel.status_code", "ERROR");
Copy link
Member

@danilo-delbusso danilo-delbusso Aug 21, 2024

Choose a reason for hiding this comment

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

I'd use const for all these strings here (such as otel.status_code, ERROR, etc.)

@@ -239,12 +259,25 @@ protected virtual T Rpc<T>(string callName, JToken parameters, JsonSerializer se
#else
var res2 = (JsonResponseV2<T>)serializer.Deserialize(responseReader, typeof(JsonResponseV2<T>));
#endif

#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)
activity?.SetTag("rpc.jsonrpc.version", "2.0");
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we be setting this tag further down for v1 too?

// propagate W3C traceparent and tracestate
// HttpClient would do this automatically on .NET 5,
// and .NET 6 would provide even more control over this: https://blog.ladeak.net/posts/opentelemetry-net6-httpclient
// the caller must ensure that the activity is in W3C format (by inheritance or direc setting)
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: direc->direct

Copy link
Contributor

@kc284 kc284 left a comment

Choose a reason for hiding this comment

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

As above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants