File: TelemetryInfra\InternalTelemetryConsumingLogger.cs
Web Access
Project: ..\..\..\src\Build\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 System.Linq;
using System.Text.Json;
using Microsoft.Build.Framework;
using Microsoft.Build.Framework.Telemetry;
using System.IO;
 
namespace Microsoft.Build.TelemetryInfra;
 
internal sealed class InternalTelemetryConsumingLogger : ILogger
{
    public LoggerVerbosity Verbosity { get; set; }
    public string? Parameters { get; set; }
    internal static event Action<WorkerNodeTelemetryData>? TestOnly_InternalTelemetryAggregted; 
 
    public void Initialize(IEventSource eventSource)
    {
        if (eventSource is IEventSource5 eventSource5)
        {
            eventSource5.WorkerNodeTelemetryLogged += EventSource5_WorkerNodeTelemetryLogged;
            eventSource.BuildFinished += EventSourceOnBuildFinished;
        }
    }
 
    private readonly WorkerNodeTelemetryData _workerNodeTelemetryData = new();
 
    public IWorkerNodeTelemetryData WorkerNodeTelemetryData => _workerNodeTelemetryData;
 
    private void EventSource5_WorkerNodeTelemetryLogged(object? sender, WorkerNodeTelemetryEventArgs e)
    {
        _workerNodeTelemetryData.Add(e.WorkerNodeTelemetryData);
    }
 
    private void EventSourceOnBuildFinished(object sender, BuildFinishedEventArgs e)
    {
        TestOnly_InternalTelemetryAggregted?.Invoke(_workerNodeTelemetryData);
        FlushDataIntoConsoleIfRequested();
        FlushDataIntoJsonFileIfRequested();
    }
 
    private void FlushDataIntoConsoleIfRequested()
    {
        if (!Traits.IsEnvVarOneOrTrue("MSBUILDOUTPUTNODESTELEMETRY"))
        {
            return;
        }
 
        Console.WriteLine("==========================================");
        Console.WriteLine($"Targets ({_workerNodeTelemetryData.TargetsExecutionData.Count}):");
        foreach (var target in _workerNodeTelemetryData.TargetsExecutionData)
        {
            Console.WriteLine($"{target.Key} : {target.Value}");
        }
        Console.WriteLine("==========================================");
        Console.WriteLine($"Tasks: ({_workerNodeTelemetryData.TasksExecutionData.Count})");
        Console.WriteLine("Custom tasks:");
        foreach (var task in _workerNodeTelemetryData.TasksExecutionData.Where(t => t.Key.IsCustom))
        {
            Console.WriteLine($"{task.Key}");
        }
        Console.WriteLine("==========================================");
        Console.WriteLine("Tasks by time:");
        foreach (var task in _workerNodeTelemetryData.TasksExecutionData.OrderByDescending(t => t.Value.CumulativeExecutionTime).Take(20))
        {
            Console.WriteLine($"{task.Key} - {task.Value.CumulativeExecutionTime}");
        }
        Console.WriteLine("==========================================");
        Console.WriteLine("Tasks by memory consumption:");
        foreach (var task in _workerNodeTelemetryData.TasksExecutionData.OrderByDescending(t => t.Value.TotalMemoryConsumption).Take(20))
        {
            Console.WriteLine($"{task.Key} - {task.Value.TotalMemoryConsumption / 1024.0:0.00}kB");
        }
        Console.WriteLine("==========================================");
        Console.WriteLine("Tasks by Executions count:");
        foreach (var task in _workerNodeTelemetryData.TasksExecutionData.OrderByDescending(t => t.Value.ExecutionsCount))
        {
            Console.WriteLine($"{task.Key} - {task.Value.ExecutionsCount}");
        }
        Console.WriteLine("==========================================");
    }
 
    private void FlushDataIntoJsonFileIfRequested()
    {
        const string jsonFileNameVariable = "MSBUILDNODETELEMETRYFILENAME";
        var jsonFilePath = Environment.GetEnvironmentVariable(jsonFileNameVariable);
        if (string.IsNullOrEmpty(jsonFilePath))
        {
            return;
        }
 
        var telemetryTags = _workerNodeTelemetryData.AsActivityDataHolder(true, true)?.GetActivityProperties();
 
        using var stream = File.OpenWrite(jsonFilePath);
        stream.SetLength(0);
        JsonSerializer.Serialize(stream, telemetryTags, new JsonSerializerOptions() { WriteIndented = true });
    }
 
    public void Shutdown()
    { }
}