< Summary

Information
Class: AmbientServices.AmbientCostTrackerCoordinator
Assembly: AmbientServices
File(s): /home/runner/work/AmbientServices/AmbientServices/AmbientServices/Helpers/CostTrackerHelpers.cs
Tag: 332_35464845198
Line coverage
100%
Covered lines: 38
Uncovered lines: 0
Coverable lines: 38
Total lines: 191
Line coverage: 100%
Branch coverage
95%
Covered branches: 19
Total branches: 20
Branch coverage: 95%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor()100%11100%
.ctor(...)100%22100%
OnChargesAccrued(...)50%22100%
OnOngoingCostChanged(...)100%22100%
CreateCallContextProfiler(...)100%44100%
CreateTimeWindowProfiler(...)100%22100%
CreateProcessProfiler(...)100%22100%
Dispose(...)100%66100%
Dispose()100%11100%

File(s)

/home/runner/work/AmbientServices/AmbientServices/AmbientServices/Helpers/CostTrackerHelpers.cs

#LineLine coverage
 1#if NET5_0_OR_GREATER
 2using System;
 3using System.Threading;
 4using System.Threading.Tasks;
 5#endif
 6
 7namespace AmbientServices;
 8
 9#if NET5_0_OR_GREATER
 10/// <summary>
 11/// A class that coordinates cost trackers.
 12/// </summary>
 13/// <remarks>
 14/// <pitch>The factory you use to turn the raw <see cref="IAmbientCostTracker"/> report stream into actual accumulations
 15/// <pledge><see cref="IAmbientCostTrackerNotificationSink"/></pledge>
 16/// <pledge>
 17/// Returns null from every factory method when there is no ambient <see cref="IAmbientCostTracker"/> to observe.  Each 
 18/// A call-context tracker sees only costs reported from within its own call context; time-window and process trackers s
 19/// </pledge>
 20/// <plan>
 21/// The coordinator registers itself with the ambient cost tracker (captured at construction) as a notification sink and
 22/// </plan>
 23/// </remarks>
 24public class AmbientCostTrackerCoordinator : IAmbientCostTrackerNotificationSink, IDisposable
 25{
 226    private static readonly AmbientService<IAmbientSettingsSet> _SettingsSet = Ambient.GetService<IAmbientSettingsSet>()
 227    private static readonly AmbientService<IAmbientCostTracker> _AmbientCostTracker = Ambient.GetService<IAmbientCostTra
 28
 29    private readonly IAmbientCostTracker? _eventBroadcaster;
 30    private readonly AsyncLocal<ScopeOnChargesAccruedDistributor> _scopeDistributor;
 31    private bool _disposedValue;
 32
 33    /// <summary>
 34    /// Constructs an AmbientCostTrackerCoordinator using settings obtained from the ambient settings set.
 35    /// </summary>
 36    public AmbientCostTrackerCoordinator()
 237        : this(_SettingsSet.Local)
 38    {
 239    }
 40    /// <summary>
 41    /// Constructs an AmbientCostTrackerCoordinator using the specified settings set.
 42    /// </summary>
 43    /// <param name="settingsSet"></param>
 244    public AmbientCostTrackerCoordinator(IAmbientSettingsSet? settingsSet)
 45    {
 246        _scopeDistributor = new AsyncLocal<ScopeOnChargesAccruedDistributor>();
 247        _eventBroadcaster = _AmbientCostTracker.Local;
 248        _eventBroadcaster?.RegisterCostTrackerNotificationSink(this);
 249    }
 50
 51    /// <summary>
 52    /// Notifies the notification sink that charges have accrued.
 53    /// </summary>
 54    /// <param name="serviceId">An optional service identifier, with empty string indicating the system itself.</param>
 55    /// <param name="customerId">A string identifying the customer.</param>
 56    /// <param name="charge">The charge (in picodollars).</param>
 57    public void OnChargesAccrued(string serviceId, string customerId, long charge)
 58    {
 259        _scopeDistributor.Value ??= new ScopeOnChargesAccruedDistributor();
 260        _scopeDistributor.Value.OnChargesAccrued(serviceId, customerId, charge);
 261    }
 62    /// <summary>
 63    /// Notifies the notification sink that an ongoing cost has changed.
 64    /// </summary>
 65    /// <param name="serviceId">An optional service identifier, with empty string indicating the system itself.</param>
 66    /// <param name="customerId">A string identifying the customer.</param>
 67    /// <param name="changePerMonth">The change in cost (in picodollars per month).</param>
 68    public void OnOngoingCostChanged(string serviceId, string customerId, long changePerMonth)
 69    {
 270        _scopeDistributor.Value ??= new ScopeOnChargesAccruedDistributor();
 271        _scopeDistributor.Value.OnOngoingCostChanged(serviceId, customerId, changePerMonth);
 272    }
 73    /// <summary>
 74    /// Creates a cost tracker which profiles the current call context.
 75    /// </summary>
 76    /// <param name="scopeName">A name of the call context to attach to the analyzer.</param>
 77    /// <returns>A <see cref="IAmbientAccruedChargesAndCostChanges"/> that will profile systems executed in this call co
 78    public IAmbientAccruedChargesAndCostChanges? CreateCallContextProfiler(string scopeName)
 79    {
 280        IAmbientCostTracker? metrics = _AmbientCostTracker.Local;
 281        if (metrics != null)
 82        {
 283            _scopeDistributor.Value ??= new ScopeOnChargesAccruedDistributor();
 284            CallContextCostTracker analyzer = new(_scopeDistributor.Value, scopeName);
 285            return analyzer;
 86        }
 287        return null;
 88    }
 89    /// <summary>
 90    /// Creates a cost tracker which profiles the entire process in sequential time units of the specified size.
 91    /// </summary>
 92    /// <param name="scopeNamePrefix">A <see cref="TimeSpan"/> indicating the size of the window.</param>
 93    /// <param name="windowPeriod">A <see cref="TimeSpan"/> indicating how often reports are desired.</param>
 94    /// <param name="onWindowComplete">An async delegate that receives a <see cref="IAmbientServiceProfile"/> at the end
 95    /// <returns>A <see cref="IDisposable"/> that scopes the collection of the profiles.</returns>
 96#pragma warning disable CA1822 // Mark members as static--I reserve the right to use member data in this function in the
 97    public IDisposable? CreateTimeWindowProfiler(string scopeNamePrefix, TimeSpan windowPeriod, Func<IAmbientAccruedChar
 98#pragma warning restore CA1822 // Mark members as static
 99    {
 2100        IAmbientCostTracker? metrics = _AmbientCostTracker.Local;
 2101        if (metrics == null) return null;
 2102        TimeWindowCostTracker tracker = new(metrics, scopeNamePrefix, windowPeriod, onWindowComplete);
 2103        return tracker;
 104    }
 105    /// <summary>
 106    /// Creates a cost tracker which profiles the entire process for the entire (remaining) duration of execution.
 107    /// Note that this is only useful to determine the distribution for an entire process from start to finish, which is
 108    /// <see cref="CreateTimeWindowProfiler"/> is a better match in most situations.
 109    /// </summary>
 110    /// <param name="scopeName">A name for the context to attach to the analyzer.</param>
 111    /// <returns>A <see cref="IAmbientAccruedChargesAndCostChanges"/> containing a service profile for the entire proces
 112    /// <remarks>
 113    /// This is different from using <see cref="CreateCallContextProfiler"/> because that will only analyze the call con
 114    /// whereas this will analyze all threads and call contexts in the process.
 115    /// They will produce the same results only for programs where there is only a single call context (no parallelizati
 116    /// </remarks>
 117#pragma warning disable CA1822 // Mark members as static--I reserve the right to use member data in this function in the
 118    public IAmbientAccruedChargesAndCostChanges? CreateProcessProfiler(string scopeName)
 119#pragma warning restore CA1822 // Mark members as static
 120    {
 2121        IAmbientCostTracker? metrics = _AmbientCostTracker.Local;
 2122        if (metrics != null)
 123        {
 2124            ProcessOrSingleTimeWindowCostTracker tracker = new(metrics, scopeName);
 2125            return tracker;
 126        }
 2127        return null;
 128    }
 129    /// <summary>
 130    /// Disposes of this instance.  May be overridden by derived classes.
 131    /// </summary>
 132    /// <param name="disposing">Whether or not we're disposing (as opposed to finalizing).</param>
 133    protected virtual void Dispose(bool disposing)
 134    {
 2135        if (!_disposedValue)
 136        {
 2137            if (disposing)
 138            {
 139                // TODO: dispose managed state (managed objects)
 2140                _eventBroadcaster?.DeregisterCostTrackerNotificationSink(this);
 141            }
 142
 143            // TODO: free unmanaged resources (unmanaged objects) and override finalizer
 144            // TODO: set large fields to null
 2145            _disposedValue = true;
 146        }
 2147    }
 148    /// <summary>
 149    /// Disposes of this instance.
 150    /// </summary>
 151    public void Dispose()
 152    {
 153        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 2154        Dispose(disposing: true);
 2155        GC.SuppressFinalize(this);
 2156    }
 157}
 158/// <summary>
 159/// An interface that abstracts accrued charges and cost changes.
 160/// </summary>
 161/// <remarks>
 162/// <pitch>The read side of cost tracking: for one scope (a call context, a time window, or a whole process), the total 
 163/// <pledge>
 164/// Charges and ongoing-cost changes accumulate separately and are never combined: the charge sum is a total amount (pic
 165/// Values may be read while the scope is still collecting (a point-in-time snapshot) or after disposal ends the collect
 166/// </pledge>
 167/// </remarks>
 168public interface IAmbientAccruedChargesAndCostChanges : IDisposable
 169{
 170    /// <summary>
 171    /// Gets the name of the scope being analyzed.  The scope identifies the scope of the operations that were profiled.
 172    /// </summary>
 173    string ScopeName { get; }
 174    /// <summary>
 175    /// Gets the number of separate operations triggering charge accumulation.
 176    /// </summary>
 177    int ChargeCount { get; }
 178    /// <summary>
 179    /// Gets the accumulated sum of all the charges.
 180    /// </summary>
 181    long AccumulatedChargeSum { get; }
 182    /// <summary>
 183    /// Gets the number of separate operations triggering cost changes.
 184    /// </summary>
 185    int CostChangeCount { get; }
 186    /// <summary>
 187    /// Gets the accumulated sum of all the cost changes.
 188    /// </summary>
 189    long AccumulatedCostChangeSum { get; }
 190}
 191#endif