File: Logging\FakeLoggerProvider.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.Diagnostics.Testing\Microsoft.Extensions.Diagnostics.Testing.csproj (Microsoft.Extensions.Diagnostics.Testing)
// 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.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Shared.Diagnostics;
 
namespace Microsoft.Extensions.Logging.Testing;
 
// bug in .NET 7 preview analyzer
#pragma warning disable CA1063
 
/// <summary>
/// Provides fake loggers.
/// </summary>
[ProviderAlias("Fake")]
public class FakeLoggerProvider : ILoggerProvider, ISupportExternalScope
{
    private readonly ConcurrentDictionary<string, FakeLogger> _loggers = new();
    private IExternalScopeProvider _scopeProvider = new LoggerExternalScopeProvider();
 
    /// <summary>
    /// Initializes a new instance of the <see cref="FakeLoggerProvider"/> class.
    /// </summary>
    /// <param name="collector">The collector that will receive all log records emitted to fake loggers.</param>
    public FakeLoggerProvider(FakeLogCollector? collector = null)
    {
        Collector = collector ?? new FakeLogCollector();
    }
 
    /// <summary>
    /// Finalizes an instance of the <see cref="FakeLoggerProvider"/> class.
    /// </summary>
    [ExcludeFromCodeCoverage]
    ~FakeLoggerProvider()
    {
        Dispose(false);
    }
 
    /// <summary>
    /// Sets external scope information source for logger provider.
    /// </summary>
    /// <param name="scopeProvider">The provider of scope data.</param>
    public void SetScopeProvider(IExternalScopeProvider scopeProvider)
    {
        _scopeProvider = Throw.IfNull(scopeProvider);
 
        foreach (var entry in _loggers)
        {
            entry.Value.ScopeProvider = _scopeProvider;
        }
    }
 
    /// <summary>
    /// Creates a new <see cref="ILogger"/> instance.
    /// </summary>
    /// <param name="categoryName">The category name for messages produced by the logger.</param>
    /// <returns>The instance of <see cref="ILogger"/> that was created.</returns>
    ILogger ILoggerProvider.CreateLogger(string categoryName) => CreateLogger(categoryName);
 
    /// <summary>
    /// Creates a new <see cref="FakeLogger"/> instance.
    /// </summary>
    /// <param name="categoryName">The category name for messages produced by the logger.</param>
    /// <returns>The instance of <see cref="ILogger"/> that was created.</returns>
    public FakeLogger CreateLogger(string? categoryName)
    {
        return _loggers.GetOrAdd(categoryName ?? string.Empty, (name) => new(Collector, name)
        {
            ScopeProvider = _scopeProvider,
        });
    }
 
    /// <summary>
    /// Cleans up resources held by this object.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    /// <summary>
    /// Gets the log record collector for all loggers created by this provider.
    /// </summary>
    public FakeLogCollector Collector { get; }
 
    /// <summary>
    /// Cleans up resources held by this object.
    /// </summary>
    /// <param name="disposing"><see langword="true"/> when called from the <see cref="Dispose()"/> method, <see langword="false"/> when called from a finalizer.</param>
    protected virtual void Dispose(bool disposing)
    {
    }
 
    internal string FirstLoggerName => _loggers.First().Key;
}