.NET Core开发实战(第19课:日志作用域:解决不同请求之间的日志干扰)--学习笔记
19 | 日志作用域:解决不同请求之间的日志干扰
开始之前先看一下上一节的代码
// 配置的框架
var configBuilder = new ConfigurationBuilder();
configBuilder.AddCommandLine(args);
configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var config = configBuilder.Build();
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IConfiguration>(p => config);
// 日志的框架
serviceCollection.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));// 注册 Logging 配置的 Section
builder.AddConsole();// 先使用一个 Console 的日志输出提供程序
builder.AddDebug();
});
我们可以观察到配置的框架和日志的框架,它们的设计模式是很相似的
区别就是:
配置的框架是从不同的数据源读取数据并且供给我们结构化的数据可以读取
日志框架是用统一的记录方式,让我们可以把日志记录到不同的地方去,输出到不同的地方去
接下来演示一下关于日志的作用域的部分
日志作用域几个常用场景:
1、一个事务包含多条操作时:比如说在一个事务里面去操作的时候,会需要记录多条日志,需要把多条日志串联在一起,而不是记录成一行
2、复杂流程的日志关联时:比如说工作流流程里面去进入这个日志
3、调用链追踪与请求处理过程对应时:如果在调用链追踪过程中记录了多条日志,希望把日志串联在一起的时候,作用域就发挥了作用
主程序
namespace LoggingScopeDemo
{
class Program
{
static void Main(string[] args)
{
var configBuilder = new ConfigurationBuilder();
configBuilder.AddCommandLine(args);
configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var config = configBuilder.Build();
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(p => config); //用工厂模式将配置对象注册到容器管理
serviceCollection.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));
builder.AddConsole();
builder.AddDebug();
});
IServiceProvider service = serviceCollection.BuildServiceProvider();
var logger = service.GetService<ILogger<Program>>();
// 相当于记录了一条上下文串联的日志
using (logger.BeginScope("ScopeId:{scopeId}", Guid.NewGuid()))
{
logger.LogInformation("这是Info");
logger.LogError("这是Error");
logger.LogTrace("这是Trace");
}
}
}
}
新增配置文件 appsettings.json,右键属性,如果较新则复制
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information",
"LoggingScopeDemo.Program": "Trace",
"alogger": "Trace"
}
}
}
}
启动程序,输出如下:
info: LoggingScopeDemo.Program[0]
这是Info
fail: LoggingScopeDemo.Program[0]
这是Error
trce: LoggingScopeDemo.Program[0]
这是Trace
和之前一样的输出,接着修改配置文件
"IncludeScopes": true,
启动程序,输出如下:
info: LoggingScopeDemo.Program[0]
=> ScopeId:b8ef7682-6c6d-4f74-83c8-b9fd4613c623
这是Info
fail: LoggingScopeDemo.Program[0]
=> ScopeId:b8ef7682-6c6d-4f74-83c8-b9fd4613c623
这是Error
trce: LoggingScopeDemo.Program[0]
=> ScopeId:b8ef7682-6c6d-4f74-83c8-b9fd4613c623
这是Trace
可以看到,日志里面有 scope,并且三条日志都包含了相同的 ScopeId,这个是由我们决定 Scope 的内容是什么,一般推荐使用一个唯一标识,比如 HTTP 请求的 id,或者是 session 的 id,或者是事务的 id
接着修改为循环
// 只要输入不是 Esc 就循环执行
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
// 相当于记录了一条上下文串联的日志
using (logger.BeginScope("ScopeId:{scopeId}", Guid.NewGuid()))
{
logger.LogInformation("这是Info");
logger.LogError("这是Error");
logger.LogTrace("这是Trace");
}
Console.WriteLine("============分割线=============");
}
Console.ReadKey();
启动程序,输出如下:
info: LoggingScopeDemo.Program[0]
=> ScopeId:cc25dd86-d3fe-41e8-b607-61912c65bde7
这是Info
============分割线=============
fail: LoggingScopeDemo.Program[0]
=> ScopeId:cc25dd86-d3fe-41e8-b607-61912c65bde7
这是Error
trce: LoggingScopeDemo.Program[0]
=> ScopeId:cc25dd86-d3fe-41e8-b607-61912c65bde7
这是Trace
这里可以看到分割线有点错乱,这是因为 Console 的提供程序实际上内部是用异步的方式在记录,那也就是这里遇到并发的问题
调整一下代码,让主线程休息一下
System.Threading.Thread.Sleep(100);
Console.WriteLine("============分割线=============");
这样子启动之后顺序就正确了
在程序启动的情况下,修改 Debug 目录下的配置文件
"IncludeScopes": false,
修改保存后在控制台输入回车,可以看到配置生效了,意味着可以使用配置热更新能力来动态修改配置的输出,调整配置输出的级别
比如将
"LoggingScopeDemo.Program": "Trace",
修改为
"LoggingScopeDemo.Program": "Error",
修改保存后在控制台输入回车,只会输出 Error 级别
GitHub源码链接:
这是在控制台里面的效果,接下来看一下在一个 ASP.NET Core Web 应用下面的日志是什么样子
这是一个默认的工程,仅仅在应用程序里面加了两行代码
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
_logger.LogInformation("开始Get了");
_logger.LogInformation("Get睡醒了");
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
日志级别
"Console": {
"IncludeScopes": true
}
启动程序,输出如下:
info: LoggingDemo.Controllers.WeatherForecastController[0]
=> RequestPath:/weatherforecast RequestId:0HLU2MTQ99HO2:00000001, SpanId:|7bb9cb12-4a0fe499cae27707., TraceId:7bb9cb12-4a0fe499cae27707, ParentId: => LoggingDemo.Controllers.WeatherForecastController.Get (LoggingDemo)
开始Get了
info: LoggingDemo.Controllers.WeatherForecastController[0]
=> RequestPath:/weatherforecast RequestId:0HLU2MTQ99HO2:00000001, SpanId:|7bb9cb12-4a0fe499cae27707., TraceId:7bb9cb12-4a0fe499cae27707, ParentId: => LoggingDemo.Controllers.WeatherForecastController.Get (LoggingDemo)
Get睡醒了
可以看到,记录的 开始Get了 以及 Get睡醒了,都包含了 RequestPath,RequestId,SpanId,TraceId 这些信息,这些信息是当前请求的上下文
也就意味着可以在记录日志的时候,用请求上下文把日志串联起来,多个请求的日志可以区分开来,无论记录了多条还是单条
也就意味着可以在事务处理的过程中,复杂的流程的过程中,或者调用链的处理过程中,当然还有其他的场景任意的需要将多条日志串联起来的场景,都可以用作用域来实现这个能力
GitHub源码链接:
https://github.com/MingsonZheng/DotNetCoreDevelopmentActualCombat/tree/main/LoggingDemo



本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。
.NET Core开发实战(第19课:日志作用域:解决不同请求之间的日志干扰)--学习笔记的更多相关文章
- 2月送书福利:ASP.NET Core开发实战
大家都知道我有一个公众号“恰童鞋骚年”,在公众号2020年第一天发布的推文<2020年,请让我重新介绍我自己>中,我曾说到我会在2020年中每个月为所有关注“恰童鞋骚年”公众号的童鞋们送一 ...
- [ASP.NET Core开发实战]开篇词
前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...
- [ASP.NET Core开发实战]基础篇02 依赖注入
ASP.NET Core的底层机制之一是依赖注入(DI)设计模式,因此要好好掌握依赖注入的用法. 什么是依赖注入 我们看一下下面的例子: public class MyDependency { pub ...
- TensorFlow实战第七课(dropout解决overfitting)
Dropout 解决 overfitting overfitting也被称为过度学习,过度拟合.他是机器学习中常见的问题. 图中的黑色曲线是正常模型,绿色曲线就是overfitting模型.尽管绿色曲 ...
- zuul开发实战(限流,超时解决)
什么是网关 API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求.鉴权.监控.缓存.限流等功能 统一接入 * 智能路由 * AB测试.灰度测试 ...
- .NET Core开发实战(第11课:文件配置提供程序)--学习笔记
11 | 文件配置提供程序:自由选择配置的格式 文件配置提供程序 Microsoft.Extensions.Configuration.Ini Microsoft.Extensions.Configu ...
- 2、SpringBoot接口Http协议开发实战8节课(1-6)
1.SpringBoot2.xHTTP请求配置讲解 简介:SpringBoot2.xHTTP请求注解讲解和简化注解配置技巧 1.@RestController and @RequestMapping是 ...
- [ASP.NET Core开发实战]基础篇03 中间件
什么是中间件 中间件是一种装配到应用管道,以处理请求和响应的组件.每个中间件: 选择是否将请求传递到管道中的下一个中间件. 可在管道中的下一个中间件前后执行. ASP.NET Core请求管道包含一系 ...
- [ASP.NET Core开发实战]基础篇01 Startup
Startup,顾名思义,就是启动类,用于配置ASP.NET Core应用的服务和请求管道. Startup有两个主要作用: 通过ConfigureServices方法配置应用的服务.服务是一个提供应 ...
- 2、SpringBoot接口Http协议开发实战8节课(7-8)
7.SpringBoot2.x文件上传实战 简介:讲解HTML页面文件上传和后端处理实战 1.讲解springboot文件上传 MultipartFile file,源自SpringMVC 1)静态页 ...
随机推荐
- 彻底解决 gcr、quay、DockerHub 镜像下载难题
在使用 Docker 和 Kubernetes 时,我们经常需要访问 gcr.io 和 quay.io 镜像仓库,由于众所周知的原因,这些镜像仓库在中国都无法访问,唯一能访问的是 Docker Hub ...
- java进阶(1)--final、常量
final是java的关键字,主要表示最终的 一.final修饰的类无法被继承
- 面向对象C++学习总结
洛谷日记3 2023.5 面向对象C++ : 运算符重载 1.运算符重载 (1)n定义重载运算符和定义普通函数类似,只是该函数的名字是operator@,@表示要重载的运算符. MinInt oper ...
- CS2打开可以听到声音,但黑屏问题?
1.问题 我这里原先是可以启动CS2的,但是后来在CS2中重新调整了分辨率等等,之后由于某种原因又调整了屏幕分辨率,导致后面一进入CS2登录界面,橙色登陆界面就会缩在左上角一小块,并且之后就会陷入黑屏 ...
- Git-远程仓库-remote-pull-push
- Oracle数据类型的简单学习之一
Oracle数据类型的简单学习之一 背景 因为信创安可替代的发展 有很多项目提到了数据库切换到国产数据库的要求. 一般情况是要求从Oracle/SQLServer 迁移到国产的: 达梦/瀚高/人大金仓 ...
- [转帖]你应该知道的Shell 脚本的经典十三问
https://blog.csdn.net/wangzhicheng987/article/details/131031344 1. 为何叫做shell? 我们知道计算机的运作不能离开硬件,但使用者却 ...
- [转帖]MySQL Decimal 的实现方法
码: 背景 数字运算在数据库中是很常见的需求, 例如计算数量.重量.价格等, 为了满足各种需求, 数据库系统通常支持精准的数字类型和近似的数字类型. 精准的数字类型包含 int, decimal 等, ...
- [转帖]Kafka-LEO和HW概念及更新流程
https://www.cnblogs.com/youngchaolin/p/12641463.html 目录 LEO&HW基本概念 LEO&HW更新流程 LEO HW 更新流程示例分 ...
- 虚拟化平台IO劣化分析
虚拟化平台IO劣化分析 背景 最近同事让帮忙做几个虚拟机进行性能测试. 本来应该搭建CentOS/Winodws平台进行相关的测试工作. 但是为了环境一致性, 使用了ESXi6.7 进行虚拟化 然后这 ...