Skip to content

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

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

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

@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.

@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

kc284
kc284 previously requested changes Aug 22, 2024
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.

@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from 3037f81 to d7468f6 Compare January 23, 2025 17:27
@edwintorok edwintorok marked this pull request as draft January 23, 2025 17:29
@edwintorok edwintorok marked this pull request as ready for review January 23, 2025 21:44
@edwintorok
Copy link
Contributor Author

I've addressed the review comments, and tested a build, the traceparent is sent correctly:

POST /jsonrpc HTTP/1.1
Host: lcy2-dt72.xenrt.citrite.net
Accept: application/json
User-Agent: XenServerPSModule/25.2.0.0
Connection: Keep-Alive
traceparent: 00-a29a037790a77a956ab8ce8887d1287d-900ac8ca433ee4f4-01
Content-Type: application/json
Content-Length: 100

@edwintorok edwintorok requested a review from kc284 January 23, 2025 21:48
@edwintorok edwintorok marked this pull request as draft January 24, 2025 09:42
@edwintorok
Copy link
Contributor Author

I'll add a small self-contained example here on how the output looks with OpenTelemetry instrumentation enabled.

@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from d7468f6 to f6c2641 Compare January 24, 2025 11:53
@edwintorok
Copy link
Contributor Author

edwintorok commented Jan 24, 2025

dotnet new console -o sample1
dotnet add package OpenTelemetry.Exporter.Console --version 1.9.0
dotnet add package OpenTelemetry --version 1.9.0
dotnet nuget add source --name 'Offline Packages' E:\myfolder\xen-api\sdk\sdk\XenServer-SDK\XenServer.NET\
dotnet add package XenServer.NET -s 'Offline Packages'
// See https://aka.ms/new-console-template for more information
using System.Net;
using System;
using System.Collections.Generic;
using XenAPI;
using System.Runtime.InteropServices;
using System.ComponentModel.DataAnnotations;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System.Diagnostics;

ActivitySource source = new ActivitySource("Sample.DistributedTracing", "1.0.0");

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                .AddSource("*")
                .AddConsoleExporter()
                .Build();

using (Activity activity = source.StartActivity("SomeWork"))
{
    //Trust all certificates. This is a test workaround. DO NOT USE IN PRODUCTION CODE!
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

    string hostUrl = args[0], username = args[1], password = args[2];
    Session session = new Session(hostUrl);
    try
    {
        session.login_with_password(username, password, "", "XenSdkSample");

        var hosts = Host.get_all(session);
        System.Console.WriteLine("Got hosts: " + hosts.Count);
    }
    finally
    {
        session.logout();
    }
}

The output looks like this (the application can choose which activity sources to enable, if they want just the XenServer on, they can enable 'XenServer.*'):
https://gist.github.com/edwintorok/d1528660c588d6916363c8bb0565ba50

@edwintorok edwintorok marked this pull request as ready for review January 24, 2025 12:17
@edwintorok
Copy link
Contributor Author

Screenshot 2025-01-27 at 11 51 51 Screenshot 2025-01-27 at 11 51 41

Tested using a slightly tweaked version of the above sample (using OTLP to send to jaeger), and confirmed that we get a joined Client + Server trace in Jaeger.

@edwintorok edwintorok dismissed kc284’s stale review January 28, 2025 16:36

Review comments addressed in new commits. Removing stale review marker, and requested new review.

Copy link
Member

@mg12 mg12 left a comment

Choose a reason for hiding this comment

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

The code changes and output looks good to me, and the joined Client + Server trace in Jaeger shows it's working as intended. Perhaps someone more used to the SDK build system could check the dependency changes @kc284 @danilo-delbusso

@edwintorok
Copy link
Contributor Author

It has been discussed that we should switch to .Net 8, so I'll see if I can add an additional build target for that here (that'll ensure that the right DLL gets picked out of the Nuget).

@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from f6c2641 to 4c2f198 Compare April 11, 2025 17:11
@edwintorok
Copy link
Contributor Author

Looks like I need to tweak the preprocessor defines, because this doesn't cover .Net 8.0:
#if (NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER)

NET462 refers to .Net framework I think, so .Net 8.0 is not covered by it, and .Net Core and regular .Net probably have no overlap either.
I'll see if I can find a simpler preprocessor define to use, and if not add .Net 6.0+ to that.

@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from 4c2f198 to 249cebb Compare April 22, 2025 15:20
@edwintorok
Copy link
Contributor Author

edwintorok commented Apr 23, 2025

The xenserver-samples fail to run:

\r\nException: System.IO.FileNotFoundException: Could not load file or assembly &apos;System.Diagnostics.DiagnosticSource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51&apos;. The system cannot find the file specified.\r\nFile name: &apos;System.Diagnostics.DiagnosticSource, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51&apos;\r\n   at XenAPI.JsonRpcClient.Rpc[T](String callName, JToken parameters, JsonSerializer serializer)\r\n   at XenAPI.JsonRpcClient.session_login_with_password(String _uname, String _pwd, String _version, String _originator)\r\n   at XenAPI.Session.login_with_password(String username, String password, String version, String originator)\r\n   at Citrix.XenServer.Commands.ConnectXenServerCommand.ProcessRecord()\r\n   at System.Management.Automation.CommandProcessor.ProcessRecord()\r\n</log>\r\n</test>\r\n<test>\r\n<name>Create SR create_nfs_sr 10.63.96.18 /mia11_export/4288734-QzbMXt PowerShellAutoTestSR True</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'create_nfs_sr 10.63.96.18 /mia11_export/4288734-QzbMXt PowerShellAutoTestSR3jigbrbkso6'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Install VM install_vm PowerShellAutoTestVM PowerShellAutoTestSR True</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'install_vm PowerShellAutoTestVM42q95qmrdwg PowerShellAutoTestSR3jigbrbkso6'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Start VM start_vm PowerShellAutoTestVM Running</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'start_vm PowerShellAutoTestVM42q95qmrdwg'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Shutdown VM shutdown_vm PowerShellAutoTestVM Halted</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'shutdown_vm PowerShellAutoTestVM42q95qmrdwg'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Uninstall VM uninstall_vm &apos;PowerShellAutoTestVM&apos; True</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'uninstall_vm &apos;PowerShellAutoTestVM42q95qmrdwg&apos;'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Destroy SR detach_nfs_sr PowerShellAutoTestSR True</name>\r\n<state>Fail</state>\r\n<log>\r\nCmd: 'detach_nfs_sr PowerShellAutoTestSR3jigbrbkso6'\r\nException: System.Exception: Could not find open sessions to any XenServers.\r\n   at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)\r\n</log>\r\n</test>\r\n<test>\r\n<name>Disconnect Server</name>\r\n<state>Pass</state>\r\n<log />\r\n</test>\r\n</group>\r\n</results>\r\n" (

Maybe the dependencies don't get propagated correctly from the SDK to the app, although I would've expected Nuget to do the right thing.

I'll try another build where I only enable tracing when you're on .Net 8.0+ and not in other cases (that means that XenCenter likely won't get it, and we'll also lack tracing in Powershell -- which was an easy way to test that the tracing works).

The C# sample fails to run too, but that probably needs the environment updated to have .Net 8.0 available (I switched the sample from 6.0 to 8.0):

You must install .NET to run this application.

App: /root/csharp/XenSdkSample
Architecture: x64
App host version: 8.0.13
.NET location: Not found

Learn more:
https://aka.ms/dotnet/app-launch-failed

Download the .NET runtime:
https://aka.ms/dotnet-core-applaunch?missing_runtime=true&arch=x64&rid=linux-x64&os=debian.12&apphost_version=8.0.13

To allow compile-testing the C# code on Linux reintroduce the
'sdksanity' rule which got dropped accidentally.
Also run the tests.

Fixes: e6afe15 ("Removed erroneously ported recipe.")

Signed-off-by: Edwin Török <[email protected]>
This is not available on .Net 4.5.
Could use .Net Standard 2.0, .Net Framework 4.6.2 and .NET 8.0 as target,
which matches the availability of the
System.Diagnostics.DiagnosticSource builtin (and Nuget package for older
versions):
```
NET462_OR_GREATER || NETSTANDARD2_0_OR_GREATER || NET8_0_OR_GREATER
```

However there are some bugs in the CI where the xenserver-samples XenSdkSample ends up
in a zip, but without its dependency (the DiagnosticSource.dll).

So for now just enable this on .Net8, where hopefully this package is part of the runtime already
(although of course you'll still need to install the runtime, which for some reason you didn't have to do
with .Net6, perhaps .Net6 would come preinstalled on Debian12?).

Signed-off-by: Edwin Török <[email protected]>
Doesn't exist on .Net45.

Only creates these activity sources if a listener has been created by the caller,
otherwise `activity` will be `null`, and the code would be a no-op by default.

A listener is created by OpenTelemetry instrumentation for example.

Signed-off-by: Edwin Török <[email protected]>
Apparently this has fewer dependencies than netstandard2.0,
and some projects would've picked net45 in favour of netstandard2.0.

Eventually we may want to drop net45, for now just add the new target.

There is also net9.0, but it has an EOL date ahead of net8.0 which is LTS.

A quick sanity test that the net80 target includes tracing support:
```
make sdksanity
strings -el ./_build/default/ocaml/sdk-gen/csharp/autogen-out/src/bin/Release/net80/XenServer.dll|grep traceparent                                             traceparent
```

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

With the latest changes here (enable tracing only for .NET 8.0), and updating the tests to install the .Net 8 runtime when testing the .Net 8 sample -- the tests have passed, so I think this is ready.

@edwintorok edwintorok force-pushed the private/edvint/otelsdk branch from 249cebb to 6c44e4c Compare April 24, 2025 09:48
@edwintorok edwintorok dismissed danilo-delbusso’s stale review April 28, 2025 08:24

Addressed comments

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.

4 participants