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

Implement OpenTelemetry infrastructure #11255

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

JanProvaznik
Copy link
Member

@JanProvaznik JanProvaznik commented Jan 10, 2025

Fixes #10945 #10948

Context

#10560

  • infrastructure part of this

Changes Made

add singleton OpenTelemetryManager

executions in Framework (standalone and managed) trace and collect basic build events with a defined sampling rate.
Sending end of build telemetry comparable to the one sent in sdk.

Testing

Unit tests of the behavior,
monitoring if we get data to the backend

Notes

@dotnet dotnet deleted a comment from azure-pipelines bot Jan 10, 2025
@JanProvaznik JanProvaznik marked this pull request as ready for review January 10, 2025 16:28
@JanProvaznik JanProvaznik requested a review from a team as a code owner January 10, 2025 16:28
/// Create a list of properties sent to VS telemetry with the information whether they should be hashed.
/// </summary>
/// <returns></returns>
public IList<TelemetryItem> GetActivityProperties()
Copy link
Member

@YuliiaKovalova YuliiaKovalova Jan 13, 2025

Choose a reason for hiding this comment

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

A suggestion, feel free to ignore:
can we logically split the types of collected data? e.g. AddFeatureFlags, AddBuildProperties, AddTimeMetrics, to improve readability and simplify adding new lines?

It looks like this method has a huge potential to grow :)

src/Framework/Telemetry/BuildTelemetry.cs Outdated Show resolved Hide resolved
telemetryItems.Add(new TelemetryItem("BuildTarget", Target, true));
}

if (Version != null)
Copy link
Member

Choose a reason for hiding this comment

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

can Version or other strings be empty?

src/Framework/Telemetry/ActivityExtensions.cs Show resolved Hide resolved

#else
// Create the SHA256 object and compute the hash
using (var sha256 = SHA256.Create())
Copy link
Member

Choose a reason for hiding this comment

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

please check

internal static class ConversionUtilities
to reuse some of methods for hashing

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 aim here is to do the same thing as sdk https://github.com/dotnet/sdk/blob/8bd19a2390a6bba4aa80d1ac3b6c5385527cc311/src/Cli/Microsoft.DotNet.Cli.Utils/Sha256Hasher.cs not to use MSBuild-specific implementations.

Copy link
Member

Choose a reason for hiding this comment

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

how do be plan to stay up to date with sdk implementation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Context: This code only runs when customers hook their own telemetry in core.

The aim was so the hash matches the one produced by sdk which would only be helpful if internal people collected it and looked at the sdk data table. If sdk changed then it'd need to be changed manually, which is concerning. I don't see how we could depend on their hasher implementation, that would create a circular dependency, no? (And also it's not completely the same, since I made a netstandard2.0 conditionally compiled version based on it which is not in sdk).

An option is to omit implementing this logic and make it a problem of the people hooking their telemetry processor/exporter.

Another option is to make a "MSBuild hasher" that does not aim to be the same as sdk, but why not start with the one in sdk.

After trying to use ConversionUtilities, it would require moving a lot of internal stuff to framework which I don't know if is worth it or if there are any concerning implications.

src/Framework/Telemetry/ActivityExtensions.cs Outdated Show resolved Hide resolved
/// <summary>
/// For VS OpenTelemetry Collector to apply the correct privacy policy.
/// </summary>
public const string VSMajorVersion = "17.0";
Copy link
Member

Choose a reason for hiding this comment

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

should we track this field somewhere if the docs to stay up to date?

@@ -13,6 +13,14 @@
<add key="dotnet8" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet8/nuget/v3/index.json" />
<add key="dotnet8-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json" />
<add key="dotnet9" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet9/nuget/v3/index.json" />
<add key="vs-impl" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json" />
Copy link
Member

Choose a reason for hiding this comment

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

is it a temporary thing?
I recall we had some limitations for using this feed in msbuild repo

Copy link
Member Author

@JanProvaznik JanProvaznik Jan 13, 2025

Choose a reason for hiding this comment

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

It's intended to be permanent. Under it, there is a restriction that this feed can pull only VS OpenTelemetry packages. (and it won't pull them outside Framework because they're conditionally included in Microsoft.Build.Framework.csproj

Copy link
Member

Choose a reason for hiding this comment

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

@rainersigwald to draw your attention here

Copy link
Member

Choose a reason for hiding this comment

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

The PSM configuration doesn't exactly say that: it says that Microsoft.VisualStudio.OpenTelemetry* must come from vs-impl, not that vs-impl can only be used for that package.

We need to be careful here--have you talked to the VMR/sourcebuild folks about the dependency?

Copy link
Member Author

@JanProvaznik JanProvaznik Jan 13, 2025

Choose a reason for hiding this comment

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

The PSM configuration doesn't exactly say that: it says that Microsoft.VisualStudio.OpenTelemetry* must come from vs-impl, not that vs-impl can only be used for that package.

Thanks, I misunderstood that. Is it possible to do? From a quick look at docs I guess no ☹️

We're in contact and it does not impact sourcebuild, because it's references are gated only for .NET Framework in Microsoft.Build.Framework.csproj, and Framework is not a part of sourcebuild.

There is no way to condition on that in NuGet.config though.

Copy link
Member

@JanKrivanek JanKrivanek left a comment

Choose a reason for hiding this comment

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

Looks great!

I'm not yet reay to sign off - I need a second detailed look, plus there are some notes I put where I'd want your answers first.

@@ -453,6 +453,7 @@ private void UpdatePriority(Process p, ProcessPriorityClass priority)
/// <exception cref="InvalidOperationException">Thrown if a build is already in progress.</exception>
public void BeginBuild(BuildParameters parameters)
{
OpenTelemetryManager.Instance.Initialize(isStandalone: false);
Copy link
Member

Choose a reason for hiding this comment

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

Is it fine if Initialize is called twice? (in case of standalone msbuild)

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see it just skips then.

src/Framework/Telemetry/ActivityExtensions.cs Outdated Show resolved Hide resolved
Comment on lines +41 to +54
/// <summary>
/// For core hook, ActivitySource is created.
/// </summary>
TracerInitialized,

/// <summary>
/// For VS scenario with a collector. ActivitySource, OTel TracerProvider are created.
/// </summary>
ExporterInitialized,

/// <summary>
/// For standalone, ActivitySource, OTel TracerProvider, VS OpenTelemetry Collector are created.
/// </summary>
CollectorInitialized,
Copy link
Member

Choose a reason for hiding this comment

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

How does the instrumentation code check whether a data should be collected? Does it need to check if state is any of those? Or is there otehr single property that can be checked in boolean style?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. It's for inner tracking of the state of the instrumentation (perhaps I can make it private).
Instrumented code does something or is a no-op based on the Tracer+Exporter objects.

In the spirit this PR not having 2k LoC it samples everything with one rate, subsequent PR will deal with sample rate differentiation based on namespaces. I figured this is acceptable since this is not a public API so we can easily change/refactor.

src/MSBuild/app.config Outdated Show resolved Hide resolved
@@ -296,6 +298,9 @@ string[] args
DumpCounters(false /* log to console */);
}

// Send OpenTelemetry before exiting
OpenTelemetryManager.Instance.Shutdown();
Copy link
Member

Choose a reason for hiding this comment

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

We don't seem to call this for the API usage case.
Let's try to see if we can have better place to control lifetime of the telemetry manager (probably BuildManager?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh that's an oversight given we don't have the collector in VS yet. Now that I look at it, it makes more sense to do everything in EndBuild.

The point is that somewhere the collector has to be shut down, whereas the Exporter is ok to just flush (if collector is somewhere else).
Is it also a goal to send telemetry when people are using MSBuild via API on their own?

src/Framework/Telemetry/OpenTelemetryManager.cs Outdated Show resolved Hide resolved
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.

Prototype sending data via VS OTel collector
5 participants