Реализация и использование оболочки журнала для Microsoft.Extensions.Logging
Этот вопрос связан с ответом 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.Logging, и как лучше использовать ее позже в коде?
Примечание. Этот вопрос является копией этого вопроса о log4net, но теперь относится только к Microsoft.Extensions.Logging.
2 ответа
Итак, мой вопрос заключается в том, как правильно создать реализацию, которая прокси-сервер 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, т.е. вы используете Pure DI, то вы делаете что-то вроде этого:
var logger = loggerFactory.CreateLogger("Application");
ILogger logging_adapter = new MicrosoftLoggingAdapter(logger);
var myobject = new MyClass(other_dependencies_here, logging_adapter);
Вот мое решение. Не слишком в отличие от Стивена. Но не совсем так. И моя склоняется к dotNetCore, но то же самое можно сделать с помощью dotnetFW.
DotNetCoreLogger - это бетон "МОЕГО" ILogger. И я вставляю "Microsoft" ILogger (Microsoft.Extensions.Logging.ILogger) в "Мой" конкретный регистратор.
Есть другой ответ SOF, который "вдохновил" "мою" абстракцию журналирования… и после перехода от DotNetFramework (classic) к 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)
{
this.concreteLogger.LogError(exception.Message, exception);
}
}
}
/* 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;
}