- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
我们记录日志惯常使用 log4j2 、 NLog 等日志组件,这些组件提供了输出到多种终端的能力,但是大部分时候我们选择将日志输出到操作系统的文件系统中,为什么呢?至少有一部分原因是记录的每条日志为字符串格式,且按时间由远往进顺序记录,打开文件可以直接人肉检索;如果这些日志记录到其它终端比如数据库中,由于是字符串格式,无法依靠数据库的机制提高检索效率,反而日志的频繁写入和数据量的持续增大,对数据库造成很大压力,还需要花时间调优数据库结构.
但 22 世纪都快到了,还在用古老的人肉检索实在说不过去,于是出现了流行一时的 EFK 、 ELK 框架,它们是几个组件的集合。大致流程如下:
filebeats
,定时从配置好的路径中采集增量日志; kafka
,缓解日志过多时的传输压力; logstash
, logstash 使用 filter
对日志进行拆分、映射、过滤等,抽取关键内容并形成符合目标数据库特性的格式。注意此处出来的就是 结构化日志
; elasticsearch
中; Kibana
进行日志检索。 上述流程在不同场景下有一些变种,不再赘述。 它们的主要目的就是使得传统的文件日志可以被计算机高效检索.
那么有没有一种可能,跳过文件存储,直接将日志按特定格式写入到目标存储容器,可能是 elasticsearch,也可能是 mysql ,甚至是文件系统。同样代码,输出不同的格式到不同的终端,同时满足 human-friendly and machine-readable .
在 .NET 世界中, 本文的主角 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 }
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的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我错过了什么,我已完成 的安装指南中要求的所有步骤 native 脚本 运行 tns doctor 给我以下输出... C:\abc\xyz>tns doctor √ Getting environm
尝试从 {addToCart(book)}}/>}> 传递数据至}> 问题: 购物车 ( render={()=> ) 收到 null,但没有收到我尝试发送的对象 已放置“console.log...
这是 _app.tsx 的外观: function MyApp({ Component, pageProps }: AppProps) { return } 我在构建项目时遇到了这个错误: Ty
我的 Laravel Vue 组件收到以下警告: [Vue warn]: Avoid mutating a prop directly since the value will be overwrit
根据这个example更详细this one我刚刚遇到了一件奇怪的事情...... 如果我使用方法作为 addTab(title,icon,component) 并且下一步想使用 setTabComp
目前我有一个捕获登录数据的表单,一个带有 TIWDBGrid 的表单,它应该返回与我从我的 mysql 数据库登录时创建的 user_id 关联的任何主机,以及一个共享数据模块。 下面是我的登录页面代
在我的react-native应用程序中,我目前有一个本地Android View (用java编写)正确渲染。当我尝试将我的react-native javascript 组件之一放入其中时,出现以
我为作业编写了简单的代码。我引用了文档和几个 youtube 视频教程系列。我的 react 代码是正确的我在运行代码时没有收到任何错误。但是这些 react-boostrap 元素没有渲染。此代码仅
几周前我刚刚开始使用 Flow,从一周前开始我就遇到了 Flow 错误,我不知道如何修复。 代码如下: // @flow import React, { Component } from "react
我想在同一个 View 中加载不同的 web2py 组件,但不是同时加载。我有 5 个 .load 文件,它们具有用于不同场景的表单字段,这些文件由 onchange 选择脚本动态调用。 web2py
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 6年前关闭。 Improve t
Blazor 有 InputNumber将输入限制为数字的组件。然而,这呈现了一个 firefox 不尊重(它允许任何文本)。 所以我尝试创建一个过滤输入的自定义组件: @inherits Inpu
我在学习 AngularDART 组件时编写了以下简单代码,但没有显示任何内容,任何人都可以帮助我知道我犯了什么错误: 我的 html 主文件:
我想在初始安装组件时或之后为 div 设置动画(淡入)。动画完成后,div 不应消失。我正在尝试使用 CSSTransition 组件并查看 reactcommunity.org 上的示例,但我根本无
我需要一个 JSF 组件来表示甘特图。是否有任何组件库(如 RichFaces)包含这样的组件? 最佳答案 JFreeChart有甘特图和PrimeFaces有一个图像组件,允许您动态地流式传输内容。
从软件工程的角度来看,组件、模块和子系统之间有什么区别? 提前致谢! 最佳答案 以下是 UML 2.5 的一些发现: 组件:该子句指定一组结构,可用于定义任意大小和复杂性的软件系统。特别是,它将组件指
我有使用非托管程序集(名为 unmanaged.dll)的托管应用程序(名为 managed.exe)。到目前为止,我们已经创建了 Interop.unmanaged.dll,managed.exe
我有一个跨多个应用程序复制的 DAL(我知道它的设计很糟糕,但现在忽略它),我想做的是这个...... 创建一个将通过所有桌面应用程序访问的 WCF DAL 组件。任何人都可以分享他们对关注的想法吗?
我有一个 ComboBox 的集合声明如下。 val cmbAll = for (i /** action here **/ } 所有这些都放在一个 TabbedPane 中。我想这不是问题。那么我
使用 VB6 创建一个 VB 应用程序。应用程序的一部分显示内部的闪存。 当我使用 printform它只是打印整个应用程序。我不知道如何单独打印闪光部分。任何帮助,将不胜感激!.. 谢谢。 最佳答案
我是一名优秀的程序员,十分优秀!