.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. 复杂的 Hash 函数组合有意义吗?

    很久以前看到一篇文章,讲某个大网站储存用户口令时,会经过十分复杂的处理.怎么个复杂记不得了,大概就是先 Hash,结果加上一些特殊字符再 Hash,结果再加上些字符.再倒序.再怎么怎么的.再 Hash ...

  2. iPhone Anywehre虚拟定位提示“后台服务未启动,请重新安装应用后使用”的解决方法

    问题描述: iPhone越狱了,之后在Cydia中安装Anywhere虚拟定位,但是打开app提示:后台服务未启动,请重新安装应用后使用. 程序无法正常使用... 解决方法: 打开Cydia-已安装, ...

  3. OpenGL超级宝典笔记----渲染管线

    在OpenGL中任何事物都在3D空间中,但是屏幕和窗口是一个2D像素阵列,所以OpenGL的大部分工作都是关于如何把3D坐标转变为适应你屏幕的2D像素.3D坐标转为2D坐标的处理过程是由OpenGL的 ...

  4. 免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)

    在生活中有一种东西几乎已经快要成为我们的另一个电子”身份证“,那就是二维码.无论是在软件开发的过程中,还是在普通用户的日常中,几乎都离不开二维码.二维码 (dimensional barcode) , ...

  5. MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决

    一.简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发.发布并支持的.有以下特点: MySQL是一种数据库管理系统. MySQL是一种关联数据库管理系统. MySQ ...

  6. bzoj3208--记忆化搜索

    题目大意: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目.    我们可以把风景区看作一个n*n的地图,每个点有它的初始高度,滑雪只能从高处往低处滑[严格大于] ...

  7. C++常见笔试面试要点以及常见问题

    1. C++常见笔试面试要点: C++语言相关: (1) 虚函数(多态)的内部实现 (2) 智能指针用过哪些?shared_ptr和unique_ptr用的时候需要注意什么?shared_ptr的实现 ...

  8. eclipse如何添加Memory Analyzer

    ①启动Eclipse,并打开"Install New software..."对话框: ②点击Add,如图: ③点击OK,最后一直点next,完成

  9. Flexible 弹性盒子模型之CSS flex-grow 属性

    实例 让第二个元素的宽度为其他元素的三倍: div:nth-of-type(1){flex-grow:1;} div:nth-of-type(2){flex-grow:3;} div:nth-of-t ...

  10. HttpPost过程中使用的URLEncoder.encode(something, encode)

    URLEncoder.encode("刘美美", "utf-8").toString()       =     %E5%88%98%E7%BE%8E%E7%B ...