.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. Azkaban源码学习笔记

    1. ConnectorParams (interface): 定义了各种常量参数,没有声明任何方法. 2. ExecutorServlet.java类   2.1 继承类HttpServlet和接口 ...

  2. RabbitMq应用二

    在应用一中,基本的消息队列使用已经完成了,在实际项目中,一定会出现各种各样的需求和问题,rabbitmq内置的很多强大机制和功能会帮助我们解决很多的问题,下面就一个一个的一起学习一下. 消息响应机制 ...

  3. JAVA回调机制(CallBack)详解

    序言 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回 ...

  4. 使用ServiceStack构建Web服务

    提到构建WebService服务,大家肯定第一个想到的是使用WCF,因为简单快捷嘛.首先要说明的是,本人对WCF不太了解,但是想快速建立一个WebService,于是看到了MSDN上的这一篇文章 Bu ...

  5. 比Mysqli操作数据库更简便的方式 。PDO

    下面来说一下PDO 先画一张图来了解一下 mysqli是针对mysql这个数据库扩展的一个类 PDO是为了能访问更多数据库 如果出现程序需要访问其他数据库的话就可以用PDO来做 PDO数据访问抽象层1 ...

  6. .net windows Kafka 安装与使用入门(入门笔记)

    完整解决方案请参考: Setting Up and Running Apache Kafka on Windows OS   在环境搭建过程中遇到两个问题,在这里先列出来,以方便查询: 1. \Jav ...

  7. 利用Node.js的Net模块实现一个命令行多人聊天室

    1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...

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

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

  9. 【工具使用】mac电脑使用技巧

    本文地址 分享提纲: 1.  mac命令行和finder的交互 2. 一些mac的插件 3. 一些开发的配置 1.mac命令行和findder交互           1)命令行中打开当前文件夹: o ...

  10. APP多版本共存,服务端如何兼容?

    做过APP产品的技术人员都知道,APP应用属于一种C/S架构的,所以在做多版本兼容,升级等处理则比较麻烦,不像web应用那么容易.下面将带大家分析几种常见的情况和应对方式: 小改动或者新加功能的 这种 ...