Microsoft.Extensions.Logging日志记录器包装器的实现和使用

本文关键字:实现 包装 Extensions Logging 日志 记录器 Microsoft | 更新日期: 2023-09-27 18:08:06

这个问题与Steven的答案有关。他提出了一个非常好的记录器包装器。我将他的代码粘贴到下面:

public interface ILogger
{
    void Log(LogEntry entry);
}
public static class LoggerExtensions
{
    public static void Log(this ILogger logger, string message)
    {
        logger.Log(new LogEntry(LoggingEventType.Information,
            message, null));
    }
    public static void Log(this ILogger logger, Exception exception)
    {
        logger.Log(new LogEntry(LoggingEventType.Error, 
            exception.Message, exception));
    }
    // More methods here.
}
所以,我的问题是创建代理Microsoft.Extensions的实现的正确方法是什么。记录在代码中使用它的最佳方法是什么?

注意:这个问题是关于log4net的问题的副本,但现在特定于Microsoft.Extensions.Logging.

Microsoft.Extensions.Logging日志记录器包装器的实现和使用

所以,我的问题是,创建代理Microsoft.Extensions.ILogger的实现的正确方法是什么?

你应该创建如下内容:

public sealed class MicrosoftLoggingAdapter  : ILogger
{
    private readonly Microsoft.Extensions.ILogger adaptee;
    public MicrosoftLoggingAdapter (Microsoft.Extensions.ILogger adaptee) =>
        this.adaptee = adaptee;
    public void Log(LogEntry e) =>
        adaptee.Log(ToLevel(e.Severity), 0, e.Message, e.Exception, (s, _) => s);       
    private static LogLevel ToLevel(LoggingEventType s) =>
        s == LoggingEventType.Debug ? LogLevel.Debug  :
        s == LoggingEventType.Information ? LogLevel.Information :
        s == LoggingEventType.Warning ? LogLevel.Warning :
        s == LoggingEventType.Error ? LogLevel.Error :
        LogLevel.Critical;      
}

在后面的代码中使用它的最好方法是什么?

如果您使用的是DI容器,那么只需使用DI容器将ILogger映射到MicrosoftLoggingAdapter。你还需要注册Microsoft.Extensions.ILogger,或者只是给一个MS logger的实例到DI容器注入它到MicrosoftLoggingAdapter构造器。

如果你不使用DI容器,也就是说,你使用纯DI,那么你做这样的事情:

var logger = loggerFactory.CreateLogger("Application");
ILogger logging_adapter = new MicrosoftLoggingAdapter(logger);
var myobject = new MyClass(other_dependencies_here, logging_adapter);

这是我的解决方案。不太像史蒂文的。但又不完全一样。我的倾向于dotNetCore,但同样的事情也可以在dotnetFW中完成。

DotNetCoreLogger是"MY"ILogger的具体实例。我将"microsoft" ILogger (microsoft . extensions . logging .ILogger)注入到"My"具体的logger中。

有另一个SOF的答案,"启发"我的"日志抽象....从DotNetFramework(经典)到DotNotCore,我很高兴我做了一个"我的"ILogger抽象。

using System;
namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
    public interface ILogger
    {
        void Log(LogEntry entry);
        void Log(string message);
        void Log(Exception exception);
    }
}

namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
    public enum LoggingEventTypeEnum
    {
        Debug,
        Information,
        Warning,
        Error,
        Fatal
    };
}

using System;
namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
    public class LogEntry
    {
        public readonly LoggingEventTypeEnum Severity;
        public readonly string Message;
        public readonly Exception Exception;
        public LogEntry(LoggingEventTypeEnum severity, string message, Exception exception = null)
        {
            if (message == null) throw new ArgumentNullException("message");
            if (message == string.Empty) throw new ArgumentException("empty", "message");
            this.Severity = severity;
            this.Message = message;
            this.Exception = exception;
        }
    }
}

using System;
using Microsoft.Extensions.Logging;
namespace MyApplication.Infrastructure.Logging.LoggingCoreConcrete
{
    public class DotNetCoreLogger<T> : MyApplication.Infrastructure.Logging.LoggingAbstractBase.ILogger
    {
        private readonly ILogger<T> concreteLogger;
        public DotNetCoreLogger(Microsoft.Extensions.Logging.ILogger<T> concreteLgr)
        {
            this.concreteLogger = concreteLgr ?? throw new ArgumentNullException("Microsoft.Extensions.Logging.ILogger is null");
        }
        public void Log(MyApplication.Infrastructure.Logging.LoggingAbstractBase.LogEntry entry)
        {
            if (null == entry)
            {
                throw new ArgumentNullException("LogEntry is null");
            }
            else
            {
                switch (entry.Severity)
                {
                    case LoggingAbstractBase.LoggingEventTypeEnum.Debug:
                        this.concreteLogger.LogDebug(entry.Message);
                        break;
                    case LoggingAbstractBase.LoggingEventTypeEnum.Information:
                        this.concreteLogger.LogInformation(entry.Message);
                        break;
                    case LoggingAbstractBase.LoggingEventTypeEnum.Warning:
                        this.concreteLogger.LogWarning(entry.Message);
                        break;
                    case LoggingAbstractBase.LoggingEventTypeEnum.Error:
                        this.concreteLogger.LogError(entry.Message, entry.Exception);
                        break;
                    case LoggingAbstractBase.LoggingEventTypeEnum.Fatal:
                        this.concreteLogger.LogCritical(entry.Message, entry.Exception);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(string.Format("LogEntry.Severity out of range. (Severity='{0}')", entry.Severity));
                }
            }
        }
        public void Log(string message)
        {
            this.concreteLogger.LogInformation(message);
        }
        public void Log(Exception exception)
        {
        /* "Always pass exception as first parameter" from https://blog.rsuter.com/logging-with-ilogger-recommendations-and-best-practices/ */

        /* there is an issue with https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Abstractions/LoggerExtensions.cs
         * the default MessageFormatter (for the extension methods) is not doing anything with the "error".  this plays out as not getting full exception information when using extension methods.  :(
         * 
         *         private static string MessageFormatter(FormattedLogValues state, Exception error)
         *         {
         *                  return state.ToString();
         *         }
         *          
         * Below code/implementation is purposely NOT using any extension method(s) to bypass the above MessageFormatter mishap.
         * 
         * */
            this.concreteLogger.Log(LogLevel.Error, exception, exception.Message);
        }
    }
}

/* IoC/DI below */

        private static System.IServiceProvider BuildDi(Microsoft.Extensions.Configuration.IConfiguration config)
        {
            //setup our DI
            IServiceProvider serviceProvider = new ServiceCollection()
                .AddLogging()
                .AddSingleton<IConfiguration>(config)
                .AddSingleton<MyApplication.Infrastructure.Logging.LoggingAbstractBase.ILogger, MyApplication.Infrastructure.Logging.LoggingCoreConcrete.DotNetCoreLogger<Program>>()
                .BuildServiceProvider();
            //configure console logging
            serviceProvider
                .GetService<ILoggerFactory>()
                .AddConsole(LogLevel.Debug);
            return serviceProvider;
        }