使用控制台记录器的控制台应用程序不会写入最终消息。轻松重现

2024-05-21

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();
}


这是由于方式Microsoft.Extensions.Logging.Console\src\ConsoleLoggerProcessor.cs被重构为这次提交 https://github.com/dotnet/runtime/commit/bb17fb55c96ed45a6323ded2b88f8b432694840d (相关公关 https://github.com/dotnet/runtime/pull/70186).

Calling logger.Log不必立即刷新消息。如果确实如此,调用可能会花费很长时间并且阻塞的时间比预期的要长。记录器将消息传递给所有内部ILoggers从你创建的ILoggerProvider并按照他们的意愿处理这些消息。配置 LoggerFactorybuilder.AddConsole(); adds ConsoleLoggerProvider : ILoggerProvider在你的情况下。

创建后ILoggerFactory,所有配置的提供程序都被实例化,此时ConsoleLoggerProvider 构造一个新类 https://github.com/dotnet/runtime/blob/9c818a3176c8505af9ac374ad3369c5832328013/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs#L58 called ConsoleLoggerProcessor。它负责将消息写入Console.Out from a 它创建的后台线程 https://github.com/dotnet/runtime/blob/9c818a3176c8505af9ac374ad3369c5832328013/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs#L71-L76处理控制台记录器消息队列。记录器将消息推送到此队列,以便它们可以快速返回给调用者,而不会阻塞文件 IO。

When ILoggerFactory被处置,它将处置所有创建的ILoggerProviders这导致处置ConsoleLoggerProcesser。处置that班级电话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);
    }
}

处置后,BlockingCollection已完成,可防止更多添加,but _messageQueue.GetConsumingEnumerable()才不是yield break; until both条件为真

  • 添加完成了吗?
  • 队列是否为空?

这意味着_outputThread不会终止,直到ProcessLogQueue返回或1500毫秒超时命中。

将此与新的实现进行比较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);
    }
}

当这个实现被处理时,标志_isAddingCompleted被设定为true和紧密的循环ProcessLogQueue基本上立即终止。在实际实现中,存在一些同步障碍,因此ProcessLogQueue未将核心固定为 100%。

所以归结起来就是:

以前的记录器最多需要 1.5 秒来刷新队列中剩余的内容。阻止您的应用程序退出最多 1.5 秒,因为Thread.Join阻塞调用线程(主线程)直到它终止。

当前的实现不会等待消息被刷新。它立即退出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用控制台记录器的控制台应用程序不会写入最终消息。轻松重现 的相关文章

随机推荐

  • DLL 中的 GUID (.Net)

    我在这方面不是很有经验 所以我有几个问题 首先 所有 Net 创建的 DLL 是否都有自己的 GUID 如果没有 我的问题是如何获得一个并将其与 DLL 关联 那么问题是 我如何获得该 dll 的 GUID 即 给定 DLL 路径 c so
  • iOS:如何获取设备当前语言设置?

    我的应用程序中的一些功能应该基于其运行设备的语言设置 我想获取实际的语言而不是某些国家 地区设置 例如 如果语言是英语 我不在乎它是美国 英国 澳大利亚等 我很熟悉NSLocale对象 但它似乎与Region Format设置而不是Lang
  • WebClient.DownloadDataAsync 冻结了我的 UI

    我在 Form 构造函数中的 InitializeComponent 之后有以下代码 using WebClient client new WebClient client DownloadDataCompleted new Downloa
  • 我的用例可以合并到单个查询中而不影响性能吗?

    我主要着眼于改善表现查询的内容以及是否能够解决单一查询对于我的用例之一 解释如下 涉及到2张表 Table 1 EMPLOYEE column1 column2 email1 email2 column5 column6 Table 2 E
  • 保留完整姓氏,在 pandas 列中获取名字的首字母(如果有的话,还有中间名)

    我有一个 pandas 数据框 其中有一列表示几位网球运动员的姓氏和姓名 如下所示 Player 0 Roddick Andy 1 Federer Roger 2 Tsonga Jo Wilfred 我想保留完整的姓氏并获取姓名的首字母和中
  • 如何使 WordPress 主题全宽?

    我尽了最大努力 但无法通过编辑 CSS 使以下主题全宽 屏幕 如果您能向我展示或给我有关此定制的提示 我将不胜感激 http demo mythemeshop com sociallyviral http demo mythemeshop
  • PC 相当于 Coda 吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 迭代带有小胡子的数组

    如何获取迭代中当前元素的引用 my array p what goes here p my array 我希望我只是忽略了显而易见的事情 根据规范的变更日志 https github com mustache spec blob maste
  • 使用 SQL 完全复制 postgres 表

    免责声明 这个问题和栈溢出问题类似here https stackoverflow com questions 198141 copy a table including indexes in postgres 但这些答案都不适用于我的问题
  • Apache Commons VFS - 无法解析文件

    VFS 方法无法处理此 URI jboss server temp dir local outgoing配置在jboss beans xml这是决心 C Download jboss eap 5 1 1 server default tmp
  • 使用 RxJava 限制吞吐量

    我现在遇到的情况很难解释 所以我会写一个更简单的版本来解释这个问题 我有一个Observable from 它发出一系列由ArrayList文件数量 所有这些文件都应上传到服务器 为此 我有一个函数可以完成这项工作并返回一个Observab
  • 限制 JPQL 中的结果数量

    如何限制从数据库检索结果的数量 select e from Entity e I need only 10 results for instance 您可以尝试像这样给出 10 个要显式获取的结果 entityManager createQ
  • 无法使用 Git 部署从多项目解决方案部署正确的网站到 Azure

    我有一个解决方案 它有一个 mvc 网站 WebApplication1 该网站依赖于解决方案中的另一个项目 WebAppCore 源代码托管在 Visual Studio Online 上的 git 中 我配置了持续集成 一切都构建得很好
  • 使用 SendKeys 向 IE 11 发送“@”特殊字符

    我正在尝试使用 Internet Explorer 11 中的 SendKeys 方法将特殊字符发送到文本框 尝试在其他浏览器中发送特殊字符时我没有遇到此问题 但 Internet Explorer 在尝试发送时发送完全不同的字符特殊字符
  • 检查 Python 中的可迭代对象中的所有元素的谓词是否计算为 true

    我很确定有一个常见的习语 但我无法通过谷歌搜索找到它 这是我想做的 用Java Applies the predicate to all elements of the iterable and returns true if all ev
  • EAR 和 WAR 类加载器

    我对 JBoss 类加载器很困惑 任何人都可以详细描述类加载器的工作原理吗 我只需要做一件事 如果 WAR 没有找到具有自己的类加载器的类 他会将搜索委托给其父类加载器 该父类加载器必须是 EAR 的 针对上述情况 我的申请需要进行哪些更改
  • 在 R 中显示变量的精确值

    gt x lt 1 00042589212565 gt x 1 1 000426 如果我想打印的确切值x 我该怎么办呢 抱歉 如果这是一个愚蠢的问题 我尝试在谷歌上搜索 R 和 精确 或 圆形 但我得到的只是有关如何舍入的文章 先感谢您 所
  • 为什么我的 @OneToMany 属性出现主键违规?

    我有一个实体 Entity public class Student GeneratedValue strategy GenerationType AUTO Id private long id OneToMany private Set
  • 删除 Django 1.7 中的应用程序(和关联的数据库表)

    是否可以使用 Django 1 7 迁移来完全删除 卸载应用程序及其所有跟踪 主要是其所有数据库表 如果没有 在 Django 1 7 中执行此操作的适当方法是什么 python manage py migrate
  • 使用控制台记录器的控制台应用程序不会写入最终消息。轻松重现

    Windows 上使用 LoggerFactory 的 net 6 控制台应用程序 最终消息不会出现在控制台上 loggerFactory Dispose 没有帮助 Ilogger 没有 Dispose 方法 这是一个复制品 大约会出现 2