@@ -25,7 +25,7 @@ internal class TelemetryManager
2525 /// <summary>
2626 /// Lock object for thread-safe initialization and disposal.
2727 /// </summary>
28- private static readonly object s_lock = new object ( ) ;
28+ private static readonly LockType s_lock = new ( ) ;
2929
3030 private static bool s_initialized ;
3131 private static bool s_disposed ;
@@ -49,11 +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="isExplicitlyRequested">
53- /// Indicates whether telemetry was explicitly requested through command line arguments.
54- /// On .NET, telemetry is only enabled when this is <c>true</c>.
55- /// </param>
56- public void Initialize ( bool isStandalone , bool isExplicitlyRequested )
52+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
53+ public void Initialize ( bool isStandalone )
5754 {
5855 lock ( s_lock )
5956 {
@@ -69,7 +66,7 @@ public void Initialize(bool isStandalone, bool isExplicitlyRequested)
6966 return ;
7067 }
7168
72- TryInitializeTelemetry ( isStandalone , isExplicitlyRequested ) ;
69+ TryInitializeTelemetry ( isStandalone ) ;
7370 }
7471 }
7572
@@ -93,16 +90,14 @@ internal static void ResetForTest()
9390 /// allowing the calling code to catch assembly loading exceptions.
9491 /// </summary>
9592 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
96- private void TryInitializeTelemetry ( bool isStandalone , bool isExplicitlyRequested )
93+ private void TryInitializeTelemetry ( bool isStandalone )
9794 {
9895 try
9996 {
10097#if NETFRAMEWORK
10198 DefaultActivitySource = VsTelemetryInitializer . Initialize ( isStandalone ) ;
10299#else
103- DefaultActivitySource = isExplicitlyRequested
104- ? new MSBuildActivitySource ( TelemetryConstants . DefaultActivitySourceNamespace )
105- : null ;
100+ DefaultActivitySource = new MSBuildActivitySource ( TelemetryConstants . DefaultActivitySourceNamespace ) ;
106101#endif
107102 }
108103 catch ( Exception ex ) when ( ex is FileNotFoundException or FileLoadException or TypeLoadException )
@@ -139,66 +134,58 @@ FileLoadException or
139134 }
140135 }
141136
142- #if NETFRAMEWORK
143- [ MethodImpl ( MethodImplOptions . NoInlining ) ]
144- private static void DisposeVsTelemetry ( ) => VsTelemetryInitializer . Dispose ( ) ;
145- #endif
146-
147137 /// <summary>
148138 /// Determines if the user has explicitly opted out of telemetry.
149139 /// </summary>
150- private static bool IsOptOut ( ) =>
140+ internal static bool IsOptOut ( ) =>
151141#if NETFRAMEWORK
152142 Traits . Instance . FrameworkTelemetryOptOut ;
153143#else
154144 Traits . Instance . SdkTelemetryOptOut ;
155145#endif
146+
147+ #if NETFRAMEWORK
148+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
149+ private static void DisposeVsTelemetry ( ) => VsTelemetryInitializer . Dispose ( ) ;
150+ #endif
156151 }
157152
158153#if NETFRAMEWORK
159- /// <summary>
160- /// Isolated class that references Microsoft.VisualStudio.Telemetry types.
161- /// This separation ensures the VS Telemetry assembly is only loaded when methods
162- /// on this class are actually invoked.
163- /// </summary>
164- /// <remarks>
165- /// Thread-safety: All public methods on this class must be called under the
166- /// <see cref="TelemetryManager"/> lock to ensure thread-safe access to static state.
167- /// Callers must not invoke <see cref="Initialize"/> or <see cref="Dispose"/> concurrently.
168- /// </remarks>
169154 internal static class VsTelemetryInitializer
170155 {
171156 // Telemetry API key for Visual Studio telemetry service.
172157 private const string CollectorApiKey = "f3e86b4023cc43f0be495508d51f588a-f70d0e59-0fb0-4473-9f19-b4024cc340be-7296" ;
173158
174- private static TelemetrySession ? s_telemetrySession ;
175- private static bool s_ownsSession ;
159+ // Store as object to avoid type reference at class load time
160+ private static object ? s_telemetrySession ;
161+ private static bool s_ownsSession = false ;
176162
163+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
177164 public static MSBuildActivitySource Initialize ( bool isStandalone )
178165 {
166+ TelemetrySession session ;
179167 if ( isStandalone )
180168 {
181- s_telemetrySession = TelemetryService . CreateAndGetDefaultSession ( CollectorApiKey ) ;
169+ session = TelemetryService . CreateAndGetDefaultSession ( CollectorApiKey ) ;
182170 TelemetryService . DefaultSession . UseVsIsOptedIn ( ) ;
183171 TelemetryService . DefaultSession . Start ( ) ;
184172 s_ownsSession = true ;
185173 }
186174 else
187175 {
188- s_telemetrySession = TelemetryService . DefaultSession ;
189- s_ownsSession = false ;
176+ session = TelemetryService . DefaultSession ;
190177 }
191178
192- return new MSBuildActivitySource ( s_telemetrySession ) ;
179+ s_telemetrySession = session ;
180+ return new MSBuildActivitySource ( session ) ;
193181 }
194182
183+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
195184 public static void Dispose ( )
196185 {
197- // Only dispose the session if we created it (standalone scenario).
198- // In VS, the session is owned by VS and should not be disposed by MSBuild.
199- if ( s_ownsSession )
186+ if ( s_ownsSession && s_telemetrySession is TelemetrySession session )
200187 {
201- s_telemetrySession ? . Dispose ( ) ;
188+ session . Dispose ( ) ;
202189 }
203190
204191 s_telemetrySession = null ;
0 commit comments