File: Latency\Internal\LatencyContext.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.Telemetry\Microsoft.Extensions.Telemetry.csproj (Microsoft.Extensions.Telemetry)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Extensions.ObjectPool;
 
namespace Microsoft.Extensions.Diagnostics.Latency.Internal;
 
/// <summary>
/// Implementation of <see cref="ILatencyContext"/>.
/// </summary>
internal sealed class LatencyContext : ILatencyContext, IResettable
{
    internal bool IsDisposed;
 
    internal bool IsRunning;
 
    private readonly ObjectPool<LatencyContext> _poolToReturnTo;
 
    private readonly CheckpointTracker _checkpointTracker;
 
    private readonly TagCollection _tagCollection;
 
    private readonly MeasureTracker _measureTracker;
 
    private long _duration;
 
    public LatencyContext(LatencyContextPool latencyContextPool)
    {
        var latencyInstrumentProvider = latencyContextPool.LatencyInstrumentProvider;
        _checkpointTracker = latencyInstrumentProvider.CreateCheckpointTracker();
        _measureTracker = latencyInstrumentProvider.CreateMeasureTracker();
        _tagCollection = latencyInstrumentProvider.CreateTagCollection();
        _poolToReturnTo = latencyContextPool.Pool;
        IsRunning = true;
    }
 
    public LatencyData LatencyData => IsDisposed ? default : new(_tagCollection.Tags, _checkpointTracker.Checkpoints, _measureTracker.Measures, Duration, _checkpointTracker.Frequency);
 
    private long Duration => IsRunning ? _checkpointTracker.Elapsed : _duration;
 
    #region Checkpoints
    public void AddCheckpoint(CheckpointToken token)
    {
        if (IsRunning)
        {
            _checkpointTracker.Add(token);
        }
    }
    #endregion
 
    #region Tags
    public void SetTag(TagToken token, string value)
    {
        if (IsRunning)
        {
            _tagCollection.Set(token, value);
        }
    }
    #endregion
 
    #region Measure
    public void AddMeasure(MeasureToken token, long value)
    {
        if (IsRunning)
        {
            _measureTracker.AddLong(token, value);
        }
    }
 
    public void RecordMeasure(MeasureToken token, long value)
    {
        if (IsRunning)
        {
            _measureTracker.SetLong(token, value);
        }
    }
    #endregion
 
    #region State
    public void Freeze()
    {
        if (IsRunning)
        {
            IsRunning = false;
            _duration = _checkpointTracker.Elapsed;
        }
    }
 
    public void Dispose()
    {
        if (IsDisposed)
        {
            return;
        }
 
        if (IsRunning)
        {
            Freeze();
        }
 
        _poolToReturnTo.Return(this);
        IsDisposed = true;
    }
 
    public bool TryReset()
    {
        _ = _checkpointTracker.TryReset();
        _ = _measureTracker.TryReset();
        _ = _tagCollection.TryReset();
        IsRunning = true;
        IsDisposed = false;
        return true;
    }
    #endregion
}