18 | 日志框架:聊聊记日志的最佳姿势
除了使用 CreateLogger 指定 logger 的名称,实际上还可以借助容器来构造 logger,通常情况下我们会定义自己的类
代码语言:javascript复制namespace LoggingSimpleDemo
{
public class OrderService
{
ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public void Show()
{
_logger.LogInformation("Show Time{time}", DateTime.Now);
}
}
}
接着,将 OrderService 注入到容器中
代码语言:javascript复制serviceCollection.AddTransient<OrderService>();
IServiceProvider service = serviceCollection.BuildServiceProvider();
var order = service.GetService<OrderService>();
order.Show();
日志级别设置为 Trace
代码语言:javascript复制"LoggingSimpleDemo.OrderService": "Trace"
启动程序,输出如下:
代码语言:javascript复制info: LoggingSimpleDemo.OrderService[0]
Show Time03/06/2020 23:41:38
这样做的意义是什么呢?
通常情况下并不会用 ILoggerFactory 来构造日志记录器,而是用强类型的这种依赖注入的方式来去管理我们的日志,也就是说用构造函数将泛型的 ILogger 注入进来的方式
这样的方式有个好处就是我们不需要去为 logger 定义名字,它会默认将我们类型的名称作为记录器的名字,命名空间加上类名 LoggingSimpleDemo.OrderService ,那也就是可以在配置文件里面设置日志级别
代码语言:javascript复制"LoggingSimpleDemo.OrderService": "None"
这样子就没有输出
这里面有一个小技巧,需要大家特别注意,就是当我们在记录日志的时候,尽量使用模板的方式
代码语言:javascript复制_logger.LogInformation("Show Time{time}", DateTime.Now);
以下两种方式效果相同,但是字符串拼接的时机不同
代码语言:javascript复制_logger.LogInformation("Show Time{time}", DateTime.Now);
_logger.LogInformation($"Show Time{DateTime.Now}");
第一行代码是在我们决定要输出的时候,也就是在 LogInformation 内部 console 要输出的时候才做拼接的动作
第二行代码是指我们在字符串拼接好以后,输入给了 LogInformation
如果我们把日志级别关掉
代码语言:javascript复制"LoggingSimpleDemo.OrderService": "None"
两行代码都不会有输出,但是第一行代码字符串拼接的动作不会执行,第二行代码已经执行了,第一行代码节省了运行资源
另外一个就是,在记录日志的时候,不要把敏感信息记录到日志中,记录日志的目的是为了调试或者定位问题
总结一下
1、日志级别定义
日志级别会从严重程度的低到高定义,可以决定输出的最低级别
2、日志对象获取
可以通过 ILoggerFactory 的方式获取日志对象,对它指定一个名字,也可以通过 ILogger 泛型的模式,从容器中获取日志对象,最推荐的就是强类型的泛型模式
3、日志过滤的配置逻辑
可以针对 logger 的名称来进行任意的配置,日志的开关以及日志的级别
4、日志记录的方法
LogInformation,LogDebug,还有一些小技巧,使用模板的方式记录日志,而不是提前拼接字符串输入给日志系统
5、避免记录敏感信息,如密码、密钥,规避安全风险