File: Metrics\DefaultMeterFactory.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.Diagnostics\src\Microsoft.Extensions.Diagnostics.csproj (Microsoft.Extensions.Diagnostics)
// 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.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.Metrics;
 
namespace Microsoft.Extensions.Diagnostics.Metrics
{
    internal sealed class DefaultMeterFactory : IMeterFactory
    {
        private readonly Dictionary<string, List<FactoryMeter>> _cachedMeters = new();
        private bool _disposed;
 
        public DefaultMeterFactory() { }
 
        public Meter Create(MeterOptions options)
        {
            if (options is null)
            {
                throw new ArgumentNullException(nameof(options));
            }
 
            if (options.Scope is not null && !object.ReferenceEquals(options.Scope, this))
            {
                throw new InvalidOperationException(SR.InvalidScope);
            }
 
            Debug.Assert(options.Name is not null);
 
            lock (_cachedMeters)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(nameof(DefaultMeterFactory));
                }
 
                if (_cachedMeters.TryGetValue(options.Name, out List<FactoryMeter>? meterList))
                {
                    foreach (Meter meter in meterList)
                    {
                        if (meter.Version == options.Version && DiagnosticsHelper.CompareTags(meter.Tags as IList<KeyValuePair<string, object?>>, options.Tags))
                        {
                            return meter;
                        }
                    }
                }
                else
                {
                    meterList = new List<FactoryMeter>();
                    _cachedMeters.Add(options.Name, meterList);
                }
 
                object? scope = options.Scope;
                options.Scope = this;
                FactoryMeter m = new FactoryMeter(options);
                options.Scope = scope;
 
                meterList.Add(m);
                return m;
            }
        }
 
        public void Dispose()
        {
            lock (_cachedMeters)
            {
                if (_disposed)
                {
                    return;
                }
 
                _disposed = true;
 
                foreach (List<FactoryMeter> meterList in _cachedMeters.Values)
                {
                    foreach (FactoryMeter meter in meterList)
                    {
                        meter.Release();
                    }
                }
 
                _cachedMeters.Clear();
            }
        }
    }
 
    internal sealed class FactoryMeter : Meter
    {
        public FactoryMeter(MeterOptions options) : base(options)
        {
        }
 
        public void Release() => base.Dispose(true); // call the protected Dispose(bool)
 
        protected override void Dispose(bool disposing)
        {
            // no-op, disallow users from disposing of the meters created from the factory.
        }
    }
}