Serilog详解
1、简介
(1)概述
- Serilog 是一个用于 .NET 应用程序的结构化日志库,它允许开发者记录应用程序运行时的日志信息。相比于传统的字符串拼接日志,Serilog 提供了更强大的功能和灵活性,包括结构化的事件数据、丰富的输出格式、以及各种各样的接收端(sink)支持。
- 官网:https://serilog.net/
(2)关键特性
- 结构化事件:Serilog 记录的是结构化事件,而不是简单的文本消息。这意味着你可以将日志信息作为键值对存储,使得后续分析更加容易。
- 丰富的内容:除了基本的日志信息外,Serilog 还可以记录异常堆栈跟踪、属性等复杂对象。
- 多接收端支持:Serilog 支持多种接收端(sinks),可以将日志发送到文件、控制台、数据库、第三方服务(如 Seq, Elasticsearch, Splunk 等)等地方。
- 过滤和级别控制:你可以根据不同的条件来过滤日志,并且可以为不同的接收端设置不同的日志级别(如 Debug, Information, Warning, Error, Fatal)。
- 易于集成:Serilog 可以与 ASP.NET Core, .NET Framework 以及其他 .NET 平台无缝集成。
2、快速使用
(1)创建项目
(2)安装NuGet包
- Serilog:核心包
- Serilog.Sinks.File:你想要使用的接收端包
dotnet add package Serilog -v 4.2.0
dotnet add package Serilog.Sinks.File -v 6.0.0
(3)配置及使用
- 创建了一个新的
LoggerConfiguration
- 设置了最低日志级别为
Debug
- 配置了一个文件接收端,日志将被写入
logs/myapp.txt
文件 - 每天生成一个新的日志文件。
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
try
{
Log.Information("Application Starting Up");
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
(4)输出日志
2025-02-11 20:23:24.404 +08:00 [INF] Application Starting Up
3、代码配置详解
(1)核心配置对象
**<font style="color:rgba(0, 0, 0, 0.9);">LoggerConfiguration</font>**
:用于构建日志记录管道的核心对象,通过链式方法配置日志记录行为。
(2)创建记录器
- 使用
LoggerConfiguration
对象创建记录器,日志记录器是日志记录的主体。 - 记录器创建完即可进行使用,都是使用的默认配置
Log.Logger = new LoggerConfiguration().CreateLogger();
Log.Information("No one listens to me!");
(3)接收器(Sinks)
- 功能:将日志输出到外部媒介(如控制台、文件、数据库等)。
- 常用接收器:
Serilog.Sinks.Console
:
- 作用: 将日志输出到控制台。
- 适用场景: 适用于开发环境或需要即时查看日志的应用。
Serilog.Sinks.File
:
- 作用: 将日志写入文件中,支持按时间滚动(如每天创建一个新的日志文件)。
- 适用场景: 适合于生产环境中长期保存日志。
Serilog.Sinks.Seq
:
- 作用: 将日志发送到 Seq 日志服务器,Seq 提供了强大的查询和可视化功能。
- 适用场景: 适合需要集中管理和分析大量日志的团队。
Serilog.Sinks.Elasticsearch
:
- 作用: 将日志发送到 Elasticsearch,配合 Kibana 使用可以进行复杂的日志分析和可视化。
- 适用场景: 适合大型应用或微服务架构中,需要对日志进行高级分析和监控。
Serilog.Sinks.MSSqlServer
:
- 作用: 将日志记录到 Microsoft SQL Server 数据库中。
- 适用场景: 适合已有 SQL Server 基础设施的企业,或者需要将日志与其他业务数据一起存储的情况。
Serilog.Sinks.MySQL
:
- 作用: 将日志记录到 MySQL 数据库中。
- 适用场景: 类似于 MSSqlServer,但针对使用 MySQL 数据库的环境。
Serilog.Sinks.Http
:
- 作用: 通过 HTTP POST 请求发送日志到远程 API 或服务。
- 适用场景: 适合自定义的日志收集系统或第三方日志管理平台。
Serilog.Sinks.Email
:
- 作用: 通过电子邮件发送错误或其他关键日志信息。
- 适用场景: 适合需要及时通知相关人员的关键事件。
Serilog.Sinks.ApplicationInsights
:
- 作用: 将日志发送到 Azure Application Insights,提供性能监控和诊断工具。
- 适用场景: 适合部署在 Azure 上的应用程序。
- 配置方法:
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
- 使用 `WriteTo` 对象配置接收器
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
- <font style="color:rgba(0, 0, 0, 0.9);">支持链式配置多个接收器。</font>多个接收器可以同时处于活跃状态。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
(4)输出模板(Output Template)
- **作用:**基于文本的接收器使用输出模板来控制格式设置。通过
outputTemplate
参数进行修改: - 默认模板:包含时间戳、日志级别、消息和异常。
- 自定义格式:
Log.Logger = new LoggerConfiguration()
.WriteTo.File("log.txt",outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
- 特殊格式选项:
<font style="color:rgba(0, 0, 0, 0.9);">{Level:u3}</font>
:大写三字符级别(如 <font style="color:rgba(0, 0, 0, 0.9);">INF</font>
)。<font style="color:rgba(0, 0, 0, 0.9);">{Message:lj}</font>
:消息中的嵌入数据以 JSON 格式输出。
(5)最低级别(Minimum Level)
- 默认级别:
<font style="color:rgba(0, 0, 0, 0.9);">Information</font>
(未配置时生效)。 - 配置方式:通过
<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel</font>
设置全局最低级别。
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
日志级别分类:
级别 | 用途描述 |
---|
Verbose | 最详细,通常不用于生产环境。 |
Debug | 内部调试信息,帮助定位问题。 |
Information | 系统正常运行时的可观测操作。 |
Warning | 服务降级或潜在问题。 |
Error | 功能不可用或预期中断。 |
Fatal | 需要立即处理的严重错误。 |
(5)覆盖接收器级别
- 场景:不同接收器设置不同最低级别。
- 关键规则:接收器级别只能“升高”,不能低于全局
<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel</font>
。
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("log.txt")
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
.CreateLogger();
(6)扩充器(Enrichers)
- 作用:动态添加/修改日志事件的属性(如线程 ID、版本号)。
- 常用扩充器:
Serilog.Enrichers.Environment
: 添加有关运行时环境的信息,如操作系统版本、进程ID等。<font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Thread</font>
: 添加线程相关信息,如线程ID。<font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Assembly</font>
: 添加关于应用程序集的信息,如名称、版本号。<font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.ClientInfo</font>
: 在 Web 应用程序中添加客户端信息,如 IP 地址、用户代理等。<font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Property</font>
: 允许你在配置时静态地添加任意属性到所有日志事件中。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Enrich.WithThreadId() // 添加线程ID属性(需安装 Serilog.Enrichers.Thread)
.CreateLogger();
- 自定义扩充器:需实现
<font style="color:rgba(0, 0, 0, 0.9);">ILogEventEnricher</font>
接口。
class ThreadIdEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
"ThreadId", Thread.CurrentThread.ManagedThreadId));
}
}
Log.Logger = new LoggerConfiguration()
.Enrich.With(new ThreadIdEnricher())
.WriteTo.Console()
.CreateLogger();
- 快捷方法:使用
<font style="color:rgba(0, 0, 0, 0.9);">WithProperty</font>
添加静态属性。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
(7)过滤器(Filters)
- 功能:按条件筛选日志事件。
**Serilog.Filters.Expressions**
: 使用表达式语言来定义复杂的过滤规则。- 示例:排除
<font style="color:rgba(0, 0, 0, 0.9);">Count</font>
属性大于 10 的事件。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Filter.ByExcluding(Matching.WithProperty<int>("Count", p => p < 10))
.CreateLogger();
(8)格式化器 (Formatters)
- 格式化器用于控制日志消息的格式。
- 常用的格式化器包括:
Serilog.Formatting.Compact
: 提供紧凑的 JSON 格式的日志输出,适合机器读取。Serilog.Formatting.Display
: 允许你定义日志消息的文本模板,如 {Timestamp} [{Level}] {Message}{NewLine}{Exception}
。
(9)其他配置
Serilog.Settings.Configuration
: 从应用程序配置文件(如 appsettings.json
)中加载 Serilog 配置。Serilog.AspNetCore
: 提供 ASP.NET Core 的集成,自动记录请求和响应信息。Serilog.Exceptions
: 深度解析异常,提取更多细节并作为结构化数据记录。Serilog.Sinks.PeriodicBatching
: 为其他接收端提供批处理能力,减少 I/O 操作次数,提高性能。
4、使用配置文件进行配置
(1)创建项目
(2)安装NuGet包
- Serilog.Settings.Configuration:用于从配置文件中加载 Serilog 设置。
- Microsoft.Extensions.Configuration.Json:加载 json 配置文件包。
dotnet add package Serilog.Settings.Configuration -v 9.0.0
dotnet add package Microsoft.Extensions.Configuration.Json -v 9.0.0
(3)配置文件
- 创建配置文件
<font style="color:rgb(64, 64, 64);">appsettings.json</font>
,确保这个文件被设置为始终复制。
{
"Serilog": {
"Using": ["Serilog.Sinks.File"],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName" ]
}
}
(4)代码实现
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
try
{
Log.Information("程序启动");
Log.Debug("这是一个调试信息");
Log.Warning("示例警告信息");
for (int i = 0; i < 3; i++)
{
Log.Information("处理第 {Iteration} 次循环", i);
}
throw new Exception("示例异常");
}
catch (Exception ex)
{
Log.Error(ex, "发生未处理异常");
}
finally
{
Log.Information("程序退出");
Log.CloseAndFlush();
}
(5)输出日志
2025-02-11 20:25:37.236 +08:00 [Information] 程序启动
2025-02-11 20:25:37.261 +08:00 [Warning] 示例警告信息
2025-02-11 20:25:37.261 +08:00 [Information] 处理第 0 次循环
2025-02-11 20:25:37.262 +08:00 [Information] 处理第 1 次循环
2025-02-11 20:25:37.262 +08:00 [Information] 处理第 2 次循环
2025-02-11 20:25:37.271 +08:00 [Error] 发生未处理异常
System.Exception: 示例异常
at Program.Main(String[] args) in D:\XCDEVDOC\00000000 开发文档\ConsoleMySerilog\Program.cs:line 53
2025-02-11 20:25:37.280 +08:00 [Information] 程序退出
(6)日志级别覆盖
- 在配置文件中,你可以通过
MinimumLevel.Override
覆盖特定命名空间的日志级别。这可以帮助你减少来自框架或第三方库的冗余日志信息。
{
"Serilog": {
"Using": ["Serilog.Sinks.File"],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore.Mvc": "Error",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
}
]
}
}
- 全局基准:Default级别,
<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel.Default = Information</font>
表示:
- 所有未被覆盖的日志源默认仅记录
<font style="color:rgba(0, 0, 0, 0.9);">Information</font>
及以上级别日志 - 低于此级别的日志会被自动过滤
- 精准控制:Override规则,
<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel.Override("Microsoft", Warning)</font>
表示:
- 所有命名空间以
**<font style="color:rgba(0, 0, 0, 0.9);">Microsoft.</font>**
开头的日志(如<font style="color:rgba(0, 0, 0, 0.9);">Microsoft.AspNetCore</font>
、<font style="color:rgba(0, 0, 0, 0.9);">Microsoft.EntityFrameworkCore</font>
)。 - 仅记录
<font style="color:rgba(0, 0, 0, 0.9);">Warning</font>
及以上级别(Warning/Error/Fatal)的日志,覆盖优先级高于Default,形成细粒度控制。
5、异步写日志
(1)安装NuGet包
dotnet add package Serilog.Sinks.Async -v 2.0.0
(2)配置文件
{
"Serilog": {
"Using": [
"Serilog.Sinks.File",
"Serilog.Sinks.Async"
],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore.Mvc": "Error",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "Logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"buffered": false,
"flushToDiskInterval": 5,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
}
}
],
"bufferSize": 1000,
"blockWhenFull": true
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName" ]
}
}
(3)代码实现
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
try
{
Log.Information("程序启动(异步模式)");
Parallel.For(0, 100, i =>
{
Log.Information("异步写入日志项 {Number}", i);
});
throw new InvalidOperationException("测试异步异常记录");
}
catch (Exception ex)
{
Log.Error(ex, "异步异常示例");
}
finally
{
Log.Information("程序结束");
await Log.CloseAndFlushAsync();
}
(4)输出日志
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 6
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 30
2025-02-11 17:57:47.363 +08:00 [Information] 异步写入日志项 60
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 12
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 0
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 54
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 24
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 48
2025-02-11 17:57:47.367 +08:00 [Information] 异步写入日志项 66
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 36
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 42
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 55
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 25
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 37
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 49
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 13
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 67
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 7
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 61
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 31
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 56
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 26
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 38
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 14
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 68
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 50
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 8
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 43
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 1
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 39
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 15
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 62
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 51
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 40
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 16
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 9
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 18
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 57
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 69
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 17
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 63
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 19
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 52
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 41
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 20
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 21
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 53
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 10
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 64
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 32
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 33
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 22
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 45
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 58
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 65
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 11
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 34
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 23
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 72
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 46
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 59
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 70
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 35
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 44
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 82
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 27
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 73
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 47
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 90
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 84
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 78
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 71
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 3
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 96
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 74
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 83
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 91
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 85
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 79
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 4
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 97
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 28
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 75
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 92
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 86
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 80
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 5
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 29
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 98
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 76
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 93
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 87
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 81
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 99
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 77
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 94
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 88
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 95
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 89
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 2
2025-02-11 17:57:47.377 +08:00 [Error] 异步异常示例
System.InvalidOperationException: 测试异步异常记录
at Program.Main(String[] args) in D:\XCDEVDOC\00000000 开发文档\ConsoleMySerilog\Program.cs:line 88
2025-02-11 17:57:47.377 +08:00 [Information] 程序结束
(5)关键优化点说明
- 异步架构:
- 通过
<font style="color:rgb(64, 64, 64);">Serilog.Sinks.Async</font>
实现非阻塞日志写入 - 主线程将日志放入内存缓冲区,后台线程处理实际文件写入
- 性能参数:
"bufferSize": 1000,
"blockWhenFull": true
"buffered": false,
"flushToDiskInterval": 5
await Log.CloseAndFlushAsync();
(6)异步 vs 同步
特性 | 同步模式 | 异步模式 |
---|
线程阻塞 | 可能阻塞主线程 | 非阻塞 |
吞吐量 | 较低 | 高(批量写入) |
数据安全性 | 实时写入更安全 | 崩溃时可能丢失少量缓冲日志 |
适用场景 | 低频率日志/关键系统 | 高并发日志/性能敏感系统 |
6、Asp.NetCore集成Serilog
(1)创建项目
- 创建Asp.NetCore WebApi 项目,基于 net8
(2)安装nuget包
- Serilog:Serilog 核心库。
- Serilog.AspNetCore:ASP.NET Core 集成包。
- Serilog.Sinks.File:将日志输出到文件。
- Serilog.Sinks.Async:异步写日志。
dotnet add package Serilog -v 4.2.0
dotnet add package Serilog.AspNetCore -v 9.0.0
dotnet add package Serilog.Sinks.File -v 6.0.0
dotnet add package Serilog.Sinks.Async -v 2.0.0
(3)配置日志记录器
using Serilog;
using Serilog.Events;
namespace AspNetCoreWebApiMySerilog
{
public static class Extends
{
const string infoPath = "Logs/info.log";
const string warnPath = "Logs/warn.log";
const string errorPath = "Logs/error.log";
const string fatalPath = "Logs/fatal.log";
const string template = "时间: {Timestamp:yyyy-MM-dd HH:mm:ss}{NewLine}来源: {SourceContext}{NewLine}内容: [{Level:u3}] {Message}{NewLine}{Exception}{NewLine}";
public static void AddSerilog(this IServiceCollection c)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: template)
.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Information).WriteTo.Async(congfig => congfig.File(
infoPath,
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1024 * 1024 * 10,
retainedFileCountLimit: 10,
rollOnFileSizeLimit: true,
shared: true,
outputTemplate: template)
))
.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Warning).WriteTo.Async(congfig => congfig.File(
warnPath,
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1024 * 1024 * 10,
retainedFileCountLimit: 10,
rollOnFileSizeLimit: true,
shared: true,
outputTemplate: template)
))
.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Error).WriteTo.Async(congfig => congfig.File(
errorPath,
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1024 * 1024 * 10,
retainedFileCountLimit: 10,
rollOnFileSizeLimit: true,
shared: true,
outputTemplate: template)
))
.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Fatal).WriteTo.Async(congfig => congfig.File(
fatalPath,
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1024 * 1024 * 10,
retainedFileCountLimit: 10,
rollOnFileSizeLimit: true,
shared: true,
outputTemplate: template)
)).CreateLogger();
c.AddLogging(opt =>
{
opt.ClearProviders();
opt.AddSerilog(dispose: true);
});
}
}
}
(4)配置Serilog到框架
namespace AspNetCoreWebApiMySerilog
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSerilog();
var app = builder.Build();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
(5)在代码中使用日志
using Microsoft.AspNetCore.Mvc;
namespace AspNetCoreWebApiMySerilog.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class MyController : Controller
{
private readonly ILogger<MyController> _logger;
public MyController(ILogger<MyController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Index()
{
_logger.LogDebug("这是一条调试消息");
_logger.LogInformation("这是一条提示消息");
_logger.LogWarning("这是一条警告消息");
_logger.LogError("这是一条错误消息");
_logger.LogCritical("这是一条严重错误");
return Ok("Hello World");
}
}
}
- 访问地址:http://localhost:5135/my/index
- 日志写入日志文件

