为 ILogger 创建后台任务的最佳方法是什么

问题描述 投票:0回答:1

我创建了一个文件 ILogger 提供程序。它有一个后台任务来实际写入磁盘,因此

Log()
调用不会等待磁盘写入完成。

创建/管理此后台任务的最佳方式是什么?我可以把它放在

Task.Run()
中,然后我就忘记了。但这让我觉得有问题。

此外,永远不会调用

ILogger.Provider.Dispose()
。我希望处理该任务,以便它可以关闭已打开的文件。

而且,当调用 Dispose() 时,我需要结束

Task.Run()
内的循环。在这种情况下,只设置一个布尔值会更好吗?或者我应该使用 CancellationToken 吗?

c# .net-core task blazor-server-side cancellation-token
1个回答
1
投票

您想使用线程安全队列。记录器将日志消息放入队列中,一个或多个线程/任务从队列中选取消息并将其写入磁盘。 Dispose 应该使队列停止接受新消息,并等待写入任何已排队的消息。

有很多方法可以编写这样的队列,一个非常简单的替代方法是使用阻塞集合:

public class QueueExample<T> : IAsyncDisposable
{
    private readonly Task task;
    private readonly BlockingCollection<T> queue = new();

    public QueueExample() => task = Task.Run(DoProcessing);

    public void Add(T item) => queue.Add(item);

    private void DoProcessing()
    {
        foreach (var item in queue.GetConsumingEnumerable())
        {
            // do processing
        }
    }

    public async ValueTask DisposeAsync()
    {
        queue.CompleteAdding();
        await task;
    }
}

一旦调用

CompleteAdding
并且所有项目都已处理完毕,循环就会停止。

但我的建议是使用现有的日志框架。这将为您做这样的缓冲,以及在记录时有用的许多其他事情。

我对 nLog 很有经验,而且设置起来相当容易。添加 nuget 依赖项并将配置放入 app.config 文件中,这样的内容至少适用于 .net 框架:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
  </configSections>
  <nlog>
    <targets async="true">
      <target name="fileTarget"
              xsi:type="File"
              keepFileOpen ="true"
              openFileCacheTimeout ="30"
              fileName=".\Logs\Log-${date}.txt"/>
    </targets>

    <rules>
      <logger name="*" minlevel="Info" writeTo="fileTarget" />
    </rules>
  </nlog>
...

并像这样创建你的记录器

private static readonly Logger log = LogManager.GetCurrentClassLogger();
© www.soinside.com 2019 - 2024. All rights reserved.