如何使用 nlog 为每个线程创建单独的日志文件

How to create separate log files per thread using nlog

我有一个简单的 ASP.NET 应用程序,我想为每个请求创建单独的日志文件。该应用程序创建了日志文件,但我从日志文件中的其他线程获得了信息。我创建了一个 nlog.config 文件,我希望所有线程都使用它 file.Here 是配置文件的内容

<?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"
      internalLogLevel="Info">

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

    <!-- the targets to write to -->
    <targets async="true">
        <!-- write logs to file  -->
        <target
            xsi:type="File"
            name="allfile"
            fileName="c:/temp/nlog-Navigator-all-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|TraceIdentifier: ${aspnet-TraceIdentifier}|SessionId: ${aspnet-sessionid}|${message} ${exception:format=tostring}" />
        <target
            xsi:type="Console"
            name="detailConsole"
            layout="${level:truncate=4:lowercase=true}: ${aspnet-sessionid} - ${logger}[0] ${newline}      ${message}${exception:format=tostring}" />
    </targets>

    <!-- rules to map from logger name to target -->
    <rules>
        <!--All logs, including from Microsoft-->
        <logger name="*" minlevel="Trace" writeTo="allfile" />
        <logger name="*" minlevel="Trace" writeTo="detailConsole" />
    </rules>
</nlog>

我使用邮递员向应用程序发送多个请求。请求正文如下所示

{
    "fileName": "testfileName1.txt"
}

我目前正在发送 4 个请求,创建的日志文件名是基于请求中的文件名。所以这意味着创建了 4 个名为 testfileName1.txt, testfileName2.txt, testfileName4.txt, testfileName4.txt 的日志文件。 这是我的控制器:

        [HttpPost]
        public async Task<IActionResult> Index([FromBody] JsonElement requestElement)
        {
            try
            {
                var myJsonString = JObject.Parse(requestElement.GetRawText());
                var fileName = myJsonString["fileName"].ToString();

                using (this._logger.BeginScope(fileName))
                {
                    for (int i = 0; i < 10; i++)
                    {
                        await this.StartJobLogger(fileName);

                        this._logger.LogInformation($"File: {fileName}");
                        await Task.Delay(1000);
                    }

                    return this.Ok("done");
                }
            }
            catch (Exception e)
            {
                throw;
            }
            finally
            {
            }
        }

        #region Private Methods

        private Task StartJobLogger( string fileName)
        {
            var target = new FileTarget();
            target.Name = fileName;
            target.FileName = $"c:\temp\{Path.GetFileNameWithoutExtension(fileName)}.log";
            target.Layout = "${longdate} ${threadid} ${callsite} ${level} ${message}";

            var config = LogManager.Configuration;
            config.AddTarget("testName", target);
            var rule = new LoggingRule("*", NLog.LogLevel.Info, target);
            
            config.LoggingRules.Add(rule);

            LogManager.Configuration = config;

            LogManager.GetLogger(fileName);

            return Task.CompletedTask;
        }

但是,第一个日志文件中正在写入以下内容。

2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:20.0592 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.0805 12 MultiThreadLogging.Controllers.HomeController+<Index>d__2.MoveNext Info File: testfileName1.txt
2022-01-03 10:34:21.6422 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName2.txt
2022-01-03 10:34:21.6422 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName2.txt
2022-01-03 10:34:21.6422 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName2.txt
2022-01-03 10:34:21.6422 12 MultiThreadLogging.Controllers.HomeController.Index Info File: testfileName2.txt

我只想将与第一个请求相关的信息记录在第一个日志文件中,将与第二个请求相关的信息记录在第二个文件中,依此类推。但这目前会创建包含混合信息的文件。

尝试这样做(使用 BeginScope 将 ScopeFileName-属性 注入 NLog MDLC):

[HttpPost]
public async Task<IActionResult> Index([FromBody] JsonElement requestElement)
{
    try
    {
        var myJsonString = JObject.Parse(requestElement.GetRawText());
        var fileName = myJsonString["fileName"].ToString();

        // Pushing input-filename as scope-property, accessible from MDLC
        using (this._logger.BeginScope(new [] { new KeyValuePair<string, object>("ScopeFileName", fileName) }))
        {
            for (int i = 0; i < 10; i++)
            {
                // REMOVED AS BROKEN -> await this.StartJobLogger(fileName);

                this._logger.LogInformation($"File: {fileName}");
                await Task.Delay(1000);
            }

            return this.Ok("done");
        }
    }
    catch (Exception e)
    {
        throw;
    }
    finally
    {
    }
}

但请注意,获取用户输入并用作文件名可以用作攻击向量。

<?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"
      internalLogLevel="Info">

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

    <variable name="ScopeFileName" value="${mdlc:ScopeFileName:whenEmpty=Navigator}" />

    <!-- the targets to write to -->
    <targets async="true">
        <!-- write logs to file  -->
        <target
            xsi:type="File"
            name="allfile"
            fileName="c:/temp/${ScopeFileName}-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|TraceIdentifier: ${aspnet-TraceIdentifier}|SessionId: ${aspnet-sessionid}|${message} ${exception:format=tostring}" />
        <target
            xsi:type="Console"
            name="detailConsole"
            layout="${level:truncate=4:lowercase=true}: ${aspnet-sessionid} - ${logger}[0] ${newline}      ${message}${exception:format=tostring}" />
    </targets>

    <!-- rules to map from logger name to target -->
    <rules>
        <!--All logs, including from Microsoft-->
        <logger name="*" minlevel="Trace" writeTo="allfile" />
        <logger name="*" minlevel="Trace" writeTo="detailConsole" />
    </rules>
</nlog>

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