繁体   English   中英

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>

和额外的.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");
    }
}

但这使得应用程序(甚至其他类)完成的所有日志记录最终都在由 extra.config 定义的extra.log文件中。 例如。 msg"Message sendt"都以该文件结尾。

我想要的是拥有

logfile.log中的"Message sendt"

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 的模式来大大简化您的代码。 配置文件几乎相同,只是将“extra”记录器的规则更改为“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”记录器放在一个帮助器 static class 中的 static 变量中:

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 规则用于过滤 output 给定记录器名称,您可以执行以下操作,例如:

  <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.*”中所有类的所有日志跟踪到“额外”目标。 将“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 问题: 最有用的 NLog 配置

快乐阅读!

而不是直接使用 NLog LogManager,那么我建议你留在 ILogger-path 上,但像这样调用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM