那些年我们用过的组件-结构化日志组件 Serilog
什么是结构化日志
我们记录日志惯常使用 log4j2、NLog 等日志组件,这些组件提供了输出到多种终端的能力,但是大部分时候我们选择将日志输出到操作系统的文件系统中,为什么呢?至少有一部分原因是记录的每条日志为字符串格式,且按时间由远往进顺序记录,打开文件可以直接人肉检索;如果这些日志记录到其它终端比如数据库中,由于是字符串格式,无法依靠数据库的机制提高检索效率,反而日志的频繁写入和数据量的持续增大,对数据库造成很大压力,还需要花时间调优数据库结构。
但 22 世纪都快到了,还在用古老的人肉检索实在说不过去,于是出现了流行一时的 EFK、ELK框架,它们是几个组件的集合。大致流程如下:
- 首先是日志采集组件比如 
filebeats,定时从配置好的路径中采集增量日志; - 上传到消息队列比如 
kafka,缓解日志过多时的传输压力; - 然后送达日志处理组件比如 
logstash, logstash 使用filter对日志进行拆分、映射、过滤等,抽取关键内容并形成符合目标数据库特性的格式。注意此处出来的就是结构化日志; - 将结构化日志存储到特定的数据库比如 
elasticsearch中; - 通过用户界面如 
Kibana进行日志检索。 
上述流程在不同场景下有一些变种,不再赘述。 它们的主要目的就是使得传统的文件日志可以被计算机高效检索。
那么有没有一种可能,跳过文件存储,直接将日志按特定格式写入到目标存储容器,可能是 elasticsearch,也可能是 mysql,甚至是文件系统。同样代码,输出不同的格式到不同的终端,同时满足 human-friendly and machine-readable。
在 .NET 世界中, 本文的主角 Serilog 就可以帮我们省去那些弯弯绕绕,依靠它,记录与查询日志显得简单而纯粹。
Serilog
以官方例子说明:
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;
log.Information("Processed {@Position} in {Elapsed} ms", position, elapsedMs);
按字面意思,最终会输出:
09:14:22 [INF] Processed {"Latitude": 25, "Longitude": 134} in 34 ms.
当 Serilog 将日志直接输出到文件系统或命令行时,结果是这样没错,其它日志组件也能做到(废话)。
当输出到 MongoDB 时,结果就不一样了:
{ "Position": { "Latitude": 25, "Longitude": 134 }, "Elapsed": 34 }
Sink
Serilog 将输出目标称之为 sink,不同的 sink 可以有各自的格式要求。其实原理很简单,输出到特定 sink 时,日志对象会先格式化处理(注意不是先生成字符串再格式化)。Serilog.Formatting.Compact 就是格式化为 json 的类库,输出到 elasticsearch 还需要 Serilog.Formatting.Elasticsearch。不过除非自定义 sink,这些我们都不用关心,使用时只要引入需要的 sink 类库即可。
使用
下面介绍在 .NET6 中使用 Serilog。
先引入 Serilog 类库和需要的 Sink 库比如这里的 Serilog.Sinks.File:
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
以通用宿主程序为例:
IHost host = Host.CreateDefaultBuilder(args).Build();
// 配置并创建 logger 实例
var log = new LoggerConfiguration()
    .MinimumLevel.Warning()
    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 10485760, rollOnFileSizeLimit: true, retainedFileCountLimit: 100, buffered: true)
    .CreateLogger();
log.Information("Hello, Serilog!"); // 直接使用(可以创建多个实例使用)
Log.Logger = log;   // Serilog 并没有实例状态需要线程间维护,所以为了方便我们可以使用单例模式,将实例赋给全局静态属性
Log.Information("The global logger has been configured");   // 项目内任意其它地方均可使用
await host.RunAsync().ContinueWith(_=> Log.CloseAndFlush());    // app 退出时释放 logger 占用资源
如果想以 .NET 内置的方式调用 Serilog,对于通用宿主程序,须引入 Serilog.Extensions.Hosting,其扮演适配器的角色,将 Serilog 自己的接口 Serilog.ILogger 转换为 Microsoft.Extensions.Logging.ILogger 使用。如果是 web 项目的话,引入的是 Serilog.AspNetCore;.NET Core 1.0, 1.1 等版本需要引入的是 Serilog.Extensions.Logging。
更改后的版本如下:
IHost host = Host
    .CreateDefaultBuilder(args)
    .UseSerilog()   // 新增该行
    .Build();
// ... 其余代码同上
另外,上述代码是直接硬编码配置 logger,更好的方式是通过 appsettings.json 配置 logger。首先引入 Serilog.Settings.Configuration,然后在 appsettings.json 中移除默认的 Logging 配置节,替换为 Serilog 配置节如下:
{
  "Serilog": {
    "Using": [ "Serilog.Sinks.File" ],
    "MinimumLevel": "Warning",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "Logs/log.txt",
          "rollingInterval": "Day",
          "fileSizeLimitBytes": 10485760,
          "rollOnFileSizeLimit": true,
          "retainedFileCountLimit": 100,
          "buffered": true
        }
      }
    ]
  }
}
代码更改如下:
IHost host = Host
    .CreateDefaultBuilder(args)
    .UseSerilog((ctx, config) => config
        .ReadFrom.Configuration(ctx.Configuration))
    .Build();
//以下注释
//var log = new LoggerConfiguration()
//    .MinimumLevel.Warning()
//    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 10485760, rollOnFileSizeLimit: true, retainedFileCountLimit: 100, shared: true, buffered: true)
//    .CreateLogger();
//Log.Logger = log;
await host.RunAsync(); //注释.ContinueWith(_ => Log.CloseAndFlush());
采用这种方式,Log.Logger 会隐式赋值,并在系统退出时自动释放资源。
参考资料
Docker+EFK 快速搭建日志收集系统
Message Templates
.NET Worker Service 添加 Serilog 日志记录
那些年我们用过的组件-结构化日志组件 Serilog的更多相关文章
- 结构化日志类库  ----  Serilog库
		
在过去的几年中,结构化日志已经大受欢迎.而Serilog是 .NET 中最著名的结构化日志类库 ,我们提供了这份的精简指南来帮助你快速了解并运用它. 0. 内容 设定目标 认识Serilog 事件和级 ...
 - 【转】结构化日志类库 ---- Serilog库
		
源地址:https://www.cnblogs.com/mq0036/p/8479956.html 解决异常: Invalid cast from 'System.String' to 'Serilo ...
 - .NET Core开发日志——结构化日志
		
在.NET生态圈中,最早被广泛使用的日志库可能是派生自Java世界里的Apache log4net.而其后来者,莫过于NLog.Nlog与log4net相比,有一项较显著的优势,它支持结构化日志. 结 ...
 - .NET下使用 Seq结构化日志系统
		
前言 我们公司在日志管理方面一直没有统一,主要痛点有: 每个开发人员都是各用各的,存储日志的形式也是五花八门,如:本地文件,数据库,Redis,MongoDB 由于公司访问服务器要通过堡垒机,所以本机 ...
 - 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志
		
前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...
 - 如何利用NLog输出结构化日志,并在Kibana优雅分析日志?
		
上文我们演示了使用NLog向ElasticSearch写日志的基本过程(输出的是普通文本日志),今天我们来看下如何向ES输出结构化日志.并利用Kibana中分析日志. NLog输出结构化日志 Elas ...
 - Asp.Net Core中利用Seq组件展示结构化日志功能
		
在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...
 - vue第七单元(vue的单文件组件形式-单文件组件的加载原理-vue-cli构建的开发环境以及生命周期)
		
第七单元(vue的单文件组件形式-单文件组件的加载原理-vue-cli构建的开发环境以及生命周期) #课程目标 掌握安装 vue-cli 命令行工具的方法,掌握使用命令行在本地搭建开发环境,使用命令行 ...
 - 容器化分布式日志组件ExceptionLess的Angular前端UI
		
写在前面 随着微服务架构的流行,日志也需要由专门的分布式日志组件来完成这个工作,我们项目使用的是 ExceptionLess 这个组件,它是前后端分离的:这篇文章我们就来实践容器化 Exception ...
 - 重新整理 .net core 实践篇—————日志系统之结构化[十八]
		
前言 什么是结构化呢? 结构化,就是将原本没有规律的东西进行有规律话. 就比如我们学习数据结构,需要学习排序然后又要学习查询,说白了这就是一套,没有排序,谈如何查询是没有意义的,因为查询算法就是根据某 ...
 
随机推荐
- MYSQL-->InnoDB引擎底层原理
			
逻辑存储结构 逻辑存储结构图 表空间 表空间文件在Linux下存放在 /var/lib/mysql文件中的 xxx.ibd 文件就是表空间文件 表空间文件用来存储,记录,索引等数据. 段 段分为,数据 ...
 - 5.ElasticSearch系列之文档的基本操作
			
1. 文档写入 # create document. 自动生成 _id POST users/_doc { "user" : "shenjian", " ...
 - Windows docker环境安装
			
前期准备 1.hyper-v功能 win10家庭版没有提供hyper-v的问题可通过如下脚本解决,保存为bat并运行重启电脑即可. pushd "%~dp0" dir /b %Sy ...
 - python制作一个小型翻译软件
			
from urllib import parse,request import requests,re,execjs,json,time 英语查词翻译 class Tencent(): def ini ...
 - Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵
			
Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵 Redis Cluster 集群相关配置,使用集群方式的你必须重视和知晓.别嘴上原理说的头头是道,而集群有哪些配置?如何配置让集 ...
 - 前端JS模板引擎Mustache.js的用法
			
Mustache.js在前端是一个非常强大的模板 Mustache用法参考
 - threejs三维地图大屏项目分享
			
这是最近公司的一个项目.客户的需求是基于总公司和子公司的数据,开发一个数据展示大屏. 大屏两边都是一些图表展示数据,中间部分是一个三维中国地图,点击中国地图的某个省份,可以下钻到省份地图的展示. 地图 ...
 - IO学习笔记
			
IO File 概述 构造方法 代码实现: public class FileDemo001 { public static void main(String[] args) { File f1 = ...
 - 使用kubeadm方式搭建K8S集群
			
使用kubeadm方式搭建K8S集群 kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具. 这个工具能通过两条指令完成一个kubernetes集群的部署: # 创建一个 Ma ...
 - HDC2022的无障碍参会体验,手语服务是如何做到的?
			
华为开发者大会2022(HDC)上,HMS Core手语数字人以全新形象亮相,并在直播中完成了长达3个多小时的实时手语翻译,向线上线下超过一千万的观众提供了专业.实时.准确的手语翻译服务,为听障人士提 ...