Elr*_*ynn 3 logging flush .net-core
Windows 上使用 LoggerFactory 的 .net 6 控制台应用程序 - 最终消息不会出现在控制台上。loggerFactory.Dispose() 没有帮助。Ilogger 没有 Dispose() 方法。
这是一个复制品。大约会出现 20 到 70 条循环消息。之后就什么都没有了。
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("MyTestApp.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
try
{
logger.LogInformation("Starting");
for (var i=0; i < 100; i++)
{
logger.LogInformation($"This is a nice long message for {i}.");
}
throw new Exception("boom");
}
catch (Exception e)
{
logger.LogInformation(e.ToString());
}
finally
{
loggerFactory.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
这是由于在此提交(关联 PRMicrosoft.Extensions.Logging.Console\src\ConsoleLoggerProcessor.cs )中重构了方式。
调用logger.Log不必立即刷新消息。如果确实如此,调用可能会花费很长时间并且阻塞的时间比预期的要长。记录器将消息传递给ILoggers从您的ILoggerProviders 创建的所有内部进程,并根据这些消息执行他们将要执行的操作。根据您的情况配置 LoggerFactory 添加builder.AddConsole();。ConsoleLoggerProvider : ILoggerProvider
创建 后ILoggerFactory,所有配置的提供程序都会被实例化,此时会构造一个名为 的ConsoleLoggerProvider 新类ConsoleLoggerProcessor。它负责Console.Out从它创建的后台线程写入消息,以处理控制台记录器消息队列。记录器将消息推送到此队列,以便它们可以快速返回给调用者,而不会阻塞文件 IO。
当ILoggerFactory被处置时,它将处置所有创建的内容ILoggerProviders,从而导致处置ConsoleLoggerProcesser。处理该类会Thread.Join调用上面链接的消息队列处理线程。
以前,ConsoleLoggerProcessor的队列是通过BlockingCollection<T>. 这是一个极其简化的视图:
public class ConsoleLoggerProcessor : IDisposable
{
private readonly Thread _outputThread;
private readonly BlockingCollection<string> _messageQueue = new();
public ConsoleLoggerProcessor()
{
_outputThread = new Thread(ProcessLogQueue) { IsBackground = true };
_outputThread.Start();
}
public void EnqueueMessage(string message)
{ /* snip */ }
private void ProcessLogQueue()
{
foreach (var message in _messageQueue.GetConsumingEnumerable())
{
Console.WriteLine(message);
}
}
public void Dispose()
{
_messageQueue.CompleteAdding();
_outputThread.Join(millisecondsTimeout: 1500);
}
}
Run Code Online (Sandbox Code Playgroud)
处置后,BlockingCollection完成,这可以防止更多添加,但 直到两个条件都为真时_messageQueue.GetConsumingEnumerable()才会发生yield break;
这意味着在返回或达到毫秒超时_outputThread之前不会终止。ProcessLogQueue1500
将此与使用的新实现进行比较Queue<T>。再次极其简化以表达要点。
public class ConsoleLoggerProcessor : IDisposable
{
private readonly Thread _outputThread;
private readonly Queue<string> _messageQueue = new();
private bool _isAddingCompleted;
public ConsoleLoggerProcessor()
{
_outputThread = new Thread(ProcessLogQueue) { IsBackground = true };
_outputThread.Start();
}
public void EnqueueMessage(string message)
{ /* snip */ }
private void ProcessLogQueue()
{
while (_isAddingCompleted)
{
if (_messageQueue.Count > 0)
{
Console.WriteLine(_messageQueue.Dequeue());
}
}
}
public void Dispose()
{
_isAddingCompleted = true;
_outputThread.Join(millisecondsTimeout: 1500);
}
}
Run Code Online (Sandbox Code Playgroud)
当这个实现被处理时,标志_isAddingCompleted被设置为true,并且紧密循环ProcessLogQueue基本上立即终止。在实际实现中,存在一些同步障碍,因此ProcessLogQueue不会将核心固定在 100%。
所以归结起来就是:
以前的记录器最多需要 1.5 秒来刷新队列中剩余的内容。阻止应用程序退出最多 1.5 秒,因为Thread.Join会阻止调用线程(主线程)直到其终止。
当前的实现不会等待消息被刷新。它立即退出。
| 归档时间: |
|
| 查看次数: |
799 次 |
| 最近记录: |