.NetCore中的日志(1)日志组件解析
.NetCore中的日志(1)日志组件解析
0x00 问题的产生
日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为。在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包含控制台、文本文件、数据库,一般都是创建全局的Logger,在需要记录日志的地方调用相应的Logger输出至相应目标。遇到输出目标多了有时候也感觉挺麻烦的,不过也还能接受。开始学习.NetCore后接触到了日志记录框架(Logging组件),虽然完全可以用之前的方式记录日志,不过应该使用更通用的方式,把日志记录和具体的输出目标解耦。所以学习了.NetCore中Logging组件,并尝试实现了自定义的LoggerProvider,以及在.NetCore的Logging框架中使用现有完善的第三方日志记录工具NLog。写一篇博客作为学习记录,同时也希望对有这方面需求的园友有所帮助。
0x01 .NetCore中的Logging
正如在上面部分写到的那样,当日志输出的目标多起来后,写日志就会变得麻烦。仔细想一下,日志输出这个动作是不变的,变的只是不同的输出目标(控制台、文本文件、数据库等),所以可以把日志记录这个动作抽象出来,日志记录器包含多个可输出目标,当我们调用Log方法写日志时,由Log方法依次调用Logger中的XxxLogger,把日志写到具体的目标上。过程如下图所示:

那么如何创建出这样的一个Logger呢,我们可以创建一个工厂叫LoggerFactory用来生产Logger,Logger中包还含了ConsoleLogger、FileLogger等,这些XxxLogger可以通过XxxLoggerProvider创建。进一步的,可以把Logger、LoggerFactory和LoggerProvider的行为抽象为接口ILogger、ILoggerFactory、ILoggerProvider。

其中:
ILogger中的Log()方法可以记录日志;
ILoggerProvider可以创建ILogger,用于向特定的目标写入日志;
ILoggerFactory可以添加多个IloggerProvider,并可以创建我们最终使用的ILogger;
下图为使用LoggerFactory中使用AddProvider方法添加ILoggerProvider:

下图为LoggerFactory中使用CreateLogger方法创建Logger:

下图为Logger的构造函数,使用传入的LoggerFactory中的providers,依次调用其中的ILoggerProvider来创建XxxLogger。

这里需要特别说明一下,ILoggerFactory和ILoggerProvider都产生ILogger,看上去让人迷惑,但实际上这两种ILogger的实现细节是不一样的,不同的实现中Log()方法的意义不同。
对于ILoggerFactory产生的是Logger类型(也就是我们最终使用的Logger),其Log()方法是依次调用Logger中包含的_loggers数组中的ILogger。

而ILoggerProvider产生的为各类不同的XxxLogger(也就是上面说的Logger中的_loggers数组包含的如ConsoleLogger、DebugLogger),其Log()方法是把日志写到具体的目标上去。下图为ConsoleLogger的Log()方法:

在有时候我们可能不希望某些日志被写入到所有的目标上。例如只想把某些特定的日志写入数据库。这时可以在XxxdLoggerProvider构造函数中传入
Func<string, LogLevel, bool> filter
形式的委托,当返回true时写入日志,返回false则不写入日志。
此外针对不同的LoggerProvider有不同的配置方式,这里就不一一说明了。
0x02 泛型的Logger<T>
前面我们看到了,Logger用name来标识其唯一性。在日志记录时我们很多情况下都希望记录日志产生时所在的命名空间和类型,因此使用完整的类型名称来作为Logger的name既保证了唯一性又记录了日志产生时所在的命名空间和类型是一个很好的选择。当创建Logger<T>对象时,实际上就是创建了一个用T的完整类型名称作为name的Logger并进行了包装,把Logger<T>的Log方法原封不动传入了创建的Logger的Log方法。

这样一来像NLog这样基于name的路由也很容易集成了。
0x03 使用日志记录
ILoggerFactory默认就已经被添加到IServiceCollection容器中了,我们只需要添加需要的ILoggerProvider即可。为了让代码更简洁更具备自解释的能力,Logging组件还给ILoggerFactory添加了扩展方法,例如只要使用以下代码

就可以完成ConsoleLoggerProvider和DebugLoggerProvider的添加。
此外对Logger复杂的Log方法也进行了封装(LogTrace、LogDebug、LogError等等),以满足不同需求。
在使用Logger时可以通过依赖注入的方式获取Logger,可以有两种方法获取:

以及

这两种方法没有本质区别,如下图所示CreateLogger<T>方法也是调用Logger<T>构造函数来创建Logger<T>的。

所以只要根据喜好选择就行。
0x04 写在最后
.NetCore的Logging组件提供了日志记录的框架,只要实现了ILoggerProvider接口的日志记录工具都可以集成到Logger中,这极大方便了成熟的第三方日志记录工具的集成。通过Logging组件,把日志记录逻辑和具体的记录行为解耦了,可以任意更换日志记录工具而不需要修改日志记录逻辑,同样的,只要实现了框架的接口,不同日志记录工具也可以混用。所以虽然.NetCore本身只实现了Console、Debug等几个有限的Logger,但借助于丰富的第三方日志记录工具,我们有非常多的选择。即使需求极其奇葩,只要实现框架中的接口,我们很容易集成自己写的日志记录工具。下一篇将以NLog为例说一下第三方日志记录工具的集成,此外还将编写和集成一个自己写的Logger。
更多内容欢迎访问我的博客:http://www.durow.vip
.NetCore中的日志(1)日志组件解析的更多相关文章
- .NetCore中的日志(2)集成第三方日志工具
.NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...
- .NetCore中使用ExceptionLess 添加操作日志
上一篇文章已经扩展了日志,下面我们在结合下处理操作日志 通常我们想到操作日志 可能想到的参数可能有 模块 方法 参数内容 操作人 操作时间 操作 Ip 下面我们就来结合这些信息添加操作日志 如果要在代 ...
- springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置
Log4j由三个重要的组件构成: 日志信息的优先级 日志信息的输出目的地 日志信息的输出格式 日志信息的优先级从高到低有ERROR.WARN. INFO.DEBUG,分别用来指定这条日志信息的重要程度 ...
- Abp中使用可视化的日志面板
Abp中使用可视化的日志面板 如果你还不了解LogDashboard请看这里. ABP的相关知识不做介绍如果有需要请阅读ABP官方文档 ABP是Net下非常优秀的开发框架,在中国很多的项目都正在使用它 ...
- .NetCore快速搭建ELK分布式日志中心
懒人必备:.NetCore快速搭建ELK分布式日志中心 该篇内容由个人博客点击跳转同步更新!转载请注明出处! 前言 ELK是什么 它是一个分布式日志解决方案,是Logstash.Elastaics ...
- 大数据学习day39----数据仓库02------1. log4j 2. 父子maven工程(子spring项目的创建)3.项目开发(埋点日志预处理-json数据解析、清洗过滤、数据集成实现、uid回补)
1. log4j(具体见log4j文档) log4j是一个java系统中用于输出日志信息的工具.log4j可以将日志定义成多种级别:ERROR / WARN / INFO / DEBUG ...
- 在idea中如何添加log日志
1.首先下载log4的jar包,官方路径为:http://www.apache.org/dyn/closer.cgi/logging/log4j/1.2.17/log4j-1.2.17.zip 2.下 ...
- gorm的日志模块源码解析
gorm的日志模块源码解析 如何让gorm的日志按照我的格式进行输出 这个问题是<如何为gorm日志加traceId>之后,一个群里的朋友问我的.如何让gorm的sql日志不打印到控制台, ...
- Python中内置的日志模块logging用法详解
logging模块简介 Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用.这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/P ...
随机推荐
- 读书笔记:JavaScript DOM 编程艺术(第二版)
读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...
- nohup程序后台执行
Linux常用命令,用于不挂断的执行程序. nohup命令:如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令.该命令可以在你退出帐户/关闭终端之后继续运行相应 ...
- Azure Service Fabric 开发环境搭建
微服务体系结构是一种将服务器应用程序构建为一组小型服务的方法,每个服务都按自己的进程运行,并通过 HTTP 和 WebSocket 等协议相互通信.每个微服务都在特定的界定上下文(每服务)中实现特定的 ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- python通过protobuf实现rpc
由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...
- DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)
上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...
- 设计模式之结构类模式大PK
结构类模式大PK 结构类模式包括适配器模式.桥梁模式.组合模式.装饰模式.门面模式.享元模式和代理模式.之所以称其为结构类模式,是因 ...
- MySQL 系列(二) 你不知道的数据库操作
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...
- 模仿Linux内核kfifo实现的循环缓存
想实现个循环缓冲区(Circular Buffer),搜了些资料多数是基于循环队列的实现方式.使用一个变量存放缓冲区中的数据长度或者空出来一个空间来判断缓冲区是否满了.偶然间看到分析Linux内核的循 ...
- 【读书】PHP程序员要读的书目(不断完善中)
本文地址 分享提纲: 1. PHP 2. Linux 3. Apache/Nginx 4. Mysql 5.设计模式/架构 6. 缓存并发 7. 其他语言 8. 代码基础 9. 大前端 10. 管理生 ...