我有一个 .NET Core Web 应用程序,我正在尝试通过 NLog 添加日志记录。 在之前的项目中,我只是在每个类的顶部使用了类似以下内容:
private static Logger logger = LogManager.GetCurrentClassLogger();
我正在尝试尽可能在这个项目中遵循更多最佳实践。
我的问题是,如何注入一个具有要注入的类的完全限定名称的记录器?
在我的startup.cs文件中,到目前为止我有以下内容:
services.AddScoped<BLL.Logging.NLogLogger>();
目前,
NLogLogger
类通过GetCurrentClassLogger()
创建NLog Logger的实例,使用时只会将名称报告为“BLL.Logging.NLogLogger”,而不是记录器被注入的实际类进入。
简化问题并使其更通用: 如何传入 .NET Core 将要注入类的类的名称?
我考虑过类似下面的事情,但不知道如何实现它:
services.AddScoped<BLL.Logging.NLogLogger>(serviceProvider => new BLL.Logging.NLogLogger("class name here"));
使用 DI 指定
ILogger<T>
类型而不是 Logger
,其中 T
是使用记录器的类类型,因此 NLog 将了解该类。例如:
public class TodoController : Controller
{
private readonly ILogger _logger;
public TodoController(ILogger<TodoController> logger)
{
_logger = logger;
}
}
参考资料:
我想我已经找到了一个可以接受的解决方案,尽管不完全是我问问题的方式。
首先,我创建一个“LoggerFactory”,它有一个名为“GetLogger”的方法(它创建具体的 NLog Logger 并接受类名作为参数),然后我注入这个工厂而不是直接注入记录器。
记录器工厂:
public class LoggerFactory : ILoggerFactory
{
public ILogger GetLogger(string fullyQualifiedClassName)
{
return new NLogLogger(fullyQualifiedClassName);
}
}
NLogLogger:
public class NLogLogger : ILogger, INLogLogger
{
NLog.Logger mylogger;
public NLogLogger(string fullyQualifiedClassName)
{
mylogger = NLog.LogManager.GetLogger(fullyQualifiedClassName);
}
}
Startup.cs:
services.AddScoped<BLL.Logging.ILoggerFactory>();
在我的控制器类中,我有:
private BLL.Logging.ILogger logger;//my NLogLogger inherits this interface
public HomeController(BLL.Logging.ILoggerFactory loggerFactory)
{
logger = loggerFactory.GetLogger(this.GetType().FullName);
}
所以我现在有效地所做的,不是注入实际的 Logger 本身(@Steven 表示这不可能按照我尝试的方式实现),而是注入实用程序来创建一个实例包装 NLog 的记录器。
我仍然有责任在类中创建记录器,但至少我已经与底层日志框架(NLog)解耦。
如果您不想在控制器中依赖 NLog(因此您需要依赖 Microsoft 抽象):
在您的命令处理程序/控制器中
class MyHandler(ILoggerFactory loggerFactory)
{
public void Handler()
{
var logger = loggerFactory.GetLogger("myCustomLogger");
logger?.LogDebug("My log");
}
}
ILoggerFactory
using Microsoft.Extensions.Logging;
public interface ILoggerFactory
{
ILogger GetLogger(string name);
}
LoggerFactory
using NLog.Extensions.Logging;
public class LoggerFactory : ILoggerFactory
{
private readonly NLogLoggerProvider _nLogLoggerProvider = new();
public Microsoft.Extensions.Logging.ILogger GetLogger(string name)
{
return _nLogLoggerProvider.CreateLogger(name);
}
}
依赖注入
using var servicesProvider = new ServiceCollection()
.AddSingleton<ILoggerFactory, LoggerFactory>()
.BuildServiceProvider();
nlog.config
<rules>
<logger name="myCustomLogger" minlevel="Trace" writeTo="myCustomFile" final="true" /> <!-- final so that myCustomLogger only logs in this rule -->
<logger name="*" minlevel="Trace" writeTo="logfile" />
</rules>
<targets>
<target xsi:type="File" name="logfile" fileName="C:\MyApp\logs\log.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="File" name="myCustomFile" fileName="C:\MyApp\logs\lastHttpCall.log"
layout="${message}" replaceFileContentsOnEachWrite="true" />
</targets>