C# 记录器包装器最佳实践
我想在我的应用程序中使用nlogger,也许将来我需要更改日志系统。 所以我想使用一个日志外观 你知道对现有例子有什么建议吗?如何写这些例子?C# 记录器包装器最佳实践,c#,.net,logging,nlog,C#,.net,Logging,Nlog,我想在我的应用程序中使用nlogger,也许将来我需要更改日志系统。 所以我想使用一个日志外观 你知道对现有例子有什么建议吗?如何写这些例子? 或者只是给我一些这方面的最佳实践的链接。您可以使用或,而不是编写自己的外观 两者都包括NLog和Log4net的适配器。我以前使用日志外观,例如(甚至隐藏我自己的库),但现在我使用。这允许我将日志记录器隐藏在应用程序定义的抽象后面,该抽象同时遵循和(ISP),因为它有一个成员,并且接口是由我的应用程序定义的;不是外部图书馆 尽可能减少应用程序的核心部分对
或者只是给我一些这方面的最佳实践的链接。您可以使用或,而不是编写自己的外观
两者都包括NLog和Log4net的适配器。我以前使用日志外观,例如(甚至隐藏我自己的库),但现在我使用。这允许我将日志记录器隐藏在应用程序定义的抽象后面,该抽象同时遵循和(ISP),因为它有一个成员,并且接口是由我的应用程序定义的;不是外部图书馆 尽可能减少应用程序的核心部分对外部库存在的了解,这样更好;即使您不打算更换日志库。对外部库的硬依赖性使得测试代码更加困难,并且使用从未专门为应用程序设计的API使应用程序复杂化 在我的应用程序中,抽象通常是这样的:
公共接口ILogger
{
作废日志(日志条目);
}
公共枚举日志事件类型{Debug,Information,Warning,Error,Fatal};
//包含日志信息的不可变DTO。
公共类日志条目
{
public LoggingEventType严重性{get;}
公共字符串消息{get;}
公共异常{get;}
公共登录(
LoggingEventType严重性,字符串消息,异常=null)
{
如果(message==null)抛出新的ArgumentNullException(“message”);
if(message==string.Empty)
抛出新ArgumentException(“空”、“消息”);
严重性=严重性;
this.Message=消息;
this.Exception=异常;
}
}
或者,可以使用一些简单的扩展方法来扩展这个抽象(允许接口保持狭窄并保持与ISP的一致性)。这使得此接口的使用者的代码更加简单:
公共静态类LoggerExtensions
{
公共静态无效日志(此ILogger记录器,字符串消息){
logger.Log(新的日志条目(LoggingEventType.Information,message));
}
公共静态无效日志(此ILogger记录器,异常示例)
{
logger.Log(
新的日志条目(LoggingEventType.Error、exception.Message、ex));
}
//这里有更多的方法。
}
由于接口只包含一个方法,因此创建一个ILogger
实现变得很容易,该实现可以、、NLog或任何其他日志库,并将DI容器配置为将其注入到构造函数中包含ILogger
的类中
将静态扩展方法放在带有单个方法的接口之上与具有多个成员的接口截然不同。扩展方法只是创建LogEntry
消息并通过ILogger
界面上唯一的方法传递消息的助手方法。这些扩展方法本身不包含易失性行为,因此不会妨碍可测试性。如果您愿意,您可以轻松地测试它们,它们将成为消费者代码的一部分;不是抽象的一部分
这不仅允许扩展方法在不需要更改抽象的情况下发展,而且当使用记录器抽象时,扩展方法和LogEntry
构造函数始终被执行,即使记录器被存根/模拟。这使得在测试套件中运行时对记录器的调用的正确性更加确定。我已经多次用这个攻击自己,在单元测试期间,我对所使用的第三方记录器抽象的调用成功了,但在生产中执行时仍然失败
单成员接口也使测试更加容易;拥有一个包含许多成员的抽象会使创建实现(如模拟、适配器和装饰器)变得困难
当您这样做时,几乎不需要日志facades(或任何其他库)可能提供的一些静态抽象。通常我更喜欢创建一个类似
public interface ILogger
{
void LogInformation(string msg);
void LogError(string error);
}
在运行时,我注入了一个从这个接口实现的具体类。我使用了这个接口的小型接口包装器+适配器,它也是:
这个问题的一个很好的解决方案是以项目的形式出现的 LibLog是一个日志抽象,内置支持主要的日志记录器,包括Serilog、NLog、Log4net和enterpriselogger。它通过NuGet软件包管理器作为源(.cs)文件而不是.dll引用安装到目标库中。这种方法允许在不强制库承担外部依赖的情况下包含日志抽象。它还允许库作者包含日志记录,而无需强制消费应用程序向库显式提供记录器。LibLog使用反射来确定正在使用的具体记录器,并在库项目中不使用任何显式连接代码的情况下将其连接起来
因此,LibLog是在库项目中进行日志记录的一个很好的解决方案。只需在主应用程序或服务中引用并配置一个具体的记录器(Serilog for the win),然后将LibLog添加到库中 自2015年以来,如果您正在构建.NET核心应用程序,也可以使用 NLog要挂接的包是:
- 对于ASP.NET核心用户
- 对于.NET核心用户,例如控制台项目
定义自己的接口,如在简单案例中所解释的那样好,但是它忽略了一些我认为重要的事情:
- 结构化日志记录和反结构化对象(@notati
PM> Install-Package NLog.Interface