logging器包装最佳实践

我想在我的应用程序中使用nlogger,也许将来我需要更改日志logging系统。 所以我想用一个logging门面。

你知道现有的例子如何写这些的build议吗? 或者只是给我链接这方面的一些最佳做法。

我曾经使用Common.Logging (甚至隐藏我自己的CuttingEdge.Logging库)等日志外观,但是现在我使用dependency injection模式 ,这使得我可以将日志logging隐藏在我自己的(简单)抽象上, 反转原理和接口隔离原理 (ISP),因为它有一个成员,因为接口是由我的应用程序定义的; 不是外部的图书馆。 最大限度地减less应用程序核心部分关于外部库存在的知识, 即使你无意replace你的日志库。 对外部库的严重依赖性使testing代码变得更加困难,并且使用从未专门为您的应用程序devise的API将应用程序复杂化。

这是抽象在我的应用程序中经常看起来像什么:

public interface ILogger { void Log(LogEntry entry); } public enum LoggingEventType { Debug, Information, Warning, Error, Fatal }; // Immutable DTO that contains the log information. public class LogEntry { public readonly LoggingEventType Severity; public readonly string Message; public readonly Exception Exception; public LogEntry(LoggingEventType 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; } } 

可选地,这个抽象可以用一些简单的扩展方法来扩展(允许接口保持狭窄并且坚持ISP)。 这使得这个接口的用户代码更加简单:

 public static class LoggerExtensions { public static void Log(this ILogger logger, string message) { logger.Log(new LogEntry(LoggingEventType.Information, message)); } public static void Log(this ILogger logger, Exception exception) { logger.Log(new LogEntry(LoggingEventType.Error, exception.Message, exception)); } // More methods here. } 

由于该接口只包含一个方法,因此您可以轻松地创build代理log4net的ILogger实现, Serilog , Microsoft.Extensions.Logging ,NLog或任何其他日志logging库,并configuration您的DI容器以将其注入到具有ILogger在他们的构造函数。

请注意,使用单个方法在接口上使用静态扩展方法与使用多个成员的接口完全不同。 扩展方法只是帮助程序方法,它们创buildLogEntry消息并通过ILogger接口上的唯一方法传递它。 扩展方法成为消费者代码的一部分; 不是抽象的一部分。 这不仅允许扩展方法在不需要改变抽象的情况下发展,而且当使用logging器抽象时,即使当logging器被嘲弄/嘲弄时,扩展方法和LogEntry构造器也总是被执行。 这使得在testing套件中运行时对logging器的调用的正确性更加确定。 一元界面使testing更容易; 对许多成员进行抽象使得很难创build实现(例如模拟器,适配器和装饰器)。

当你这样做的时候,几乎没有任何需要logging正面(或任何其他库)提供的静态抽象。

一般我比较喜欢创build一个接口

 public interface ILogger { void LogInformation(string msg); void LogError(string error); } 

在运行时注入一个从这个接口实现的具体类。

这个问题的一个很好的解决scheme已经以LibLog项目的forms出现了。

LibLog是一个logging抽象,内置了对主要logging器的支持,包括Serilog,NLog,Log4net和Enterpriselogging器。 它通过NuGet包pipe理器作为源(.cs)文件而不是.dll引用安装到目标库中。 该方法允许将日志抽象包含在内,而不会强制该库承担外部依赖。 它还允许库作者在不强迫消费应用程序显式地向库提供logging器的情况下包含日志logging。 LibLog使用reflection来确定具体的logging器在使用中,并在库项目中没有任何明确的接线代码的情况下进行连接。

所以,LibLog是在库项目中logging的一个很好的解决scheme。 只需在您的主应用程序或服务中引用和configuration一个具体的logging器(Serilog for the win),并将LibLog添加到您的库中!

您可以使用城堡日志logging服务或简单日志logging外观来代替编写自己的外观 。

两者都包含适用于NLog和Log4net的适配器。

自2015年以来,如果您正在构build.NET核心应用程序,则还可以使用.NET Core Logging 。

NLog挂钩的包是:

  • NLog.Web.AspNetCore for ASP.NET Core用户
  • .NET核心用户的NLog.Extensions.Logging ,例如控制台项目