File: src\VisualStudio\Core\Def\Telemetry\Shared\AggregatingHistogramLog.cs
Web Access
Project: src\src\Workspaces\Remote\ServiceHub\Microsoft.CodeAnalysis.Remote.ServiceHub.csproj (Microsoft.CodeAnalysis.Remote.ServiceHub)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.VisualStudio.Telemetry;
using Microsoft.VisualStudio.Telemetry.Metrics;
using Microsoft.VisualStudio.Telemetry.Metrics.Events;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Telemetry;
 
/// <summary>
/// Provides a wrapper around the VSTelemetry histogram APIs to support aggregated telemetry. Each instance
/// of this class corresponds to a specific FunctionId operation and can support aggregated values for each
/// metric name logged.
/// </summary>
internal sealed class AggregatingHistogramLog : AbstractAggregatingLog<IHistogram<long>, long>, ITelemetryBlockLog
{
    private readonly HistogramConfiguration? _histogramConfiguration;
 
    /// <summary>
    /// Creates a new aggregating telemetry log
    /// </summary>
    /// <param name="session">Telemetry session used to post events</param>
    /// <param name="functionId">Used to derive meter name</param>
    /// <param name="bucketBoundaries">Optional values indicating bucket boundaries in milliseconds. If not specified, 
    /// all histograms created will use the default histogram configuration</param>
    public AggregatingHistogramLog(TelemetrySession session, FunctionId functionId, double[]? bucketBoundaries) : base(session, functionId)
    {
        if (bucketBoundaries != null)
        {
            _histogramConfiguration = new HistogramConfiguration(bucketBoundaries);
        }
    }
 
    public IDisposable? LogBlockTime(KeyValueLogMessage logMessage, int minThresholdMs)
    {
        if (!IsEnabled)
            return null;
 
        if (!logMessage.Properties.TryGetValue(TelemetryLogging.KeyName, out var nameValue) || nameValue is not string)
            throw ExceptionUtilities.Unreachable();
 
        return new TimedTelemetryLogBlock(logMessage, minThresholdMs, telemetryLog: this);
    }
 
    protected override IHistogram<long> CreateAggregator(IMeter meter, string metricName)
    {
        return meter.CreateHistogram<long>(metricName, _histogramConfiguration);
    }
 
    protected override void UpdateAggregator(IHistogram<long> histogram, long value)
    {
        histogram.Record(value);
    }
 
    protected override TelemetryMetricEvent CreateTelemetryEvent(TelemetryEvent telemetryEvent, IHistogram<long> histogram)
    {
        return new TelemetryHistogramEvent<long>(telemetryEvent, histogram);
    }
}