File: CoordinatorTelemetry.cs
Web Access
Project: src\msbuild\src\MSBuild.Coordinator\MSBuild.Coordinator.csproj (MSBuild.Coordinator)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Framework.Telemetry;

namespace Microsoft.Build.Coordinator;

/// <summary>
///  Provides telemetry instrumentation for the coordinator server using MSBuild's
///  standard telemetry infrastructure (<see cref="MSBuildActivitySource"/>).
///  On .NET, activities are emitted via <see cref="System.Diagnostics.Activity"/>.
///  On .NET Framework, activities are emitted via VS Telemetry.
/// </summary>
internal static class CoordinatorTelemetry
{
    // Activity names
    private const string ActivityPrefix = "Coordinator/";

    private const string GrantActivity = $"{ActivityPrefix}Grant";
    private const string DeferredActivity = $"{ActivityPrefix}Deferred";
    private const string DeferredGrantFulfilledActivity = $"{ActivityPrefix}DeferredGrantFulfilled";
    private const string ReleasedActivity = $"{ActivityPrefix}Released";

    // Tag names
    private const string ConnectionIdTag = "ConnectionId";
    private const string ProcessIdTag = "ProcessId";
    private const string NodesRequestedTag = "NodesRequested";
    private const string NodesGrantedTag = "NodesGranted";
    private const string NodesReleasedTag = "NodesReleased";
    private const string QueueDepthTag = "QueueDepth";
    private const string ActiveBuildsTag = "ActiveBuilds";
    private const string AllocatedNodesTag = "AllocatedNodes";

    private static IActivity? StartActivity(string name)
        => TelemetryManager.Instance.DefaultActivitySource?.StartActivity(name);

    /// <summary>
    ///  Records that a node grant was issued immediately to a build.
    /// </summary>
    public static void RecordGrantIssued(BuildGrant grant, int queueDepth, int activeBuilds, int allocatedNodes)
    {
        using IActivity? _ = StartActivity(GrantActivity)
            ?.SetTag(ConnectionIdTag, grant.ConnectionId)
            ?.SetTag(ProcessIdTag, grant.ProcessId)
            ?.SetTag(NodesRequestedTag, grant.RequestedNodes)
            ?.SetTag(NodesGrantedTag, grant.GrantedNodes)
            ?.SetTag(QueueDepthTag, queueDepth)
            ?.SetTag(ActiveBuildsTag, activeBuilds)
            ?.SetTag(AllocatedNodesTag, allocatedNodes);
    }

    /// <summary>
    ///  Records that a build was queued because no nodes were available.
    /// </summary>
    public static void RecordGrantDeferred(BuildGrant grant, int queueDepth)
    {
        using IActivity? _ = StartActivity(DeferredActivity)
            ?.SetTag(ConnectionIdTag, grant.ConnectionId)
            ?.SetTag(ProcessIdTag, grant.ProcessId)
            ?.SetTag(NodesRequestedTag, grant.RequestedNodes)
            ?.SetTag(QueueDepthTag, queueDepth);
    }

    /// <summary>
    ///  Records that a deferred grant was fulfilled from the wait queue.
    /// </summary>
    public static void RecordDeferredGrantFulfilled(BuildGrant grant, int queueDepth, int activeBuilds, int allocatedNodes)
    {
        using IActivity? _ = StartActivity(DeferredGrantFulfilledActivity)
            ?.SetTag(ConnectionIdTag, grant.ConnectionId)
            ?.SetTag(ProcessIdTag, grant.ProcessId)
            ?.SetTag(NodesGrantedTag, grant.GrantedNodes)
            ?.SetTag(QueueDepthTag, queueDepth)
            ?.SetTag(ActiveBuildsTag, activeBuilds)
            ?.SetTag(AllocatedNodesTag, allocatedNodes);
    }

    /// <summary>
    ///  Records that a grant was released by a client.
    /// </summary>
    public static void RecordGrantReleased(BuildGrant grant, int queueDepth, int activeBuilds, int allocatedNodes)
    {
        using IActivity? _ = StartActivity(ReleasedActivity)
            ?.SetTag(ConnectionIdTag, grant.ConnectionId)
            ?.SetTag(ProcessIdTag, grant.ProcessId)
            ?.SetTag(NodesReleasedTag, grant.GrantedNodes)
            ?.SetTag(QueueDepthTag, queueDepth)
            ?.SetTag(ActiveBuildsTag, activeBuilds)
            ?.SetTag(AllocatedNodesTag, allocatedNodes);
    }
}