C# 我应该服用伊洛格,伊洛格<;T>;,库的iLogger工厂或iLogger提供程序?
这可能在某种程度上与库设计相关,而与使用这些库的实际应用程序如何实现其日志记录无关 我正在编写一个.net标准2.0库,它将通过Nuget安装,为了让使用该库的人能够获得一些调试信息,我依赖于允许注入标准化的记录器 但是,我看到了多个接口,web上的示例代码有时使用C# 我应该服用伊洛格,伊洛格<;T>;,库的iLogger工厂或iLogger提供程序?,c#,.net,logging,.net-core,.net-standard,C#,.net,Logging,.net Core,.net Standard,这可能在某种程度上与库设计相关,而与使用这些库的实际应用程序如何实现其日志记录无关 我正在编写一个.net标准2.0库,它将通过Nuget安装,为了让使用该库的人能够获得一些调试信息,我依赖于允许注入标准化的记录器 但是,我看到了多个接口,web上的示例代码有时使用ILoggerFactory,并在类的ctor中创建一个记录器。还有ILoggerProvider,它看起来像工厂的只读版本,但是实现可能实现也可能不实现这两个接口,所以我不得不选择。(工厂似乎比供应商更常见) 我看到的一些代码使用非
ILoggerFactory
,并在类的ctor中创建一个记录器。还有ILoggerProvider
,它看起来像工厂的只读版本,但是实现可能实现也可能不实现这两个接口,所以我不得不选择。(工厂似乎比供应商更常见)
我看到的一些代码使用非泛型的ILogger
接口,甚至可能共享同一个记录器的一个实例,还有一些代码在其ctor中使用ILogger
,并期望DI容器支持开放泛型类型或显式注册库使用的每个ILogger
变体
现在,我确实认为ILogger
是正确的方法,而且可能是一个不接受该参数而只传递空记录器的ctor。这样,如果不需要日志记录,则不使用日志记录。然而,一些DI容器选择最大的ctor,因此无论如何都会失败
我很好奇我在这里应该做些什么来让用户头痛最少,同时如果需要的话仍然允许适当的日志记录支持。这些都是有效的,除了
iLogger Provider
ILogger
和ILogger
是您应该用来记录日志的。要获取ILogger
,请使用ILogger工厂
ILogger
是获取特定类别记录器的快捷方式(作为类别的类型的快捷方式)
当您使用ILogger
执行日志记录时,每个注册的ILogger提供者都有机会处理该日志消息。直接调用ILogger提供程序
对于使用代码来说是无效的。ILogger
实际上是为DI制作的。ILogger的出现是为了帮助更容易地实现工厂模式,而不是您自己编写所有DI和工厂逻辑,这是ASP.NET Core中最明智的决策之一
您可以选择:
ILogger
如果需要在代码中使用工厂模式和DI模式或可以使用ILogger
,实现简单的日志记录,而不需要DI
鉴于此,ILoggerProvider
只是处理每个已注册日志消息的桥梁。没有必要使用它,因为它不会影响您应该干预代码的任何内容。它侦听已注册的iLogger提供程序
,并处理消息。仅此而已。定义
我们有3个接口:ILogger
、ILoggerProvider
和ILoggerFactory
。让我们看看他们的职责:
ILogger:负责编写给定日志级别的日志消息
ILoggerProvider:负责创建ILogger
的实例(不应直接使用ILoggerProvider
创建记录器)
ILogger工厂:您可以向工厂注册一个或多个ILogger提供程序
s,然后工厂使用所有这些提供程序来创建ILogger
的实例iLogger工厂
保存一组iLogger提供程序
在下面的示例中,我们向工厂注册了2个提供程序(控制台和文件)。创建记录器时,工厂使用这两个提供程序来创建记录器的实例
:
ILoggerFactory factory = new LoggerFactory().AddConsole(); // add console provider
factory.AddProvider(new LoggerFileProvider("c:\\log.txt")); // add file provider
Logger logger = factory.CreateLogger(); // <-- creates a console logger and a file logger
创建类别为TodoApi.Controllers.TodoController的记录器
2。注入通用的ILogger
:
public TodoController(ITodoRepository todoRepository, ILoggerFactory logger)
{
_todoRepository = todoRepository;
_logger = logger.CreateLogger("TodoApi.Controllers.TodoController");
}
public TodoController(ITodoRepository todoRepository, ILogger<TodoController> logger)
{
_todoRepository = todoRepository;
_logger = logger;
}
public TodoController(ITodoRepository todoRepository,ILogger记录器)
{
_todoRepository=todoRepository;
_记录器=记录器;
}
创建类别为TodoController的完全限定类型名称的记录器
在我看来,让文档混淆的是它没有提到任何关于注入非泛型,
ILogger
。在上面的同一个例子中,我们正在注入一个非泛型的ITodoRepository
,但它并没有解释为什么我们对ILogger
不这样做
根据:
注入构造函数只应接收
依赖关系
将工厂注入控制器不是一个好方法,因为初始化记录器不是控制器的责任(违反SRP)。同时,注入通用的ILogger
会增加不必要的噪音。有关更多详细信息,请参阅Simple Injector的博客:
应该注入的(至少根据上面的文章)是一个非通用的ILogger
,但是,这不是微软内置的DI容器可以做到的,您需要使用第三方DI库。文档解释了如何将第三方库与.NET Core一起使用
这是尼古拉·马洛维奇(Nikola Malovic)的作品,他在其中解释了国际奥委会的5条法律 国际奥委会尼古拉第四定律 正在解析的类的每个构造函数都不应该有 实现而不是接受一组自己的依赖项
对于图书馆设计,好的方法是:
class-MyClass
{
私人只读iLogger工厂(loggerFactory);
public MyClass():此(N)
loggerFactory.CreateLogger("MyLibrary");
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"MyLibrary": "None"
}
}
}
services.AddTransient(s => s.GetRequiredService<ILoggerFactory>().CreateLogger(""));