Skip to content

Commit 924c0a3

Browse files
update telemetry logic
1 parent c8de872 commit 924c0a3

File tree

8 files changed

+43
-51
lines changed

8 files changed

+43
-51
lines changed

eng/Signing.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<ItemsToSign Include="$(ArtifactsDir)\xsd\Update-MSBuildXsds.ps1" />
1212

1313
<FileSignInfo Include="RuntimeContracts.dll" CertificateName="3PartySHA2" />
14+
15+
<!-- For Telemetry in VS.-->
16+
<FileSignInfo Include="Newtonsoft.Json.dll" CertificateName="3PartySHA2" />
1417
</ItemGroup>
1518

1619
<!-- Remove existing .nupkg signing info and set to None for testing to workaround the existing issue in arcade. -->

src/Build.UnitTests/BackEnd/BuildManager_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ public void OverlappingBuildsOfTheSameProjectDifferentTargetsAreAllowed()
18011801
</Target>
18021802
</Project>
18031803
");
1804-
1804+
_env.SetEnvironmentVariable("MSBUILDNOINPROCNODE", "1");
18051805
Project project = CreateProject(contents, MSBuildDefaultToolsVersion, _projectCollection, true);
18061806
ProjectInstance instance = _buildManager.GetProjectInstanceForBuild(project);
18071807
_buildManager.BeginBuild(_parameters);

src/Build/BackEnd/BuildManager/BuildManager.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ public BuildManager()
295295
public BuildManager(string hostName)
296296
{
297297
ErrorUtilities.VerifyThrowArgumentNull(hostName);
298+
298299
_hostName = hostName;
299300
_buildManagerState = BuildManagerState.Idle;
300301
_buildSubmissions = new Dictionary<int, BuildSubmissionBase>();
@@ -459,8 +460,11 @@ private void UpdatePriority(Process p, ProcessPriorityClass priority)
459460
/// <exception cref="InvalidOperationException">Thrown if a build is already in progress.</exception>
460461
public void BeginBuild(BuildParameters parameters)
461462
{
462-
TelemetryManager.Instance.Initialize(isStandalone: false, parameters.IsTelemetryEnabled);
463-
463+
#if NETFRAMEWORK
464+
// Collect telemetry unless explicitly opted out via environment variable.
465+
// The decision to send telemetry is made at EndBuild to avoid eager loading of telemetry assemblies.
466+
parameters.IsTelemetryEnabled |= !TelemetryManager.IsOptOut();
467+
#endif
464468
if (_previousLowPriority != null)
465469
{
466470
if (parameters.LowPriority != _previousLowPriority)
@@ -586,7 +590,6 @@ public void BeginBuild(BuildParameters parameters)
586590
// Initialize components.
587591
_nodeManager = ((IBuildComponentHost)this).GetComponent(BuildComponentType.NodeManager) as INodeManager;
588592

589-
_buildParameters.IsTelemetryEnabled |= TelemetryManager.Instance?.DefaultActivitySource?.IsTelemetryEnabled ?? false;
590593
var loggingService = InitializeLoggingService();
591594

592595
// Log deferred messages and response files
@@ -1113,10 +1116,7 @@ public void EndBuild()
11131116

11141117
loggingService.LogTelemetry(buildEventContext: null, _buildTelemetry.EventName, _buildTelemetry.GetProperties());
11151118

1116-
if (_buildParameters.IsTelemetryEnabled)
1117-
{
1118-
EndBuildTelemetry();
1119-
}
1119+
EndBuildTelemetry();
11201120

11211121
// Clean telemetry to make it ready for next build submission.
11221122
_buildTelemetry = null;
@@ -1160,9 +1160,11 @@ void SerializeCaches()
11601160
}
11611161
}
11621162

1163-
[MethodImpl(MethodImplOptions.NoInlining)] // avoid early assembly load of Microsoft.VisualStudio.Telemetry
1163+
[MethodImpl(MethodImplOptions.NoInlining)]
11641164
private void EndBuildTelemetry()
11651165
{
1166+
TelemetryManager.Instance.Initialize(isStandalone: false);
1167+
11661168
using IActivity? activity = TelemetryManager.Instance
11671169
?.DefaultActivitySource
11681170
?.StartActivity(TelemetryConstants.Build)

src/Framework/Telemetry/MSBuildActivitySource.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,16 @@ internal class MSBuildActivitySource
2121
public MSBuildActivitySource(TelemetrySession? telemetrySession)
2222
{
2323
_telemetrySession = telemetrySession;
24-
IsTelemetryEnabled = _telemetrySession?.IsOptedIn ?? false;
2524
}
2625
#else
2726
private readonly ActivitySource _source;
2827

29-
public MSBuildActivitySource(string name, bool isTelemetryExplicitlyRequested)
28+
public MSBuildActivitySource(string name)
3029
{
3130
_source = new ActivitySource(name);
32-
IsTelemetryEnabled = isTelemetryExplicitlyRequested;
3331
}
3432
#endif
3533

36-
/// <summary>
37-
/// Gets a value indicating whether telemetry is enabled for this activity source.
38-
/// On .NET Framework, this reflects whether the VS Telemetry session is opted in.
39-
/// On .NET Core and later, this reflects whether telemetry was explicitly requested.
40-
/// </summary>
41-
public bool IsTelemetryEnabled { get; }
42-
4334
/// <summary>
4435
/// Starts a new activity with the appropriate telemetry prefix.
4536
/// </summary>

src/Framework/Telemetry/TelemetryManager.cs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@ private TelemetryManager()
4949
/// versus integrated mode (e.g., running within Visual Studio or dotnet CLI).
5050
/// When <c>true</c>, creates and manages its own telemetry session on .NET Framework.
5151
/// </param>
52-
/// <param name="isTelemetryExplicitlyRequested">
53-
/// Indicates whether telemetry was explicitly requested through command line arguments.
54-
/// </param>
55-
public void Initialize(bool isStandalone, bool isTelemetryExplicitlyRequested)
52+
[MethodImpl(MethodImplOptions.NoInlining)]
53+
public void Initialize(bool isStandalone)
5654
{
5755
lock (s_lock)
5856
{
@@ -68,7 +66,7 @@ public void Initialize(bool isStandalone, bool isTelemetryExplicitlyRequested)
6866
return;
6967
}
7068

71-
TryInitializeTelemetry(isStandalone, isTelemetryExplicitlyRequested);
69+
TryInitializeTelemetry(isStandalone);
7270
}
7371
}
7472

@@ -92,14 +90,14 @@ internal static void ResetForTest()
9290
/// allowing the calling code to catch assembly loading exceptions.
9391
/// </summary>
9492
[MethodImpl(MethodImplOptions.NoInlining)]
95-
private void TryInitializeTelemetry(bool isStandalone, bool isTelemetryExplicitlyRequested)
93+
private void TryInitializeTelemetry(bool isStandalone)
9694
{
9795
try
9896
{
9997
#if NETFRAMEWORK
10098
DefaultActivitySource = VsTelemetryInitializer.Initialize(isStandalone);
10199
#else
102-
DefaultActivitySource = new MSBuildActivitySource(TelemetryConstants.DefaultActivitySourceNamespace, isTelemetryExplicitlyRequested);
100+
DefaultActivitySource = new MSBuildActivitySource(TelemetryConstants.DefaultActivitySourceNamespace);
103101
#endif
104102
}
105103
catch (Exception ex) when (ex is FileNotFoundException or FileLoadException or TypeLoadException)
@@ -136,65 +134,58 @@ FileLoadException or
136134
}
137135
}
138136

139-
#if NETFRAMEWORK
140-
[MethodImpl(MethodImplOptions.NoInlining)]
141-
private static void DisposeVsTelemetry() => VsTelemetryInitializer.Dispose();
142-
#endif
143-
144137
/// <summary>
145138
/// Determines if the user has explicitly opted out of telemetry.
146139
/// </summary>
147-
private static bool IsOptOut() =>
140+
internal static bool IsOptOut() =>
148141
#if NETFRAMEWORK
149142
Traits.Instance.FrameworkTelemetryOptOut;
150143
#else
151144
Traits.Instance.SdkTelemetryOptOut;
152145
#endif
146+
147+
#if NETFRAMEWORK
148+
[MethodImpl(MethodImplOptions.NoInlining)]
149+
private static void DisposeVsTelemetry() => VsTelemetryInitializer.Dispose();
150+
#endif
153151
}
154152

155153
#if NETFRAMEWORK
156-
/// <summary>
157-
/// Isolated class that references Microsoft.VisualStudio.Telemetry types.
158-
/// This separation ensures the VS Telemetry assembly is only loaded when methods
159-
/// on this class are actually invoked.
160-
/// </summary>
161-
/// <remarks>
162-
/// Thread-safety: All public methods on this class must be called under the
163-
/// <see cref="TelemetryManager"/> lock to ensure thread-safe access to static state.
164-
/// Callers must not invoke <see cref="Initialize"/> or <see cref="Dispose"/> concurrently.
165-
/// </remarks>
166154
internal static class VsTelemetryInitializer
167155
{
168156
// Telemetry API key for Visual Studio telemetry service.
169157
private const string CollectorApiKey = "f3e86b4023cc43f0be495508d51f588a-f70d0e59-0fb0-4473-9f19-b4024cc340be-7296";
170158

171-
private static TelemetrySession? s_telemetrySession;
159+
// Store as object to avoid type reference at class load time
160+
private static object? s_telemetrySession;
172161
private static bool s_ownsSession = false;
173162

163+
[MethodImpl(MethodImplOptions.NoInlining)]
174164
public static MSBuildActivitySource Initialize(bool isStandalone)
175165
{
166+
TelemetrySession session;
176167
if (isStandalone)
177168
{
178-
s_telemetrySession = TelemetryService.CreateAndGetDefaultSession(CollectorApiKey);
169+
session = TelemetryService.CreateAndGetDefaultSession(CollectorApiKey);
179170
TelemetryService.DefaultSession.UseVsIsOptedIn();
180171
TelemetryService.DefaultSession.Start();
181172
s_ownsSession = true;
182173
}
183174
else
184175
{
185-
s_telemetrySession = TelemetryService.DefaultSession;
176+
session = TelemetryService.DefaultSession;
186177
}
187178

188-
return new MSBuildActivitySource(s_telemetrySession);
179+
s_telemetrySession = session;
180+
return new MSBuildActivitySource(session);
189181
}
190182

183+
[MethodImpl(MethodImplOptions.NoInlining)]
191184
public static void Dispose()
192185
{
193-
// Only dispose the session if we created it (standalone scenario).
194-
// In VS, the session is owned by VS and should not be disposed by MSBuild.
195-
if (s_ownsSession)
186+
if (s_ownsSession && s_telemetrySession is TelemetrySession session)
196187
{
197-
s_telemetrySession?.Dispose();
188+
session.Dispose();
198189
}
199190

200191
s_telemetrySession = null;

src/MSBuild/XMake.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ string[] args
250250
// Initialize new build telemetry and record start of this build.
251251
KnownTelemetry.PartialBuildTelemetry = new BuildTelemetry { StartAt = DateTime.UtcNow, IsStandaloneExecution = true };
252252

253-
TelemetryManager.Instance?.Initialize(isStandalone: true, isTelemetryExplicitlyRequested: false);
253+
TelemetryManager.Instance?.Initialize(isStandalone: true);
254254

255255
using PerformanceLogEventListener eventListener = PerformanceLogEventListener.Create();
256256

src/MSBuild/app.amd64.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@
106106
<bindingRedirect oldVersion="0.0.0.0-9.0.0.11" newVersion="9.0.0.11" />
107107
<codeBase version="9.0.0.11" href="..\System.Collections.Immutable.dll"/>
108108
</dependentAssembly>
109+
<dependentAssembly>
110+
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
111+
<codeBase version="13.0.0.0" href="..\Newtonsoft.Json.dll" />
112+
</dependentAssembly>
109113
<dependentAssembly>
110114
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
111115
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />

src/Package/MSBuild.VSSetup/files.swr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ folder InstallDir:\MSBuild\Current\Bin
8989
file source=$(X86BinPath)Microsoft.WinFx.targets
9090
file source=$(X86BinPath)Microsoft.WorkflowBuildExtensions.targets
9191
file source=$(X86BinPath)Microsoft.VisualStudio.Utilities.Internal.dll vs.file.ngenApplications="[installDir]\MSBuild\Current\Bin\amd64\MSBuild.exe" vs.file.ngenArchitecture=all vs.file.ngenPriority=3
92+
file source=$(X86BinPath)Newtonsoft.Json.dll vs.file.ngenApplications="[installDir]\MSBuild\Current\Bin\amd64\MSBuild.exe" vs.file.ngenArchitecture=all vs.file.ngenPriority=2
9293

9394
folder InstallDir:\MSBuild\Current\Bin\MSBuild
9495
file source=$(X86BinPath)\MSBuild\Microsoft.Build.Core.xsd

0 commit comments

Comments
 (0)