第18课:日志框架:聊聊记日志的最佳姿势

学习分享 丨作者 / 郑 子 铭 丨公众号 / DotNet NB / CloudNative NB

日志框架必要的包:

1、Microsoft.Extensions.Logging

2、Microsoft.Extensions.Logging.Console

3、Microsoft.Extensions.Logging.Debug

4、Microsoft.Extensions.Logging.TraceSource

5、Microsoft.Extensions.Configuration.Json

代码通过一个控制台程序,展示从读取配置到整个日志的记录器的构造和日志记录的过程

首先从文件读取配置

IConfigurationBuilder configBuilder = new ConfigurationBuilder();
configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var config = configBuilder.Build();

接着构造容器,注入对象

IServiceCollection serviceCollection = new ServiceCollection();// 构造容器
// 用工厂模式将配置对象注册到容器管理
// 注入的时候使用了一个委托,意味着容器可以帮我们管理这个对象的生命周期
serviceCollection.AddSingleton<IConfiguration>(p => config);
// 如果将实例直接注入,容器不会帮我们管理
//serviceCollection.AddSingleton<IConfiguration>(config);

// AddLogging 往容器里面注册了几个关键对象:
// ILoggerFactory,泛型模板 typeof (ILogger<>),Logger 的过滤配置 IConfigureOptions<LoggerFilterOptions>
// 最后一行,configure((ILoggingBuilder) new LoggingBuilder(services)); 就是整个注入我们的委托
serviceCollection.AddLogging(builder =>
{
    builder.AddConfiguration(config.GetSection("Logging"));// 注册 Logging 配置的 Section
    builder.AddConsole();// 先使用一个 Console 的日志输出提供程序
});

AddLogging 源码

配置文件,appsettings.json

Logging 里面定义了 Log 的级别,Key 代表 Log 的名称,Value 代表 Logger 的级别

Console 是指针对 Console 的输出提供程序配置的日志级别

下面看一下日志级别的定义,按照严重程度从低到高

也就是说我们可以指定日志输出的最低级别

接着 BuildServiceProvider,从容器里面获取 ILoggerFactory

ILoggerFactory 的定义

获取到 ILoggerFactory 之后就可以创建日志记录器

因为配置文件中 alogger 的级别是 Trace

所以这三行都会被打印出来

启动程序,输出如下:

方括号的内容是 EventID,也就是针对每一个记录的位置事件,可以为它分配一个事件 ID,代码中在 LogDebug 的时候定义了一个事件 ID 是2001

假如说把 alogger 的日志级别调整成 Information

那么 Debug 级别的信息没有输出的

除了使用 CreateLogger 指定 logger 的名称,实际上还可以借助容器来构造 logger,通常情况下我们会定义自己的类

接着,将 OrderService 注入到容器中

日志级别设置为 Trace

启动程序,输出如下:

这样做的意义是什么呢?

通常情况下并不会用 ILoggerFactory 来构造日志记录器,而是用强类型的这种依赖注入的方式来去管理我们的日志,也就是说用构造函数将泛型的 ILogger 注入进来的方式

这样的方式有个好处就是我们不需要去为 logger 定义名字,它会默认将我们类型的名称作为记录器的名字,命名空间加上类名 LoggingSimpleDemo.OrderService ,那也就是可以在配置文件里面设置日志级别

这样子就没有输出

这里面有一个小技巧,需要大家特别注意,就是当我们在记录日志的时候,尽量使用模板的方式

以下两种方式效果相同,但是字符串拼接的时机不同

第一行代码是在我们决定要输出的时候,也就是在 LogInformation 内部 console 要输出的时候才做拼接的动作

第二行代码是指我们在字符串拼接好以后,输入给了 LogInformation

如果我们把日志级别关掉

两行代码都不会有输出,但是第一行代码字符串拼接的动作不会执行,第二行代码已经执行了,第一行代码节省了运行资源

另外一个就是,在记录日志的时候,不要把敏感信息记录到日志中,记录日志的目的是为了调试或者定位问题

总结一下

1、日志级别定义

日志级别会从严重程度的低到高定义,可以决定输出的最低级别

2、日志对象获取

可以通过 ILoggerFactory 的方式获取日志对象,对它指定一个名字,也可以通过 ILogger 泛型的模式,从容器中获取日志对象,最推荐的就是强类型的泛型模式

3、日志过滤的配置逻辑

可以针对 logger 的名称来进行任意的配置,日志的开关以及日志的级别

4、日志记录的方法

LogInformation,LogDebug,还有一些小技巧,使用模板的方式记录日志,而不是提前拼接字符串输入给日志系统

5、避免记录敏感信息,如密码、密钥,规避安全风险

GitHub源码链接:https://github.com/MingsonZheng/DotNetCoreDevelopmentActualCombat/tree/main/LoggingSimpleDemoarrow-up-right

Last updated