前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改。 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基础结构,来生成结构化日志。

翻译: Andrew Lock   https://andrewlock.net/new-in-aspnetcore-3-structured-logging-for-startup-messages/

探索ASP.NET Core 3.0系列一:新的项目文件、Program.cs和generic host

探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs

探索 ASP.Net Core 3.0系列三:ASP.Net Core 3.0中的Service provider validation

探索ASP.Net Core 3.0系列四:在ASP.NET Core 3.0的应用中启动时运行异步任务

探索 ASP.Net Core 3.0系列五:引入IHostLifetime并弄清Generic Host启动交互

一、ASP.NET Core 2.x中恼人的非结构化日志

当您在ASP.NET Core 2.x中启动应用程序时,默认情况下,ASP.NET Core会将一些有关您的应用程序的信息输出到控制台,例如当前环境,内容根路径以及Kestrel正在监听的URL。:

这些消息由WebHostBuilder写入的,目的是为您提供了应用程序的便捷概述,但它直接写入控制台中。

这有两个主要缺点:

  • 这些有用的信息仅写入控制台,因此不会写入任何其他日志记录基础结构。
  • 写入控制台的消息是非结构化的,它们的格式将与写入控制台的任何其他日志不同。 他们甚至没有日志级别或源。

最后一点特别烦人,因为在Docker中运行时通常将结构化日志写入标准输出(控制台),然后让另一个进程读取这些日志并将其发送到中央位置(例如使用fluentd),这很常见。

幸运的是,在ASP.NET Core 2.1中,有一种方法可以使用环境变量禁用这些消息,如我在上一篇文章中所展示的。 唯一的缺点是消息被完全禁用,因此根本不会记录任何方便的信息,详细请参考这边文章:

https://andrewlock.net/suppressing-the-startup-and-shutdown-messages-in-asp-net-core/

幸运的是,ASP.NET Core 3.0中的微小变化为我们提供了两全其美的方法!

二、在ASP.NET Core 3.0中正确记录日志

如果使用dotnet run启动ASP.NET Core 3.0应用程序,您会注意到写入控制台的日志消息中的细微差别:

现在,使用结构化日志记录启动消息! 但是并不像使用Logger替代Console那样简单。 在ASP.NET Core 2.x中,由WebHost负责记录这些消息。 在ASP.NET Core 3.0中,这些消息由ConsoleLifetime记录,ConsoleLifetime是通用主机注册的默认IHostLifetime。

我在上一篇文章中描述了IhostLifetime(尤其是ConsoleLifetime)的作用,但总而言之,该类负责侦听控制台中的Ctrl + C按键,并启动关闭过程。

ConsoleLifetime还在其WaitForStartAsync()方法期间注册回调,这些回调在触发ApplicationLifetime.ApplicationStarted事件以及触发ApplicationLifetime.ApplicationStopping事件时调用:

public Task WaitForStartAsync(CancellationToken cancellationToken)
{
if (!Options.SuppressStatusMessages)
{
// Register the callbacks for ApplicationStarted
_applicationStartedRegistration = ApplicationLifetime.ApplicationStarted.Register(state =>
{
((ConsoleLifetime)state).OnApplicationStarted();
},
this); // Register the callbacks for ApplicationStopping
_applicationStoppingRegistration = ApplicationLifetime.ApplicationStopping.Register(state =>
{
((ConsoleLifetime)state).OnApplicationStopping();
},
this);
} // ... return Task.CompletedTask;
}

这些回调运行简单地写入日志记录基础结构的OnApplicationStarted()和OnApplicationStopping()方法(如下所示):

private void OnApplicationStarted()
{
Logger.LogInformation("Application started. Press Ctrl+C to shut down.");
Logger.LogInformation("Hosting environment: {envName}", Environment.EnvironmentName);
Logger.LogInformation("Content root path: {contentRoot}", Environment.ContentRootPath);
} private void OnApplicationStopping()
{
Logger.LogInformation("Application is shutting down...");
}

尽管确切的消息略有不同,但是System Lifetime和Windows ServiceLifetime实现使用相同的方法通过标准日志记录基础结构来写入日志文件。

三、使用ConsoleLifetime抑制启动消息

ConsoleLifetime创建的启动消息引起的一个令人惊讶的变化是,您将无法再按照我在上一篇文章中描述的方式隐藏消息。 设置ASPNETCORE_SUPPRESSSTATUSMESSAGES显然没有任何效果-无论是否设置了环境变量,消息都将继续记录!

正如我已经指出的那样,由于使用Microsoft.Extensions.Logging基础结构正确记录了消息,因此这现在并不是什么大问题。 但是,如果这些消息由于某种原因冒犯了您,并且您真的想摆脱它们,则可以在Startup.cs中配置ConsoleLifetimeOptions:

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// ... other configuration
services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
}
}

现在只显示结构化的日志信息了。

如果需要,您甚至可以根据ASPNETCORE_SUPPRESSSTATUSMESSAGES环境变量的存在来设置SuppressStatusMessages字段:

public class Startup
{
public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) => Configuration = configuration; public void ConfigureServices(IServiceCollection services)
{
// ... other configuration
services.Configure<ConsoleLifetimeOptions>(opts
=> opts.SuppressStatusMessages = Configuration["SuppressStatusMessages"] != null);
}
}

如果您确实选择不显示消息,请注意,Kestrel仍会记录其正在监听的URL;否则,您将保留其记录。 没有办法抑制这些:

info: Microsoft.Hosting.Lifetime[]
Now listening on: http://0.0.0.0:5000
info: Microsoft.Hosting.Lifetime[]
Now listening on: https://0.0.0.0:5001

四、总结

在本文中,我展示了如何在3.0中记录结构化日志,避免在ASP.NET Core 2.x应用程序启动时烦人的非结构化日志。 这样可以确保将日志写入所有已配置的记录器,并且在写入控制台时具有标准格式。 我在日志消息中描述了IhostLifetime的角色,并说明了如何配置ConsoleLifetimeOptions以根据需要禁止显示状态消息。

好了,这个系列 的文章就到此结束,后面我会再补充6篇文章,该系列就完全结束了,剩下的 就是继续搞秒杀项目(ASP.Net Core )的CI/CD,争取 年前能搞定吧。

翻译: Andrew Lock   https://andrewlock.net/new-in-aspnetcore-3-structured-logging-for-startup-messages/

作者:郭峥

出处:http://www.cnblogs.com/runningsmallguo/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志的更多相关文章

  1. 探索 ASP.Net Core 3.0系列五:引入IHostLifetime并弄清Generic Host启动交互

    前言:在本文中,我将介绍如何在通用主机之上重新构建ASP.NET Core 3.0,以及由此带来的一些好处. 同时也展示了3.0中引入新的抽象类IHostLifetime,并描述了它在管理应用程序(尤 ...

  2. .NET Core开发日志——结构化日志

    在.NET生态圈中,最早被广泛使用的日志库可能是派生自Java世界里的Apache log4net.而其后来者,莫过于NLog.Nlog与log4net相比,有一项较显著的优势,它支持结构化日志. 结 ...

  3. 学习ASP.NET Core Blazor编程系列六——新增图书(上)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  4. 学习ASP.NET Core Razor 编程系列六——数据库初始化

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  5. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    C#中的函数式编程:递归与纯函数(二)   在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...

  6. 学习ASP.NET Core Razor 编程系列五——Asp.Net Core Razor新建模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  7. [渣译文] SignalR 2.0 系列: 开始使用SignalR 2.0

    原文:[渣译文] SignalR 2.0 系列: 开始使用SignalR 2.0 英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with ASP ...

  8. Atitit 发帖机系列(8)  词法分析器v5 版本新特性说明)

    Atitit 发帖机系列(8)  词法分析器v5 版本新特性说明) v5  增加对sql单引号的内部支持.可以作为string 结构调整,使用递归法重构循环发..放弃循环发. V4 java dsl词 ...

  9. 学习ASP.NET Core Blazor编程系列六——初始化数据

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

随机推荐

  1. es6一句话拾遗

    Symbol最大的作用就是用于消除魔术字符串: Set跟数组的最大区别,就是Set的成员都是唯一的,没有重复:(方法:add(value),has,delete,clear) Map跟对象的最大区别, ...

  2. 《转》crontab 定时任务

    命令格式 crontab [-u user] file crontab [-u user] [-e | -l | -r | -i ] 命令参数 -u user:用来设定某个用户的crontab服务,例 ...

  3. 05爬虫-requests模块基础(2)

    今日重点: 1.代理服务器的设置 2.模拟登陆过验证码(静态验证码) 3.cookie与session 4.线程池 1.代理服务器的设置 有时候使用同一个IP去爬取同一个网站,久了之后会被该网站服务器 ...

  4. Linq分页排序通用方法

    1.通用方法 2.调用 -----------------------------1.------------------------------------------- public class ...

  5. 【计算机网络】WebSocket实现原理分析

    1.介绍一下websocket和通信过程? 1.1 基本概念 [!NOTE] Websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 T ...

  6. oracle多表关联update

    日常的开发中一般都是写的单表update语句,很少写多表关联的update. 不同于SQL Server,在Oracle中,update的多表连接更新和select的多表连接查询在使用的方法上存在较大 ...

  7. Oracle - 如何查找指定字符串所出现的表

    需求:举个例子,oracle测试库的scott用户下面的有张emp表,emp表的ename列中有一行数据为'CLARK'.红色标记部分. SQL> select * from scott.emp ...

  8. NumPy 学习 第四篇:数组的基本操作

    在数组中,用axis(轴)表示维度,对于三维数组,axis参数的取值通常有: 当axis=None时,表示把数组展开为一维数组: 当axis=0时,表示按照行(第一维)进行计算: 当axis=1时,表 ...

  9. Jsp学习笔记(2)——页面导航、表单、EL表达式

    页面导航 有两种跳转页面的方法.重定向和请求转发 两者区别: 请求转发(forward) 重定向(rerect) 请求服务次数 1 2 是否保留第一次请求request范围的属性 保留 不保留 地址栏 ...

  10. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

    本文梯子 本文3.0版本文章 更新 代码已上传Github+Gitee,文末有地址 零.今天完成的绿色部分 一.依赖注入的理解和思考 二.常见的IoC框架有哪些 1.Autofac+原生 2.三种注入 ...