.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)日志组件解析的更多相关文章

  1. .NetCore中的日志(2)集成第三方日志工具

    .NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...

  2. .NetCore中使用ExceptionLess 添加操作日志

    上一篇文章已经扩展了日志,下面我们在结合下处理操作日志 通常我们想到操作日志 可能想到的参数可能有 模块 方法 参数内容 操作人 操作时间 操作 Ip 下面我们就来结合这些信息添加操作日志 如果要在代 ...

  3. springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置

    Log4j由三个重要的组件构成: 日志信息的优先级 日志信息的输出目的地 日志信息的输出格式 日志信息的优先级从高到低有ERROR.WARN. INFO.DEBUG,分别用来指定这条日志信息的重要程度 ...

  4. Abp中使用可视化的日志面板

    Abp中使用可视化的日志面板 如果你还不了解LogDashboard请看这里. ABP的相关知识不做介绍如果有需要请阅读ABP官方文档 ABP是Net下非常优秀的开发框架,在中国很多的项目都正在使用它 ...

  5. .NetCore快速搭建ELK分布式日志中心

    懒人必备:.NetCore快速搭建ELK分布式日志中心   该篇内容由个人博客点击跳转同步更新!转载请注明出处! 前言 ELK是什么 它是一个分布式日志解决方案,是Logstash.Elastaics ...

  6. 大数据学习day39----数据仓库02------1. log4j 2. 父子maven工程(子spring项目的创建)3.项目开发(埋点日志预处理-json数据解析、清洗过滤、数据集成实现、uid回补)

    1. log4j(具体见log4j文档) log4j是一个java系统中用于输出日志信息的工具.log4j可以将日志定义成多种级别:ERROR  /  WARN  /  INFO  /  DEBUG ...

  7. 在idea中如何添加log日志

    1.首先下载log4的jar包,官方路径为:http://www.apache.org/dyn/closer.cgi/logging/log4j/1.2.17/log4j-1.2.17.zip 2.下 ...

  8. gorm的日志模块源码解析

    gorm的日志模块源码解析 如何让gorm的日志按照我的格式进行输出 这个问题是<如何为gorm日志加traceId>之后,一个群里的朋友问我的.如何让gorm的sql日志不打印到控制台, ...

  9. Python中内置的日志模块logging用法详解

    logging模块简介 Python的logging模块提供了通用的日志系统,可以方便第三方模块或者是应用使用.这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/P ...

随机推荐

  1. SQLSERVER将一个文件组的数据移动到另一个文件组

    SQLSERVER将一个文件组的数据移动到另一个文件组 有经验的大侠可以直接忽视这篇文章~ 这个问题有经验的人都知道怎麽做,因为我们公司的数据量不大没有这个需求,也不知道怎麽做实验 今天求助了QQ群里 ...

  2. Fis3的前端工程化之路[三大特性篇之内容嵌入]

    Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...

  3. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整(续)-使用配置文件动态注入

    上次实现了依赖注入,但是web项目必须要引用业务逻辑层和数据存储层的实现,项目解耦并不完全:另一方面,要同时注入业务逻辑层和数据访问层,注入的服务直接写在Startup中显得非常臃肿.理想的方式是,w ...

  4. Anders Hejlsberg 技术理想架构开发传奇

    Anders Hejlsberg(安德斯-海森博格) 坐在自己的办公室,双眼直直的盯着前方.他要做一个决定,决定自己未来的命运和理想.这是1996年一个普通的下午,几个小时前,他刚与比尔-盖茨结束了 ...

  5. MongoDB系列(二):C#应用

    前言 上一篇文章<MongoDB系列(一):简介及安装>已经介绍了MongoDB以及其在window环境下的安装,这篇文章主要讲讲如何用C#来与MongoDB进行通讯.再次强调一下,我使用 ...

  6. 代码的坏味道(22)——不完美的库类(Incomplete Library Class)

    坏味道--不完美的库类(Incomplete Library Class) 特征 当一个类库已经不能满足实际需要时,你就不得不改变这个库(如果这个库是只读的,那就没辙了). 问题原因 许多编程技术都建 ...

  7. input type='file'上传控件假样式

    采用bootstrap框架样式 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> &l ...

  8. Ubuntu1604下安装Liggghts及CFDEM Coupling

    部分内容参考http://www.linuxdiyf.com/linux/16315.html LIGGGHTS是一款开源的DEM软件,来自于著名的分子动力学软件LAMMPS,目前借助于CFDEM C ...

  9. 关于sqlmap的使用

    好记性不如烂笔头,记录一下. 带cookie的注入 python sqlmap.py -u "http://www.xxx.com?id=1" --cookie="coo ...

  10. 初学DirectX11, 留个纪恋。

    以前学的是openGL, 最近才开始学DirectX11,写了个很垃圾的代码,怀念以前的glPushMatrix(), glPopMatrix(), glBegin(), glEnd(), 多简单啊, ...