| File: TelemetryInfra\TelemetryCollectorProvider.cs | Web Access |
| Project: Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.Build.BackEnd; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Framework; using Microsoft.Build.Framework.Telemetry; namespace Microsoft.Build.TelemetryInfra; /// <summary> /// Build component that creates isolated <see cref="ITelemetryCollector"/> instances. /// Registered as a singleton, but holds no mutable collection state. /// </summary> internal class TelemetryCollectorProvider : IBuildComponent { private bool _telemetryEnabled; /// <summary> /// Creates a new isolated <see cref="ITelemetryCollector"/>. /// Returns a no-op collector when telemetry is disabled. /// </summary> internal ITelemetryCollector CreateCollector() => _telemetryEnabled ? new TelemetryCollector() : NullTelemetryCollector.Instance; internal static IBuildComponent CreateComponent(BuildComponentType type) { Assumed.Equal(type, BuildComponentType.TelemetryCollector, $"Cannot create components of type {type}"); return new TelemetryCollectorProvider(); } public void InitializeComponent(IBuildComponentHost host) { Assumed.NotNull(host, "BuildComponentHost was null"); _telemetryEnabled = host!.BuildParameters.IsTelemetryEnabled; } public void ShutdownComponent() { } /// <summary> /// Collects task/target telemetry for one processing scope. Not thread-safe. /// </summary> internal class TelemetryCollector : ITelemetryCollector { private WorkerNodeTelemetryData _data = new(); public bool IsTelemetryCollected => true; public void AddTarget(TaskOrTargetTelemetryKey key, bool wasExecuted, TargetSkipReason skipReason = TargetSkipReason.None) { _data.AddTarget(key, wasExecuted, skipReason); } public void AddTargetResult(bool wasExecuted, TargetSkipReason skipReason = TargetSkipReason.None) { _data.AddTargetResult(wasExecuted, skipReason); } public void AddInputOutputTarget(bool upToDate) => _data.AddInputOutputTarget(upToDate); public void AddTask(TaskOrTargetTelemetryKey key, TimeSpan cumulativeExecutionTime, int executionsCount, long? totalMemoryConsumed, string? taskFactoryName, string? taskHostRuntime) { _data.AddTask(key, cumulativeExecutionTime, executionsCount, totalMemoryConsumed, taskFactoryName, taskHostRuntime); } public void FinalizeProcessing(LoggingContext loggingContext) { if (_data.IsEmpty) { return; } WorkerNodeTelemetryData snapshot = _data; _data = new(); WorkerNodeTelemetryEventArgs telemetryArgs = new(snapshot) { BuildEventContext = loggingContext.BuildEventContext }; loggingContext.LogBuildEvent(telemetryArgs); } } internal class NullTelemetryCollector : ITelemetryCollector { internal static readonly NullTelemetryCollector Instance = new(); public bool IsTelemetryCollected => false; public void AddTarget(TaskOrTargetTelemetryKey key, bool wasExecuted, TargetSkipReason skipReason = TargetSkipReason.None) { } public void AddTargetResult(bool wasExecuted, TargetSkipReason skipReason = TargetSkipReason.None) { } public void AddInputOutputTarget(bool upToDate) { } public void AddTask(TaskOrTargetTelemetryKey key, TimeSpan cumulativeExecutionTime, int executionsCount, long? totalMemoryConsumed, string? taskFactoryName, string? taskHostRuntime) { } public void FinalizeProcessing(LoggingContext loggingContext) { } } }