NLog 多个记录器在同一 class
NLog multiple loggers in same class
我有一个 class 应该像往常一样记录,但有时它应该记录到特定目标(例如文件)。
这是我的 NLog 配置文件:
nlog.config
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
和extra.config
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\extra.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="extra" />
</rules>
</nlog>
我正在尝试这样的事情:
public class Program
{
private static IConfiguration _configuration;
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("init main");
var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production";
_configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile($"appsettings.{environment}.json", true)
.Build();
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureLogging(logBuilder =>
{
logBuilder.ClearProviders();
logBuilder.SetMinimumLevel(LogLevel.Trace);
})
.ConfigureServices((hostContext, services) =>
{
//serviceConfig
})
.UseNLog()
.UseWindowsService();
}
还有 class 我想要两个记录器:
public class MyClass
{
private readonly ILogger<MyClass> _logger;
private readonly Logger _extraLogger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
_extraLogger = NLogBuilder.ConfigureNLog("extra.config").GetLogger("extra");
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.Info(msg);
_logger.LogInformation("Message sendt");
}
}
但这使得应用程序(甚至其他 classes)完成的所有日志记录最终都在 extra.config 定义的 extra.log
文件中。例如。 msg
和 "Message sendt"
都在该文件中。
我想要的是拥有
"Message sendt"
在 logfile.log
msg
在 extra.log
这有可能吗?
为什么要在同一个 class 上使用两个日志?如果你的 class 上有一个你想单独记录的子组件,那么没关系,你所需要的只是一个合适的配置文件......但是,通常情况下,这将是一种代码味道。
你可以用一个配置做所有你想做的事:
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="extra" minlevel="Trace" writeTo="extra" final="true" />
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
注意“extra”日志规则中的“final”属性。它会阻止将额外的日志写入其他日志。
无需使用不同的配置创建此记录器。只需按照以下步骤操作:
public class MyClass
{
private readonly ILogger<MyClass> _logger;
private readonly Logger _extraLogger = LogManager.GetLogger("extra");
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.Info(msg);
_logger.LogInformation("Message sendt");
}
}
但我认为您应该重新考虑是否真的需要两个记录器来处理同一个 class。
更新
根据您的需要,您可以通过使用开箱即用的 NLog 功能并遵循更 nlogish 的模式来大大简化您的代码。配置文件几乎相同,只是将“额外”记录器的规则更改为“syslog”,因为我们将在代码中更改它的名称:
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<!-- This will probably be a network target -->
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="syslog" minlevel="Trace" writeTo="extra" final="true" />
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
我们将把“syslog”记录器放在 helper static 中的静态变量中 class:
public static class CommonLoggers
{
public static Logger SysLogger { get; private set; } = LogManager.GetLogger("syslog");
// you can put other centralized loggers here if you want
}
那么您应该将 class 代码简单地更改为:
public class MyClass
{
// the "correct" pattern is to use a logger that follows the class name
// put this in each class you create
private static Logger logger = LogManager.GetCurrentClassLogger();
// nothing to do on the constructor (can be removed as it's redundant)
public MyClass() { }
public void doBothTypesOfLogging() {
var msg = "Hello";
CommonLoggers.SysLogger.Info(msg);
logger.Info("Message sent");
}
}
重要的部分是了解 NLog 规则用于过滤给定记录器名称的输出,您可以这样做,例如:
<rules>
<logger name="SomeNamespace.Somewhere.*" minlevel="Trace" writeTo="extra" final="true"/>
<logger name="SomeNamespace.SomewhereElse.MyClass" minlevel="Info" writeTo="some_other_target" />
<logger name="*" minlevel="error" writeTo="logfile" />
<logger name="*" minlevel="info" writeTo="logconsole" />
</rules>
通过这种方式,您可以从“SomeNamespace.Somewhere].*”内的所有 classes 跟踪所有日志到“extra”目标。将“MyClass”的所有INFO日志写入“some_other_target”。将 ERROR 消息发送到“logfile”,将 INFO 消息发送到“logconsole”。
阅读有关规则、目标和过滤器的文档会对您有很大帮助!
这是一篇好文章:https://www.codeproject.com/Articles/4051307/NLog-Rules-and-filters
官方文档:https://github.com/nlog/nlog/wiki/Configuration-file#rules
还有这个精彩的 SO 问题:Most useful NLog configurations
阅读愉快!
与其直接使用 NLog LogManager,我建议您留在 ILogger 路径上,但像这样调用 ILoggerFactory:
public class MyClass
{
private readonly ILogger _logger;
private readonly ILogger _extraLogger;
public MyClass(ILoggerFactory logfactory)
{
_logger = logfactory.CreateLogger(GetType().ToString());
_extraLogger = logfactory.CreateLogger("extra");
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.LogInformation(msg);
_logger.LogInformation("Message sendt");
}
}
但我同意接受的答案,即应该使用单个 NLog.config
。
我有一个 class 应该像往常一样记录,但有时它应该记录到特定目标(例如文件)。
这是我的 NLog 配置文件:
nlog.config
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
和extra.config
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\extra.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="extra" />
</rules>
</nlog>
我正在尝试这样的事情:
public class Program
{
private static IConfiguration _configuration;
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("init main");
var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production";
_configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile($"appsettings.{environment}.json", true)
.Build();
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureLogging(logBuilder =>
{
logBuilder.ClearProviders();
logBuilder.SetMinimumLevel(LogLevel.Trace);
})
.ConfigureServices((hostContext, services) =>
{
//serviceConfig
})
.UseNLog()
.UseWindowsService();
}
还有 class 我想要两个记录器:
public class MyClass
{
private readonly ILogger<MyClass> _logger;
private readonly Logger _extraLogger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
_extraLogger = NLogBuilder.ConfigureNLog("extra.config").GetLogger("extra");
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.Info(msg);
_logger.LogInformation("Message sendt");
}
}
但这使得应用程序(甚至其他 classes)完成的所有日志记录最终都在 extra.config 定义的 extra.log
文件中。例如。 msg
和 "Message sendt"
都在该文件中。
我想要的是拥有
"Message sendt"
在 logfile.log
msg
在 extra.log
这有可能吗?
为什么要在同一个 class 上使用两个日志?如果你的 class 上有一个你想单独记录的子组件,那么没关系,你所需要的只是一个合适的配置文件......但是,通常情况下,这将是一种代码味道。
你可以用一个配置做所有你想做的事:
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="extra" minlevel="Trace" writeTo="extra" final="true" />
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
注意“extra”日志规则中的“final”属性。它会阻止将额外的日志写入其他日志。
无需使用不同的配置创建此记录器。只需按照以下步骤操作:
public class MyClass
{
private readonly ILogger<MyClass> _logger;
private readonly Logger _extraLogger = LogManager.GetLogger("extra");
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.Info(msg);
_logger.LogInformation("Message sendt");
}
}
但我认为您应该重新考虑是否真的需要两个记录器来处理同一个 class。
更新
根据您的需要,您可以通过使用开箱即用的 NLog 功能并遵循更 nlogish 的模式来大大简化您的代码。配置文件几乎相同,只是将“额外”记录器的规则更改为“syslog”,因为我们将在代码中更改它的名称:
<?xml version="1.0" encoding="utf-8" ?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="C:\Logs\logfile.log"
internalLogLevel="Info" >
<targets>
<target xsi:type="File" name="logfile" fileName="C:\Logs\logfile.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<target xsi:type="Console" name="logconsole"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
<!-- This will probably be a network target -->
<target xsi:type="File" name="extra" fileName="C:\Logs\extra.log"
layout="${longdate}|${level}|${message} |${all-event-properties} ${exception:format=tostring}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="syslog" minlevel="Trace" writeTo="extra" final="true" />
<logger name="*" minlevel="Trace" writeTo="logfile,logconsole" />
</rules>
</nlog>
我们将把“syslog”记录器放在 helper static 中的静态变量中 class:
public static class CommonLoggers
{
public static Logger SysLogger { get; private set; } = LogManager.GetLogger("syslog");
// you can put other centralized loggers here if you want
}
那么您应该将 class 代码简单地更改为:
public class MyClass
{
// the "correct" pattern is to use a logger that follows the class name
// put this in each class you create
private static Logger logger = LogManager.GetCurrentClassLogger();
// nothing to do on the constructor (can be removed as it's redundant)
public MyClass() { }
public void doBothTypesOfLogging() {
var msg = "Hello";
CommonLoggers.SysLogger.Info(msg);
logger.Info("Message sent");
}
}
重要的部分是了解 NLog 规则用于过滤给定记录器名称的输出,您可以这样做,例如:
<rules>
<logger name="SomeNamespace.Somewhere.*" minlevel="Trace" writeTo="extra" final="true"/>
<logger name="SomeNamespace.SomewhereElse.MyClass" minlevel="Info" writeTo="some_other_target" />
<logger name="*" minlevel="error" writeTo="logfile" />
<logger name="*" minlevel="info" writeTo="logconsole" />
</rules>
通过这种方式,您可以从“SomeNamespace.Somewhere].*”内的所有 classes 跟踪所有日志到“extra”目标。将“MyClass”的所有INFO日志写入“some_other_target”。将 ERROR 消息发送到“logfile”,将 INFO 消息发送到“logconsole”。
阅读有关规则、目标和过滤器的文档会对您有很大帮助!
这是一篇好文章:https://www.codeproject.com/Articles/4051307/NLog-Rules-and-filters
官方文档:https://github.com/nlog/nlog/wiki/Configuration-file#rules
还有这个精彩的 SO 问题:Most useful NLog configurations
阅读愉快!
与其直接使用 NLog LogManager,我建议您留在 ILogger 路径上,但像这样调用 ILoggerFactory:
public class MyClass
{
private readonly ILogger _logger;
private readonly ILogger _extraLogger;
public MyClass(ILoggerFactory logfactory)
{
_logger = logfactory.CreateLogger(GetType().ToString());
_extraLogger = logfactory.CreateLogger("extra");
}
public void doBothTypesOfLogging()
{
var msg = "Hello";
_extraLogger.LogInformation(msg);
_logger.LogInformation("Message sendt");
}
}
但我同意接受的答案,即应该使用单个 NLog.config
。