《ASP.NET Core 6框架揭秘实例》演示[14]:日志的进阶用法

为了对各种日志框架进行整合,微软创建了一个用来提供统一的日志编程模式的日志框架。《ASP.NET Core 6框架揭秘》实例演示[13]:日志的基本编程模式》以实例演示的方式介绍了日志的基本编程模式,现在我们来补充几种“进阶”用法。[本文节选《ASP.NET Core 6框架揭秘》第8章]

[S808]利用配置定义日志过滤规则(源代码)
[S809]利用日志范围输出调用链(源代码)
[S810]LoggerMessage的应用(源代码)
[S812]基于Activity的日志范围(源代码)

[S808]利用配置定义日志过滤规则

通过Func<string, string, LogLevel, bool>对象表示的日志过滤规还可以采用配置的形式来定义。以配置的形式定义的过滤规则最终都体现为对最低等级的设置,设定的这个最低日志等级可以是一个全局的默认设置,也可以专门针对某个日志类别或者ILoggerProvider类型。下面演示针对配置形式的日志过滤规则。我们先创建一个名为logging.json的文件,并在其中定义如下这段配置,然后将“Copy to Output Directory”的属性设置为“Copy Always”。这段配置定义了两组日志过滤规则,第一组是默认规则,第二组则是专门为ConsoleLoggerProvider(别名为Console)定义的过滤规则。

{"LogLevel": {"Default" : "Error","Foo" : "Debug"},"Console": {"LogLevel": {"Default" : "Information","Foo" : "Warning","Bar" : "Error"}}
}

以配置形式定义的日志过滤规则最终会落实到对最低日志等级的设置上,其中Default表示默认设置,其他的则是针对具体日志类别的设置。上面定义的这段配置体现的过滤规则如下:对于ConsoleLoggerProvider来说,在默认情况下只有等级不低于Information的日志事件会被输出,而对日志类别“Foo”和“Bar”来说,对应的最低日志等级分别为Warning和Error。对于其他ILoggerProvider类型来说,如果日志类别为“Foo”,那么只有等级不低于Debug的日志才会被输出,其他日志类别则采用默认的等级Error。

为了检验最终是否会采用配置定义的规则对日志消息进行过滤,我们根据配置文件生成对应的IConfiguration对象,然后采用依赖注入的方式创建一个ILoggerFactory对象。我们将IConfiguration对象作为参数调用ILoggingBuilder接口的AddConfiguration扩展方法将配置承载的过滤规则应用到配置模型上。我们最终采用不同的类别(“Foo”、“Bar”和“Baz”)创建了三个ILogger对象,并利用它们记录了六条具有不同等级的日志。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("logging.json").Build();var loggerFactory = new ServiceCollection().AddLogging(builder => builder.AddConfiguration(configuration).AddConsole().AddDebug()).BuildServiceProvider().GetRequiredService<ILoggerFactory>();Log(loggerFactory, "Foo");
Log(loggerFactory, "Bar");
Log(loggerFactory, "Baz");Console.Read();static void Log(ILoggerFactory loggerFactory, string category)
{var logger = loggerFactory.CreateLogger(category);var levels = (LogLevel[])Enum.GetValues(typeof(LogLevel));levels = levels.Where(it => it != LogLevel.None).ToArray();var eventId = 1;Array.ForEach(levels, level => logger.Log(level, eventId++, "This is a/an {0} log message.", level));

由于我们注册了两个不同的ILoggerProvider类型,创建了三种基于不同日志类别的ILogger对象,所以这里面涉及分发的36条日志消息。而图1是程序执行(以Debug模式进行编译)之后控制台和Visual Studio调试输出窗口的输出结果。

976c64cb8bb6940dabd6e72cd025b906.png
图1 针对配置文件的日志过滤

[S809]利用日志范围输出调用链

日志可以为针对某种目的(如纠错查错、系统优化和安全审核等)而进行的分析提供原始数据,所以孤立存在的一条日志消息对数据分析往往毫无用处,很多问题只有将多条相关的日志消息综合起来分析才能找到答案。日志框架为此引入了日志范围(Log Scope)的概念。所谓的日志范围是为日志记录创建的一个具有唯一标识的上下文,如果注册的ILoggerProvider对象支持这个特性,那么它提供的ILogger对象会感知到当前日志范围的存在,此时它可以将上下文信息一并记录下来。

在接下来演示的实例中,我们将一个包含多个处理步骤的事务作为日志范围,并将各个步骤的执行耗时记录下来。如下面的代码片段所示,我们利用依赖注入容器创建一个ILogger对象。在调用AddConsole扩展方法注册ConsoleLoggerProvider对象之后,我们接着调用AddSimpleConsole扩展方法为它注册了一个简单的格式化器,该方法接受一个Action<SimpleConsoleFormatterOptions>对象作为参数来对格式化器配置选项进行设置。我们利用传入的这个委托将配置选项的IncludeScopes属性设置为True。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Diagnostics;var logger = new ServiceCollection().AddLogging(builder => builder.AddConsole().AddSimpleConsole(options => options.IncludeScopes = true)).BuildServiceProvider().GetRequiredService<ILogger<Program>>();using (logger.BeginScope($"Foobar Transaction[{Guid.NewGuid()}]"))
{var stopwatch = Stopwatch.StartNew();await Task.Delay(500);logger.LogInformation("Operation foo completes at {0}", stopwatch.Elapsed);await Task.Delay(300);logger.LogInformation("Operation bar completes at {0}", stopwatch.Elapsed);await Task.Delay(800);logger.LogInformation("Operation baz completes at {0}", stopwatch.Elapsed);
}
Console.Read();

日志范围是通过调用ILogger对象的BeginScope方法创建的,我们在调用这个方法时指定一个携带请求ID的字符串来描述并标识创建日志范围。创建的日志范围上下文体现为一个IDisposable对象,范围因Dispose方法的调用而终结。对于支持日志范围的ILoggerProvider对象来说,它提供的ILogger对象自身能够感知到当前上下文的存在,所以我们演示程序并不需要作额外的修改。在我们演示的程序中,执行的事务包含三个操作(Foo、Bar和Baz)。我们将事务开始的那一刻作为基准,记录每个操作完成的时间。该程序启动后会将日志以图2所示的形式输出到控制台上,可以看出包含事务ID的日志范围上下文描述信息一并被记录下来。如果日志最终被写入海量存储中,只要知道请求ID,我们就能将相关的日志提取出来并利用它们构建出该请求的调用链。

75a5f60e1e94f8e6ff5a61113e8677a7.png
图2 记录日志范围上下文

[S810]LoggerMessage的应用

前面演示的程序总是指定一个包含占位符(“{数字}”或者“{文本}”)的消息模板作为参数调用ILogger对象的Log方法来记录日志,所以该方法每次都需要对提供的消息模板进行解析。如果每次提供的都是相同的消息模板,那么这种对消息模板的重复解析就会显得多余。如果应用对性能要求比较高,这绝不是一种好的编程方式。为了解决这个问题,日志框架提供了一个名为LoggerMessage的静态类型,我们可以利用它根据某个具体的消息模板创建一个委托来记录日志。在如下所示的演示程序中,我们利用日志将针对FoobarAsync方法的“调用现场”记录下来,具体记录的内容包括输入参数、返回值和执行耗时。如代码片段所示,我们根据FoobarAsync的定义调用LoggerMessage类型的静态Define方法创建了一个Action<ILogger, int, long, double, TimeSpan, Exception>类型的委托对象来记录日志。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Diagnostics;var random = new Random();
var template = "Method FoobarAsync is invoked." +"\n\t\tArguments: foo={foo}, bar={bar}" +"\n\t\tReturn value: {returnValue}" +"\n\t\tTime:{time}";
var log = LoggerMessage.Define<int, long, double, TimeSpan>(logLevel: LogLevel.Trace,eventId: 3721,formatString: template);
var logger = new ServiceCollection().AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace).AddConsole()).BuildServiceProvider().GetRequiredService<ILoggerFactory>()
.CreateLogger("App.Program");await FoobarAsync(random.Next(), random.Next());
await FoobarAsync(random.Next(), random.Next());
Console.Read();async Task<double> FoobarAsync(int foo, long bar)
{var stopwatch = Stopwatch.StartNew();await Task.Delay(random.Next(100, 900));var result = random.Next();log(logger, foo, bar, result, stopwatch.Elapsed, null);return result;
}《ASP.NET Core 6框架揭秘》实例演示[01]:编程初体验
《ASP.NET Core 6框架揭秘》实例演示[02]:各种形式的API开发
《ASP.NET Core 6框架揭秘》实例演示[03]:Dapr初体验
《ASP.NET Core 6框架揭秘》实例演示[04]:自定义依赖注入框架
《ASP.NET Core 6框架揭秘》实例演示[05]:依赖注入基本编程模式
《ASP.NET Core 6框架揭秘》实例演示[06]:依赖注入框架设计细节
《ASP.NET Core 6框架揭秘》实例演示[07]:文件系统
《ASP.NET Core 6框架揭秘》实例演示[08]:配置的基本编程模式
《ASP.NET Core 6框架揭秘》实例演示[09]:将配置绑定为对象
《ASP.NET Core 6框架揭秘》实例演示[10]:Options基本编程模式
《ASP.NET Core 6框架揭秘》实例演示[11]:诊断跟踪的几种基本编程方式 
《ASP.NET Core 6框架揭秘》实例演示[13]:日志的基本编程模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是云原生,云原生技术为什么这么火?

文章目录 一、开篇浅谈二、云计算是什么三、云原生是什么四、云计算的四个层次 4.1 IaaS&#xff08;基础架构即服务&#xff09;4.2 PaaS&#xff08;平台即服务&#xff09;4.3 SaaS&#xff08;软件即服务&#xff09;4.4 DaaS&#xff08;数据即服务&#xff09;五、云原生…

PerfView专题 (第五篇):如何寻找 C# 托管内存泄漏

一&#xff1a;背景 前几篇我们聊的都是 非托管内存泄漏&#xff0c;这一篇我们再看下如何用 PerfView 来排查 托管内存泄漏 &#xff0c;其实 托管内存泄漏 比较好排查&#xff0c;尤其是用 WinDbg&#xff0c;毕竟C#是带有丰富的元数据&#xff0c;不像C下去就是二进制。二&a…

DevOps及DevOps常用的工具介绍

目录 1. 什么是 DevOps2. DevOps 概念的起源 2.1. 单体架构 瀑布模式2.2. 分布式架构 敏捷开发模式 2.2.1. 多人协同开发问题2.2.2. 多机器问题2.2.3. 开发和运维角色的天生对立问题2.3. 微服务架构 DevOps3. DevOps 到底是什么4. DevOps 常用的工具 4.1. Jenkins4.2. Kuber…

2018年SIAF 广州国际工业自动化技术及装备展览会下周隆重开幕

同期研讨活动聚焦行业未来趋势&#xff0c;探索技术发展及实际应用层面。 华南最重要的工业自动化行业盛会之一&#xff0c;SIAF广州国际工业自动化技术及装备展览会&#xff0c;将于2018年3月4至6日在广州中国进出口商品交易会展馆隆重开幕。为期三天的展会将再度与广州国际模…

相约现在,遇见未来

# 遇见未来这个世界很小&#xff0c;我们就这样遇见。这个世界很大&#xff0c;分开就很难再见。大家好&#xff0c;我是 chait&#xff0c;很高兴我们在这里《遇见》。今天是我申请公众号通过后的第一天&#xff0c;也是在该平台发表的第一篇文章&#xff0c;唠嗑点啥呢&#…

有关并行的两个重要定律

本文摘自 葛一鸣 老师的《实战java高并发程序设计》一书。因为觉得写得好就摘下来了 将串行程序改造成并发程序&#xff0c;一般来说可以提高程序的整体性能&#xff0c;但是究竟能提升多少&#xff0c;甚至说究竟是否真的可以提高&#xff0c;还是一个需要研究的问题。目前&am…

IT圈中的Bug的类型与历史

美国计算机科学家、图灵奖获得者詹姆斯尼古拉格雷(Jim Gray)&#xff0c;在他的著名的论文“Why do computers stop and what can be done about it?”中首次提出了程序bug的类型&#xff0c;比如玻尔bug(Bohrbug)、 海森堡bug(Heisenbugs)等用著名科学家名称命名的bug。后来又…

Windows Nano Server安装配置详解03:远程管理Nano Server

远程管理Nano Server主要是通过使用远程powershell的方式。首先&#xff0c;我们把Nano Server的登录凭据保存到$cred变量之中&#xff0c;如图。其次&#xff0c;把远程Nano Server服务器添加到远程管理机本地的trustedHosts中&#xff0c;否则会报下面的错误&#xff0c;如图…

你和阿里资深架构师之间,差的不仅仅是年龄(进阶必看)

导读&#xff1a;阅读本文需要有足够的时间&#xff0c;笔者会由浅到深带你一步一步了解一个资深架构师所要掌握的各类知识点&#xff0c;你也可以按照文章中所列的知识体系对比自身&#xff0c;对自己进行查漏补缺&#xff0c;觉得本文对你有帮助的话&#xff0c;可以点赞关注…

[luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

传送门 很蒙蔽&#xff0c;不知道怎么搞。 网上看题解有说可以哈希二分搞&#xff0c;也有的人说用Manacher搞&#xff0c;Manacher是什么鬼&#xff1f;以后再学。 对于这个题&#xff0c;可以从矩阵4个角hash一遍&#xff0c;然后枚举矩阵中的点&#xff0c;再二分半径。 但是…

Semaphore详解

Semaphore基本使用场景 Semaphore的基本使用场景是限制一定数量的线程能够去执行. 举个简单的例子: 一个单向隧道能同时容纳10个小汽车或5个卡车通过(1个卡车等效与2个小汽车), 而隧道入口记录着当前已经在隧道内的汽车等效比重. 比如1个小汽车和1个卡车, 则隧道入口显示3. 若…

PerfView专题 (第六篇):如何洞察 C# 中 GC 的变化

一&#xff1a;背景 在洞察 GC 方面&#xff0c;我觉得市面上没有任何一款工具可以和 PerfView 相提并论&#xff0c;这也是为什么我会在 WinDbg 之外还要学习这么一款工具的原因&#xff0c;这篇我们先简单聊聊 PerfView 到底能洞察 GC 什么东西&#xff1f;二&#xff1a;洞察…

Linux_日志管理介绍(一)

一、介绍1、CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务&#xff0c;但是rsyslogd是和syslogd服务相兼容的2、除了系统默认的日志之外&#xff0c;采用RPM方式安装的系统服务也会默认把日志记录在/var/log/目录中&#xff08;源码包安装的服务日志是在源码包指…

如何将exe文件添加到开机启动

1、先创建exe文件的快捷方式 2、打开windows的startup启动目录&#xff08;针对win10以上&#xff09; windows有两个以上startup目录&#xff0c;一个是针对所有用户有效的&#xff0c;另外是每个用户下边有一个&#xff1a; 针对当前用户 &#xff1a; C:\Users\{当前用户}\A…

.NET MAUI 跨平台应用程序 (Windows App 和 Android )示例

也就前周&#xff0c;.Net MAUI正式版出来了 &#xff0c;一个支持跨平台的UI框架,Linux支持情况官网也没说&#xff0c;按理来说应该也是支持的&#xff0c;刚好&#xff0c;我最近也在研究GUI的基本原理&#xff0c;微软出品还是值得深入研究一下的&#xff0c;就先来个样例&…

OpenStack 计算节点删除

前提 计算节点中一个僵尸计算节点存在&#xff0c;而里面的CPU数目在总物理CPU中&#xff0c;导致认为当前能创建实例。而实际没有这么多资源。其中node-11为僵尸节点。 原因 删除计算节点不能直接格式化该服务器&#xff0c;否则在控制节点的数据库上会存在该计算节点的数据。…

PHP 7.2 新功能介绍

PHP 7.2 已經在 2017 年 11 月 30 日 正式發布 。這次發布包含新特性、功能&#xff0c;及優化&#xff0c;以讓我們寫出更好的代碼。在這篇文章裡&#xff0c;我將會介紹一些 PHP 7.2 最有趣的語言特性。 你可以在 Requests For Comments 頁面查看完整的更動清單。 核心改进 参…

如何打造单文件 Blazor Server 应用

前言上次&#xff0c;我们介绍了《如何打造单文件前后端集成 ASP.NET Core 应用》。但是&#xff0c;网友说&#xff0c;对于 Blazor Server 项目此方法无效。于是&#xff0c;我们测试了一下&#xff1a;BlazorApp1.csproj<Project Sdk"Microsoft.NET.Sdk.Web"&g…

Android线程池详解

引入线程池的好处 1&#xff09;提升性能。创建和消耗对象费时费CPU资源 2&#xff09;防止内存过度消耗。控制活动线程的数量&#xff0c;防止并发线程过多。 我们来看一下线程池的简单的构造 [html] view plaincopy print?public ThreadPoolExecutor(int corePoolSize, …

win11下vscode 自动升级失败 There was an error while marking a file for deletion

当升级vscode时出现下方报错&#xff1a; There was an error while marking a file for deletion:Failed to mark file for deletion:拒绝访问.Please verify there are no Visual Studio Code processes still executing既然是“拒绝访问”应该是权限问题&#xff0c;关闭vsc…