首页 > 解决方案 > NLog 写入 .Net Core 3.1 中的多个日志

问题描述

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

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

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

程序.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>

应用主机.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 供开发人员使用,并提供更多技术细节出于调试/支持原因发生了什么。

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

<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.");
}
}

程序.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();

标签: c#asp.net-corenlog

解决方案


不确定我是否理解特定的导入/导出文件应该如何影响 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


推荐阅读