NLog 写入 .Net Core 3.1 中的多个日志

NLog write to multiple logs in .Net Core 3.1

我必须编写一个文件实用程序来读取导入文件和创建导出文件。我希望写入不同的 NLog 文件,具体取决于我是在处理导入文件还是创建导出文件。我今天一直在搜索和阅读不同的文章,但我要么没有搜索正确的东西,要么我只是不了解如何使用依赖注入写入不同的日志文件。

这是我正在尝试解决的基本概念。我 运行 一个控制台应用程序,它使用 JSON 文件读取文件设置列表。该文件 setting/config JSON 文件将有一个设置让我知道这是出站文件还是入站文件。因此,假设我正在使用的当前文件是一个出站文件,我会将它的日志记录写入我的 OutboundFiles.log 而不是我的 InboundFiles.log.

目前,我将以下内容与我创建的大多数 .Net Core 控制台应用程序一起使用,它将使用 _log(例如:_log.LogInformation)将其写入单个日志文件。我不明白的是我怎么能说出 _logOutbound.LogInformation 和 _logInbound.LogInformation 我会根据我正在使用的文件时间以及我将如何改变我的 NLog.config 文件用于不同的日志名称和目录。这是我当前用于写入单个文件的代码。

Program.cs

public class Program
    {
        static void Main(string[] args)
        {
            var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();

            try
            {
                logger.Debug("Initializing Program.Main");

                var host = Host.CreateDefaultBuilder()
                    .ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        config.SetBasePath(Path.Combine(AppContext.BaseDirectory));
                        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    })
                    .ConfigureServices((context, services) =>
                    {
                        services.AddTransient<IAppHost, AppHost>();

                        services.AddLogging(builder =>
                        {
                            builder.AddNLog("nlog.config");
                        });
                    }).Build();

                var application = ActivatorUtilities.CreateInstance<AppHost>(host.Services);
                application.Run();
            }
            catch (Exception ex)
            {
                logger.Error("Stopped program setup with Error. {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
                throw;
            }
            finally
            {
                // Ensure to flush and stop internal timers/threads before application-exit
                NLog.LogManager.Shutdown();
            }
        }
    }

NLog.config

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

  <!-- enable asp.net core layout renderers -->
  <extensions>
    <add assembly="NLog.Web.AspNetCore"/>
  </extensions>

  <variable name="LogDirectory" value="D:\logs\ApplictionName"/>

  <!-- the targets to write to -->
  <targets>
    
    <target xsi:type="File" 
      name="DefaultTarget" 
      fileName="${LogDirectory}\LogFile.log"
      layout="${longdate} | ${callsite} | ${message}"
      archiveAboveSize="3145728"  
      archiveEvery="Day"
      archiveFileName = "${LogDirectory}/Archive/{#}.log"  
      archiveNumbering = "DateAndSequence"            
      archiveDateFormat = "yyyyMMdd"  
      maxArchiveFiles = "21"            
    />

    <target name="ConsoleTarget"
      xsi:type="Console"
      layout="${longdate} ${logger:shortName=True} ${message} ${onexception:EXCEPTION OCCURRED\:${exception:format=type,message,StackTrace,method:maxInnerExceptionLevel=8:innerFormat=type,message,StackTrace,method}}"
    />
    
  </targets>  
  <rules>
    <logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
    <logger name="*" minlevel="Debug" writeTo="DefaultTarget,ConsoleTarget" />
  </rules>
</nlog>

AppHost.cs

public class AppHost : IAppHost
    {
        private readonly ILogger<AppHost> _log;
        private readonly IConfiguration _configuration;

        public AppHost(ILogger<AppHost> log, IConfiguration config)
        {
            _log = log;
            _configuration = config;
        }

        public void Run()
        {
            _log.LogInformation("Application START");

            try
            {
                //***  All code goes here  ***

            }
            catch (Exception ex)
            {
                _log.LogError("Error: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
            }

            _log.LogInformation("Application END");
        }
    }

这是我将通读的 JSON 文件的一个基本示例。其中一个参数告诉我它将是一个出站文件,这是我将用来将任何日志记录写入 Outbound.log 文件的密钥。入站文件的工作方式相同。

"fileTypes": {
  "FileName1": 
{
  "dayofweek": "MON",
  "dayofmonth": "*",
  "time": "23:00",
  "inputFolder": "\servername\emft\inbound",
  "inputFileName": "FileName.pgp",
 "maxInputFiles": "1",
  "minInputFiles": "1",
  "inputDecryptionKey": "d:\PgpKeys\private\keyname.asc",
  "outputFolder": "\servername\emft\outbound",
  "outputFileName": "outfilename.txt.pgp",
 "outputEncryptionKey": "d:\PgpKeys\public\keyname.asc",      
 "logFileType": "outbound"
}
}

问题更新

如果我的 NLog.config 文件中有多个目标,如下例所示,我该如何告诉 .Net Core 我要定位哪个目标?

例如,使用下面的目标,我如何告诉依赖注入我想创建一个名为 _logOutgoing 的对象以使用“OutgoingTarget”目标,_logIncoming 对象以“IncomingTarget”目标为目标,然后_log 使用“DefaultTarget”?然后,当我在我的控制台应用程序中工作时,如果我正在处理一个传入文件,我会在 _logIncoming 和 _logOutgoing 中写一些东西,如果我正在处理我的传出文件?

我找这样的东西的原因是为了做一份临时报告。 OutgoingTarget 和 IncomingTarget 将用于编写更多非技术报告,我将通过电子邮件将其发送给业务经理,以便他们知道发生了什么,而我将使用 DefaultTarget 供开发人员使用,并提供更多技术细节debugging/support 个原因。

这是我在研究中发现的一个例子。

<target xsi:type="File" name="DefaultTarget" fileName="C:/AVDS/Logs/MyApps/nlog-all-${shortdate}.log"
            layout="${longdate}|${uppercase:${level}}|${aspnet-traceidentifier}|${aspnet-user-identity}|${logger}|${aspnet-request-url}|${aspnet-mvc-action}|${message} ${exception:format=ToString}"
            archiveFileName="C:/AVDS/Logs/MyApps/archives/nlog-all.{#}.txt"
            archiveEvery="Day"
            archiveNumbering="Rolling"
            maxArchiveFiles="7" />

    <target xsi:type="File" name="OutgoingTarget" fileName="C:/AVDS/Logs/MyApps/nlog-own-${shortdate}.log"
            layout="${longdate}|${uppercase:${level}}|${aspnet-traceidentifier}|${aspnet-user-identity}|${logger}|${aspnet-request-url}|${aspnet-mvc-action}|${message} ${exception:format=ToString}"
            archiveFileName="C:/AVDS/Logs/MyApps/archives/nlog-own.{#}.txt"
            archiveEvery="Day"
            archiveNumbering="Rolling"
            maxArchiveFiles="7" />

    <target xsi:type="File" name="IncomingTarget" fileName="C:/AVDS/Logs/MyApps/nlog-errors-${shortdate}.log"
            layout="${longdate}|${uppercase:${level}}|${aspnet-traceidentifier}|${aspnet-user-identity}|${logger}|${aspnet-request-url}|${aspnet-mvc-action}|${message} ${exception:format=ToString}"
            archiveFileName="C:/AVDS/Logs/MyApps/archives/nlog-errors.{#}.txt"
            archiveEvery="Day"
            archiveNumbering="Rolling"
            maxArchiveFiles="7" />

修复尝试

我一定是漏了什么。我根据下面的示例添加了以下内容,但是 _logIncoming.LogInformation("Testing") 出现错误,提示“ILoggerFactory 不包含 LogInformation 的定义”。我仍然是依赖注入的新手,但我想知道是否需要在 Program.cs 文件中向我的 .ConfigureServices 添加一些内容?

已更新Apphost.cs

public class AppHost : IAppHost
    {
        private readonly ILogger<AppHost> _log;
        private readonly IConfiguration _configuration;

        private readonly ILoggerFactory _logIncoming;
        private readonly ILoggerFactory _logOutgoing;

        public AppHost(ILogger<AppHost> log, ILoggerFactory loggerFactory, IConfiguration config)
        {
            _log = log;
            _logIncoming = (ILoggerFactory)loggerFactory.CreateLogger("IncomingLogger");
            _logOutgoing = (ILoggerFactory)loggerFactory.CreateLogger("OutgoingLogger");
            _configuration = config;
        }

        public void Run()
        {
            _log.LogInformation("Application START");

            _logIncoming.LogInformation("Testing Incoming log.");
            _logOutgoing.LogInformation("Testing outgoing  log.");
}
}

Program.cs

var host = Host.CreateDefaultBuilder()
                    .ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        config.SetBasePath(Path.Combine(AppContext.BaseDirectory));
                        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    })
                    .ConfigureServices((context, services) =>
                    {
                        services.AddTransient<IAppHost, AppHost>();

                        services.AddLogging(builder =>
                        {
                            builder.AddNLog("nlog.config");
                        });
                    }).Build();

不确定我是否理解特定 import/export-files 应该如何影响 NLog 输出。所以我只是在这里随机猜测:

我可能会使用 ILogger.BeginScope 然后使用 NLog ${mdlc}.

// You can inject several properties into the scope, or use Dictionary<string, object> instead of array
using (logger.BeginScope(new [] { new KeyValuePair<string, object>("ProcessFile", logFileName) }))
{
     logger.LogInformation("Processing File ...");
}

然后在 NLog.config 中做这样的事情:

<nlog>
  <variable name="LogDirectory" value="D:/logs/ApplictionName"/>
  <variable name="LogProcessFile" value="${mdlc:ProcessFile:whenEmpty=LogFile}"/>

  <targets>
    <target xsi:type="File" 
      name="DefaultTarget" 
      fileName="${LogDirectory}/${LogProcessFile}.log"
      layout="${longdate}|${message}" />
  </targets>  

  <rules>
    <logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
    <logger name="*" minlevel="Debug" writeTo="DefaultTarget" />
  </rules>
</nlog>

然后 ILogger.BeginScope 内发生的所有日志记录都将转到专用文件。您可以让多个线程在各自的 ILogger.BeginScope.

中同时处理

另请参阅:https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-properties-with-Microsoft-Extension-Logging

如果您想将输出重定向到 3 个不同的文件,那么您可以这样做:

public class AppHost : IAppHost
{
    private readonly ILogger _log;
    private readonly IConfiguration _configuration;
    private readonly ILogger _logIncoming;
    private readonly ILogger _logOutgoing;

    public AppHost(ILoggerFactory loggerFactory, IConfiguration config)
    {
        _log = loggerFactory.CreateLogger(typeof(AppHost).ToString());
        _logIncoming = loggerFactory.CreateLogger("IncomingLogger");
        _logOutgoing = loggerFactory.CreateLogger("OutgoingLogger");
        _configuration = config;
    }


    public void Run()
    {
        _log.LogInformation("Application START");
        _logIncoming.LogInformation("IncomingTarget START");
        _logOutgoing.LogInformation("OutgoingTarget START");
    }
}

然后您可以将 Logger-name 映射到输出目标:

<nlog>
  <variable name="LogDirectory" value="D:/logs/ApplictionName"/>
  <variable name="LogProcessFile" value="${mdlc:ProcessFile:whenEmpty=LogFile}"/>

  <targets>
    <target xsi:type="File" 
      name="DefaultTarget" 
      fileName="${LogDirectory}/AppLog.log"
      layout="${longdate}|${message}" />
    <target xsi:type="IncomingTarget" 
      name="DefaultTarget" 
      fileName="${LogDirectory}/IncomingTarget.log"
      layout="${longdate}|${message}" />
    <target xsi:type="File" 
      name="OutgoingTarget" 
      fileName="${LogDirectory}/OutgoingTarget.log"
      layout="${longdate}|${message}" />
  </targets>  

  <rules>
    <logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
    <logger name="IncomingLogger" minlevel="Debug" writeTo="IncomingTarget" final="true" />
    <logger name="OutgoingLogger" minlevel="Debug" writeTo="OutgoingTarget" final="true" />
    <logger name="*" minlevel="Debug" writeTo="DefaultTarget" />
  </rules>
</nlog>

另请参阅:https://github.com/nlog/nlog/wiki/Configuration-file#rules