18 | 日志框架:聊聊记日志的最佳姿势
新建控制台应用程序👉命名LoggingSimpleDemo
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace LoggingSimpleDemo
{
class Program
{
static void Main(string[] args)
{
// 利用之前的方式加载json配置
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsetting.json", false, true);
var config = builder.Build();
IServiceCollection servicesCollection = new ServiceCollection();
// 使用工厂模式将配置对象注册到容器管理
servicesCollection.AddSingleton<IConfiguration>(p => config);
servicesCollection.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));
builder.AddConsole();
});
}
}
}
前三行代码,我们使用了之前的方式,加载json配置
利用IServiceCollection servicesCollection = new ServiceCollection()
构建了一个容器
使用工厂模式将配置注册到容器管理servicesCollection.AddSingleton<IConfiguration>(p => config)
,因为使用servicesCollection.AddSingleton<IConfiguration>(config)
这种方式,将config
实例直接注入进去,容器是不会帮助我们管理这个对象的生命周期的。
servicesCollection.AddLogging(builder =>
{
builder.AddConfiguration(config);
builder.AddConsole();
});
我们可以看看servicesCollection.AddLogging()
方法的定义AddLogging
往容器里注册了几个关键的对象,一个ILoggerFactory
,一个ILogger
的泛型模板,一个是Logger
的过滤配置,最后configure
就是我们整个注入的委托。
接下来看看我们的配置文件appsettings.josn
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"LogLevel": {
"Default": "Information",
"Program": "Trace",
"alogger": "Trace"
}
}
}
}
配置文件里面有一节Logging
,里面定义了Log
的级别。
这里面Key
就代表了我们的Logger
的名称,Value
就代表了我们Logger
的级别。
下面一节Console
指我们针对Console
的输出提供程序,配置的日志级别。
日志级别定义
namespace Microsoft.Extensions.Logging
{
// Defines logging severity levels.
public enum LogLevel
{
Trace,
Debug,
Information,
Warning,
Error,
Critical,
None
}
}
None
代表不输出任何的日志
接下来继续看代码
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace LoggingSimpleDemo
{
class Program
{
static void Main(string[] args)
{
// 利用之前的方式加载json配置
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json", false, true);
var config = builder.Build();
IServiceCollection servicesCollection = new ServiceCollection();
// 使用工厂模式将配置对象注册到容器管理
servicesCollection.AddSingleton<IConfiguration>(p => config);
servicesCollection.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));
builder.AddConsole();
});
// 将我们的容器Build出来
IServiceProvider services = servicesCollection.BuildServiceProvider();
// 从容器中获取ILoggerFactory
ILoggerFactory loggerFactory = services.GetService<ILoggerFactory>();
var alogger = loggerFactory.CreateLogger("alogger");
alogger.LogDebug(10086, "Begin");
alogger.LogInformation("Hello World!");
var ex = new Exception("There is a bug");
alogger.LogError(ex, "Error!");
Console.ReadKey();
}
}
}
利用IServiceProvider services = servicesCollection.BuildServiceProvider();
将我们的容器Build
出来
ILoggerFactory loggerFactory = services.GetService<ILoggerFactory>();
将ILoggerFactory
对象取出来。ILoggerFactory
里面有连个方法,一个是ILogger CreateLogger(string categoryName)
输入的是Logger的名称,输出是一个ILogger对象,这个ILogger
就代表我们的日志记录器。第二个方式就是void AddProvider(ILoggerProvider provider)
,一般我们不使用,直接在AddLogging
里去注册。
利用var alogger = loggerFactory.CreateLogger("alogger");
获取一个ILogger
对象,这个Logger
对象的名字叫alogger。
运行输出:
其中,alogger[10086]
中10086
是EventID
,是针对每一个记录的位置,实践,我们可以为它分配一个事件ID
如果我们把日志级别设置为Information
"alogger": "Information"
运行输出:
可以看到,DeBug级别的日志是没有输出的。
这是使用CreateLogger
的的方式来方式指定了Logger
的名称,实际上我们可以借助容器来构造我们的Logger
。
通常情况下,我们会定义自己的类,新建类OrderService
using Microsoft.Extensions.Logging;
using System;
namespace LoggingSimpleDemo
{
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public void ShowLog()
{
_logger.LogInformation("OrderService.Log.ShowTime : {time}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}
这里,我们使用了一个小技巧:使用模板去记录日志_logger.LogInformation("xxx : {time}", DateTime.Now)
这样相比较使用插值运算符$
,_logger.LogInformation($"xxx : {DateTime.Now}")
,虽然最终输出结果是一样的,但是我们字符串拼接的时机是不同的。使用模板方法,是在我们决定要输出的时候,也就是在LogInformation
内部Console
提供程序要输出的时候,才去做这个拼接动作。而使用第二种办法其实是将我们的字符串拼接好以后,输入给了LogInformation
这个参数。如果说我们把日志等级改成None的话,模板的拼接动作是不会执行的,第二种怎么也会执行拼接的操作,这样字符串拼接操作累计下来,造成的损耗是非常大的。
然后将我们的类注入到容器里。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace LoggingSimpleDemo
{
class Program
{
static void Main(string[] args)
{
// 利用之前的方式加载json配置
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json", false, true);
var config = builder.Build();
IServiceCollection servicesCollection = new ServiceCollection();
// 使用工厂模式将配置对象注册到容器管理
servicesCollection.AddSingleton<IConfiguration>(p => config);
servicesCollection.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));
builder.AddConsole();
});
servicesCollection.AddSingleton<OrderService>();
// 将我们的容器Build出来
IServiceProvider services = servicesCollection.BuildServiceProvider();
var orderService = services.GetService<OrderService>();
orderService.ShowLog();
Console.ReadKey();
}
}
}
运行输出:
这样使用的好处是,我们不需要定义名字,它会自动的把类型的名称作为记录器的名字,如上LoggingSimpleDemo.OrderService
。
也就意味着我们可以使用这个名称来设置日志级别。
配置文件添加:"LoggingSimpleDemo.OrderService": "none"
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"LogLevel": {
"Default": "Information",
"Program": "Trace",
"alogger": "Information",
"LoggingSimpleDemo.OrderService": "none"
}
}
}
}
运行输出:
可以看到我们将日志级别设为None
之后,控制台什么都没打印出来。
注意:记录日志的时候不要把敏感信息输出出来。
本文作者:hiwwwk
本文链接:https://www.cnblogs.com/wwwk/p/15873392.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步